Example #1
0
 /**
  * Create a new user
  *
  * @access	public
  * @param	string	$data			An array of data to use for creating the user
  * @param	boolean	$send_welcome	Whether or not to send the welcome email or not
  * @return	boolean
  **/
 public function create($data = FALSE, $send_welcome = TRUE)
 {
     //	Has an email or a suername been submitted?
     if (APP_NATIVE_LOGIN_USING == 'EMAIL') {
         //	Email defined?
         if (empty($data['email'])) {
             $this->_set_error('An email address must be supplied.');
             return FALSE;
         }
         //	Check email against DB
         $this->db->where('email', $data['email']);
         if ($this->db->count_all_results(NAILS_DB_PREFIX . 'user_email')) {
             $this->_set_error('This email is already in use.');
             return FALSE;
         }
     } elseif (APP_NATIVE_LOGIN_USING == 'USERNAME') {
         //	Username defined?
         if (empty($data['username'])) {
             $this->_set_error('A username must be supplied.');
             return FALSE;
         }
         //	Check username against DB
         $this->db->where('username', $data['username']);
         if ($this->db->count_all_results(NAILS_DB_PREFIX . 'user')) {
             $this->_set_error('This username is already in use.');
             return FALSE;
         }
     } else {
         //	Either a username or an email must be supplied
         if (empty($data['email']) && empty($data['username'])) {
             $this->_set_error('An email address or a username must be supplied.');
             return FALSE;
         }
         if (!empty($data['email'])) {
             //	Check email against DB
             $this->db->where('email', $data['email']);
             if ($this->db->count_all_results(NAILS_DB_PREFIX . 'user_email')) {
                 $this->_set_error('This email is already in use.');
                 return FALSE;
             }
         }
         if (!empty($data['username'])) {
             //	Check username against DB
             $this->db->where('username', $data['username']);
             if ($this->db->count_all_results(NAILS_DB_PREFIX . 'user')) {
                 $this->_set_error('This username is already in use.');
                 return FALSE;
             }
         }
     }
     // --------------------------------------------------------------------------
     //	All should be ok, go ahead and create the account
     $_user_data = array();
     // --------------------------------------------------------------------------
     //	If a password has been passed then generate the encrypted strings, otherwise
     //	just generate a salt.
     if (empty($data['password'])) {
         $_password[] = NULL;
         $_password[] = $this->user_password_model->salt();
     } else {
         $_password = $this->user_password_model->generate_hash($data['password']);
         if (!$_password) {
             $this->_set_error($this->user_password_model->last_error());
             return FALSE;
         }
     }
     //	Do we need to inform the user of their password? This might be set
     //	if an admin created the account, or if the system generated a new password
     $_inform_user_pw = !empty($data['inform_user_pw']) ? TRUE : FALSE;
     // --------------------------------------------------------------------------
     //	Check that we're dealing with a valid group
     if (empty($data['group_id'])) {
         $_user_data['group_id'] = $this->user_group_model->get_default_group_id();
     } else {
         $_user_data['group_id'] = $data['group_id'];
     }
     $_group = $this->user_group_model->get_by_id($_user_data['group_id']);
     if (!$_group) {
         $this->_set_error('Invalid Group ID specified.');
         return FALSE;
     } else {
         $_user_data['group_id'] = $_group->id;
     }
     // --------------------------------------------------------------------------
     //	Check we're dealing with a valid auth_method
     if (!empty($data['auth_method_id'])) {
         if (is_numeric($data['auth_method_id'])) {
             $this->db->where('id', (int) $data['auth_method_id']);
         } else {
             //	TODO: Change this column to be called `slug`
             $this->db->where('type', $data['auth_method_id']);
         }
         $_auth_method = $this->db->get(NAILS_DB_PREFIX . 'user_auth_method')->row();
         if (!$_auth_method) {
             //	Define a use friendly error (this may be shown to them)
             $this->_set_error('There was an error creating the user account - Error #001');
             //	This is a problem, email devs
             send_developer_mail('No auth method available for the supplied auth_method_id', 'The user_model->create() method was called with an invalid auth_method_id ("' . $data['auth_method_id'] . '"). This needs investigated and corrected.');
             return FALSE;
         }
     } else {
         //	TODO: this column should be `slug`
         $this->db->where('type', 'native');
         $_auth_method = $this->db->get(NAILS_DB_PREFIX . 'user_auth_method')->row();
         if (!$_auth_method) {
             //	Define a use friendly error (this may be shown to them)
             $this->_set_error('There was an error creating the user account - Error #002');
             //	This is a problem, email devs
             send_developer_mail('No Native Authentication Method', 'There is no authentication method defined in the database for native registrations.');
             return FALSE;
         }
     }
     $_user_data['auth_method_id'] = $_auth_method->id;
     // --------------------------------------------------------------------------
     if (!empty($data['username'])) {
         $_user_data['username'] = $data['username'];
     }
     if (!empty($data['email'])) {
         $_email = $data['email'];
         $_email_is_verified = !empty($data['email_is_verified']);
     }
     $_user_data['password'] = $_password->password;
     $_user_data['password_md5'] = $_password->password_md5;
     $_user_data['password_engine'] = $_password->engine;
     $_user_data['salt'] = $_password->salt;
     $_user_data['ip_address'] = $this->input->ip_address();
     $_user_data['last_ip'] = $_user_data['ip_address'];
     $_user_data['created'] = date('Y-m-d H:i:s');
     $_user_data['last_update'] = date('Y-m-d H:i:s');
     $_user_data['is_suspended'] = !empty($data['is_suspended']);
     $_user_data['temp_pw'] = !empty($data['temp_pw']);
     $_user_data['auth_method_id'] = $_auth_method->id;
     //	Facebook oauth details
     $_user_data['fb_token'] = !empty($data['fb_token']) ? $data['fb_token'] : NULL;
     $_user_data['fb_id'] = !empty($data['fb_id']) ? $data['fb_id'] : NULL;
     //	Twitter oauth details
     $_user_data['tw_id'] = !empty($data['tw_id']) ? $data['tw_id'] : NULL;
     $_user_data['tw_token'] = !empty($data['tw_token']) ? $data['tw_token'] : NULL;
     $_user_data['tw_secret'] = !empty($data['tw_secret']) ? $data['tw_secret'] : NULL;
     //	Linkedin oauth details
     $_user_data['li_id'] = !empty($data['li_id']) ? $data['li_id'] : NULL;
     $_user_data['li_token'] = !empty($data['li_token']) ? $data['li_token'] : NULL;
     //	Referral code
     $_user_data['referral'] = $this->_generate_referral();
     //	Other data
     $_user_data['salutation'] = !empty($data['salutation']) ? $data['salutation'] : NULL;
     $_user_data['first_name'] = !empty($data['first_name']) ? $data['first_name'] : NULL;
     $_user_data['last_name'] = !empty($data['last_name']) ? $data['last_name'] : NULL;
     if (isset($data['gender'])) {
         $_user_data['gender'] = $data['gender'];
     }
     if (isset($data['timezone'])) {
         $_user_data['timezone'] = $data['timezone'];
     }
     if (isset($data['datetime_format_date'])) {
         $_user_data['datetime_format_date'] = $data['datetime_format_date'];
     }
     if (isset($data['datetime_format_time'])) {
         $_user_data['datetime_format_time'] = $data['datetime_format_time'];
     }
     if (isset($data['language'])) {
         $_user_data['language'] = $data['language'];
     }
     // --------------------------------------------------------------------------
     //	Set Meta data
     $_meta_cols = $this->_get_meta_columns();
     $_meta_data = array();
     foreach ($data as $key => $val) {
         if (array_search($key, $_meta_cols) !== FALSE) {
             $_meta_data[$key] = $val;
         }
     }
     // --------------------------------------------------------------------------
     $this->db->trans_begin();
     $this->db->set($_user_data);
     if (!$this->db->insert(NAILS_DB_PREFIX . 'user')) {
         $this->_set_error('Failed to create base user object.');
         $this->db->trans_rollback();
         return FALSE;
     }
     $_id = $this->db->insert_id();
     // --------------------------------------------------------------------------
     //	Update the user table with an MD5 hash of the user ID; a number of functions
     //	make use of looking up this hashed information; this should be quicker.
     $this->db->set('id_md5', md5($_id));
     $this->db->where('id', $_id);
     if (!$this->db->update(NAILS_DB_PREFIX . 'user')) {
         $this->_set_error('Failed to update base user object.');
         $this->db->trans_rollback();
         return FALSE;
     }
     // --------------------------------------------------------------------------
     //	Create the user_meta record, add any extra data if needed
     $this->db->set('user_id', $_id);
     if ($_meta_data) {
         $this->db->set($_meta_data);
     }
     if (!$this->db->insert(NAILS_DB_PREFIX . 'user_meta')) {
         $this->_set_error('Failed to create user meta data object.');
         $this->db->trans_rollback();
         return FALSE;
     }
     // --------------------------------------------------------------------------
     //	Finally add the email address to the user_email table
     if (!empty($_email)) {
         $_code = $this->email_add($_email, $_id, TRUE, $_email_is_verified, FALSE);
         if (!$_code) {
             //	Error will be set by email_add();
             $this->db->trans_rollback();
             return FALSE;
         }
         //	Send the user the welcome email
         if ($send_welcome) {
             $this->load->library('emailer');
             $_email = new stdClass();
             $_email->type = 'new_user_' . $_group->id;
             $_email->to_id = $_id;
             $_email->data = array();
             $_email->data['method'] = $_auth_method;
             //	If this user is created by an admin then take note of that.
             if ($this->is_admin()) {
                 $_email->data['admin'] = new stdClass();
                 $_email->data['admin']->id = active_user('id');
                 $_email->data['admin']->first_name = active_user('first_name');
                 $_email->data['admin']->last_name = active_user('last_name');
                 $_email->data['admin']->group = new stdClass();
                 $_email->data['admin']->group->id = $_group->id;
                 $_email->data['admin']->group->name = $_group->label;
             }
             if (!empty($data['password']) && !empty($_inform_user_pw)) {
                 $_email->data['password'] = $data['password'];
                 //	Is this a temp password? We should let them know that too
                 if ($_user_data['temp_pw']) {
                     $_email->data['temp_pw'] = !empty($_user_data['temp_pw']);
                 }
             }
             //	If the email isn't verified we'll want to include a note asking them to do so
             if (!$_email_is_verified) {
                 $_email->data['verification_code'] = $_code;
             }
             if (!$this->emailer->send($_email, TRUE)) {
                 //	Failed to send using the group email, try using the generic email template
                 $_email->type = 'new_user';
                 if (!$this->emailer->send($_email, TRUE)) {
                     //	Email failed to send, musn't exist, oh well.
                     $_error = 'Failed to send welcome email.';
                     $_error .= !empty($_inform_user_pw) ? ' Inform the user their password is <strong>' . $data['password'] . '</strong>' : '';
                     $this->_set_error($_error);
                 }
             }
         }
     }
     // --------------------------------------------------------------------------
     //	commit the transaction and return new user object
     if ($this->db->trans_status() !== FALSE) {
         $this->db->trans_commit();
         return $this->get_by_id($_id);
     } else {
         return FALSE;
     }
 }
 public function send_order_notification($order)
 {
     //	If an ID has been passed, look it up
     if (is_numeric($order)) {
         _LOG('Looking up order #' . $order);
         $order = $this->get_by_id($order);
         if (!$order) {
             _LOG('Invalid order ID');
             $this->_set_error('Invalid order ID.');
             return FALSE;
         }
     }
     // --------------------------------------------------------------------------
     $this->load->library('emailer');
     $this->load->helper('email');
     $_email = new stdClass();
     $_email->type = 'shop_notify';
     $_email->data = array();
     $_email->data['order'] = $order;
     $_recipients = explode(',', notification('notify_order', 'shop'));
     foreach ($_recipients as $recipient) {
         $_email->to_email = $recipient;
         if (!$this->emailer->send($_email, TRUE)) {
             //	Email failed to send, alert developers
             _LOG('!! Failed to send order notification to ' . $_email->to_email . ', alerting developers.');
             _LOG(implode("\n", $this->emailer->get_errors()));
             send_developer_mail('Unable to send order notification email', 'Unable to send the order notification to ' . $_email->to_email . '; order: #' . $order->id . "\n\nEmailer errors:\n\n" . print_r($this->emailer->get_errors(), TRUE));
         }
     }
 }
Example #3
0
 protected function _notify_paypal()
 {
     //	Configure log
     _LOG_FILE(app_setting('url', 'shop') . 'notify/paypal/ipn-' . date('Y-m-d') . '.php');
     _LOG();
     _LOG('- - - - - - - - - - - - - - - - - - -');
     _LOG('Waking up IPN responder; handling with PayPal');
     // --------------------------------------------------------------------------
     //	POST data?
     //	Want to test a previous IPN message?
     //	Paste the IPN message into the following and uncomment the following lines
     //	$_message = '';
     //	$_message = str_replace( '+', '%2B', $_message );
     //	parse_str( $_message, $_POST );
     if (!$this->data['testing'] && !$this->input->post()) {
         _LOG('No POST data, going back to sleep...');
         _LOG('- - - - - - - - - - - - - - - - - - -');
         _LOG();
         return;
     }
     // --------------------------------------------------------------------------
     //	Are we testing?
     if ($this->data['testing']) {
         $_ipn = TRUE;
         _LOG();
         _LOG('**TESTING**');
         _LOG('**Simulating data sent from PayPal**');
         _LOG();
         //	Check order exists
         $_order = $this->shop_order_model->get_by_ref($this->input->get('ref'));
         if (!$_order) {
             _LOG('Invalid order reference, aborting.');
             _LOG('- - - - - - - - - - - - - - - - - - -');
             _LOG();
             return;
         }
         // --------------------------------------------------------------------------
         $_paypal = array();
         $_paypal['payment_type'] = 'instant';
         $_paypal['invoice'] = $_order->ref;
         $_paypal['custom'] = $this->encrypt->encode(md5($_order->ref . ':' . $_order->code), APP_PRIVATE_KEY);
         $_paypal['txn_id'] = 'TEST:' . random_string('alpha', 6);
         $_paypal['txn_type'] = 'cart';
         $_paypal['payment_status'] = 'Completed';
         $_paypal['pending_reason'] = 'PaymentReview';
         $_paypal['mc_fee'] = 0.0;
     } else {
         _LOG('Validating the IPN call');
         $this->load->library('paypal');
         $_ipn = $this->paypal->validate_ipn();
         $_paypal = $this->input->post();
         $_order = $this->shop_order_model->get_by_ref($this->input->post('invoice'));
         if (!$_order) {
             _LOG('Invalid order ID, aborting. Likely a transaction not initiated by the site.');
             _LOG('- - - - - - - - - - - - - - - - - - -');
             _LOG();
             return;
         }
     }
     // --------------------------------------------------------------------------
     //	Did the IPN validate?
     if ($_ipn) {
         _LOG('IPN Verified with PayPal');
         _LOG();
         // --------------------------------------------------------------------------
         //	Extra verification step, check the 'custom' variable decodes appropriately
         _LOG('Verifying data');
         _LOG();
         $_verification = $this->encrypt->decode($_paypal['custom'], APP_PRIVATE_KEY);
         if ($_verification != md5($_order->ref . ':' . $_order->code)) {
             $_data = array('pp_txn_id' => $_paypal['txn_id']);
             $this->shop_order_model->fail($_order->id, $_data);
             _LOG('Order failed secondary verification, aborting.');
             _LOG('- - - - - - - - - - - - - - - - - - -');
             _LOG();
             // --------------------------------------------------------------------------
             //	Inform developers
             send_developer_mail('An IPN request failed', 'An IPN request was made which failed secondary verification, Order: ' . $_paypal['invoice']);
             return;
         }
         // --------------------------------------------------------------------------
         //	Only bother to handle certain types
         //	TODO: handle refunds
         _LOG('Checking txn_type is supported');
         _LOG();
         if ($_paypal['txn_type'] != 'cart') {
             _LOG('"' . $_paypal['txn_type'] . '" is not a supported PayPal txn_type, gracefully aborting.');
             _LOG('- - - - - - - - - - - - - - - - - - -');
             _LOG();
             return;
         }
         // --------------------------------------------------------------------------
         //	Check if order has already been processed
         _LOG('Checking if order has already been processed');
         _LOG();
         if (ENVIRONMENT == 'production' && $_order->status != 'UNPAID') {
             _LOG('Order has already been processed, aborting.');
             _LOG('- - - - - - - - - - - - - - - - - - -');
             _LOG();
             return;
         } elseif (ENVIRONMENT != 'production' && $_order->status != 'UNPAID') {
             _LOG('Order has already been processed, but not on production so continuing anyway.');
             _LOG();
         }
         // --------------------------------------------------------------------------
         //	Check the status of the payment
         _LOG('Checking the status of the payment');
         _LOG();
         switch (strtolower($_paypal['payment_status'])) {
             case 'completed':
                 //	Do nothing, this transaction is OK
                 _LOG('Payment status is "completed"; continuing...');
                 break;
                 // --------------------------------------------------------------------------
             // --------------------------------------------------------------------------
             case 'reversed':
                 //	Transaction was cancelled, mark order as FAILED
                 _LOG('Payment was reversed, marking as failed and aborting');
                 $_data = array('pp_txn_id' => $_paypal['txn_id']);
                 $this->shop_order_model->fail($_order->id, $_data);
                 break;
                 // --------------------------------------------------------------------------
             // --------------------------------------------------------------------------
             case 'pending':
                 //	Check the pending_reason, if it's 'paymentreview' then gracefully stop
                 //	processing; PayPal will send a further IPN once the payment is complete
                 _LOG('Payment status is "pending"; check the reason.');
                 if (strtolower($_paypal['pending_reason']) == 'paymentreview') {
                     //	The transaction is pending review, gracefully stop proicessing, but don't cancel the order
                     _LOG('Payment is pending review by PayPal, gracefully aborting just now.');
                     $this->shop_order_model->pending($_order->id);
                     return;
                 } else {
                     _LOG('Unsupported payment reason "' . $_paypal['pending_reason'] . '", aborting.');
                     // --------------------------------------------------------------------------
                     $_data = array('pp_txn_id' => $_paypal['txn_id']);
                     $this->shop_order_model->fail($_order->id, $_data);
                     // --------------------------------------------------------------------------
                     //	Inform developers
                     send_developer_mail('A PayPal payment failed', '<strong>' . $_order->user->first_name . ' ' . $_order->user->last_name . ' (' . $_order->user->email . ')</strong> has just attempted to pay for order ' . $_order->ref . '. The payment failed with status "' . $_paypal['payment_status'] . '" and reason "' . $_paypal['pending_reason'] . '".');
                     return;
                 }
                 // --------------------------------------------------------------------------
                 return;
                 break;
                 // --------------------------------------------------------------------------
             // --------------------------------------------------------------------------
             default:
                 //	Unknown/invalid payment status
                 _LOG('Invalid payment status');
                 $_data = array('pp_txn_id' => $_paypal['txn_id']);
                 $this->shop_order_model->fail($_order->id, $_data);
                 // --------------------------------------------------------------------------
                 //	Inform developers
                 send_developer_mail('A PayPal payment failed', '<strong>' . $_order->user->first_name . ' ' . $_order->user->last_name . ' (' . $_order->user->email . ')</strong> has just attempted to pay for order ' . $_order->ref . '. The payment failed with status "' . $_paypal['payment_status'] . '" and reason "' . $_paypal['pending_reason'] . '".');
                 return;
                 break;
         }
         // --------------------------------------------------------------------------
         //	All seems good, continue with order processing
         _LOG('All seems well, continuing...');
         _LOG();
         _LOG('Setting txn_id (' . $_paypal['txn_id'] . ') and fees_deducted (' . $_paypal['mc_fee'] . ').');
         _LOG();
         $_data = array('pp_txn_id' => $_paypal['txn_id'], 'fees_deducted' => $_paypal['mc_fee']);
         $this->shop_order_model->paid($_order->id, $_data);
         // --------------------------------------------------------------------------
         //	PROCESSSSSS...
         $this->shop_order_model->process($_order);
         _LOG();
         // --------------------------------------------------------------------------
         //	Send a receipt to the customer
         _LOG('Sending receipt to customer: ' . $_order->user->email);
         $this->shop_order_model->send_receipt($_order);
         _LOG();
         // --------------------------------------------------------------------------
         //	Send a notification to the store owner(s)
         _LOG('Sending notification to store owner(s): ' . notification('notify_order', 'shop'));
         $this->shop_order_model->send_order_notification($_order);
         // --------------------------------------------------------------------------
         if ($_order->voucher) {
             //	Redeem the voucher, if it's there
             _LOG('Redeeming voucher: ' . $_order->voucher->code . ' - ' . $_order->voucher->label);
             $this->shop_voucher_model->redeem($_order->voucher->id, $_order);
         }
         // --------------------------------------------------------------------------
         _LOG();
         // --------------------------------------------------------------------------
         _LOG('All done here, going back to sleep...');
         _LOG('- - - - - - - - - - - - - - - - - - -');
         _LOG();
         if ($this->data['testing']) {
             echo anchor(app_setting('url', 'shop') . 'checkout/processing?ref=' . $_order->ref, 'Continue to Processing Page');
         }
     } else {
         _LOG('PayPal did not verify this IPN call, aborting.');
         _LOG('- - - - - - - - - - - - - - - - - - -');
         _LOG();
     }
 }
Example #4
0
 protected function _check_cache($file)
 {
     //	Check cache for $file
     if (!is_file(DEPLOY_CACHE_DIR . $file)) {
         //	If not found, generate
         $this->load->model('sitemap/sitemap_model');
         if (!$this->sitemap_model->generate()) {
             //	Failed to generate sitemap
             _LOG('Failed to generate sitemap: ' . $this->sitemap_model->last_error());
             //	Let the dev's know too, this could be serious
             send_developer_mail('Failed to generate sitemap', 'There was no ' . $file . ' data in the cache and I failed to recreate it.');
             //	Send a temporarily unavailable header, we don't want search engines unlisting us because of this.
             $this->output->set_header($this->input->server('SERVER_PROTOCOL') . ' 503 Service Temporarily Unavailable');
             $this->output->set_header('Status: 503 Service Temporarily Unavailable');
             $this->output->set_header('Retry-After: 7200');
             $this->load->view('sitemap/error');
             return FALSE;
         }
     }
     return TRUE;
 }
Example #5
0
 /**
  * Send a templated email immediately
  *
  * @access	private
  * @param	object	$input			The input object
  * @param	boolean	$graceful		Whether to fail gracefully or not
  * @return	boolean
  **/
 private function _send($email_id = FALSE, $graceful = FALSE)
 {
     //	Get the email if $email_id is not an object
     if (!is_object($email_id)) {
         $_email = $this->get_by_id($email_id);
     } else {
         $_email = $email_id;
     }
     // --------------------------------------------------------------------------
     if (!$_email) {
         $this->_set_error('EMAILER: Unable to fetch email object');
         return FALSE;
     }
     // --------------------------------------------------------------------------
     $_send = new stdClass();
     $_send->to = new stdClass();
     $_send->to->email = $_email->user->email;
     $_send->to->email_verified = (bool) $_email->email_verified;
     $_send->to->email_verified_code = $_email->email_verified_code;
     $_send->to->first = $_email->user->first_name;
     $_send->to->last = $_email->user->last_name;
     $_send->to->id = (int) $_email->user->id;
     $_send->to->username = $_email->user->username;
     $_send->to->group_id = $_email->user->group_id;
     $_send->to->login_url = $_email->user->id ? site_url('auth/login/with_hashes/' . md5($_email->user->id) . '/' . md5($_email->user->password)) : NULL;
     $_send->email_type_id = $_email->type_id;
     $_send->subject = $_email->subject;
     $_send->template = $_email->template_file;
     $_send->template_pt = $_email->template_file . '_plaintext';
     $_send->data = $_email->email_vars;
     $_send->data['ci'] =& get_instance();
     //	Check login URLs are allowed
     get_instance()->config->load('auth');
     if (!get_instance()->config->item('auth_enable_hashed_login')) {
         $_send->to->login_url = '';
     }
     if (!is_array($_send->data)) {
         $_send->data = array();
     }
     // --------------------------------------------------------------------------
     //	From user
     $_send->from = new stdClass();
     if (!empty($_send->data['email_from_email'])) {
         $_send->from->email = $_send->data['email_from_email'];
         $_send->from->name = !empty($_send->data['email_from_name']) ? $_send->data['email_from_name'] : $_send->data['email_from_email'];
     } else {
         $_send->from->email = $this->from->email;
         $_send->from->name = $this->from->name;
     }
     // --------------------------------------------------------------------------
     //	Fresh start please
     $this->ci->email->clear(TRUE);
     // --------------------------------------------------------------------------
     //	Add some extra, common variables for the template
     $_send->data['email_type_id'] = $_email->type_id;
     $_send->data['email_ref'] = $_email->ref;
     $_send->data['sent_from'] = $_send->from;
     $_send->data['sent_to'] = $_send->to;
     $_send->data['email_subject'] = $_send->subject;
     $_send->data['site_url'] = site_url();
     $_send->data['secret'] = APP_PRIVATE_KEY;
     // --------------------------------------------------------------------------
     //	If we're not on a production server, never send out to any live addresses
     $_send_to = $_send->to->email;
     if (ENVIRONMENT != 'production' || EMAIL_OVERRIDE) {
         if (EMAIL_OVERRIDE) {
             $_send_to = EMAIL_OVERRIDE;
         } elseif (APP_DEVELOPER_EMAIL) {
             $_send_to = APP_DEVELOPER_EMAIL;
         } else {
             //	Not sure where this is going; fall over *waaaa*
             show_error('EMAILER: Non production environment and neither EMAIL_OVERRIDE nor APP_DEVELOPER_EMAIL is set.');
             return FALSE;
         }
     }
     // --------------------------------------------------------------------------
     //	Start prepping the email
     $this->ci->email->from($this->from->email, $_send->from->name);
     $this->ci->email->reply_to($_send->from->email, $_send->from->name);
     $this->ci->email->to($_send_to);
     $this->ci->email->subject($_send->subject);
     // --------------------------------------------------------------------------
     //	Clear any errors which might have happened previously
     $_error =& load_class('Exceptions', 'core');
     $_error->clear_errors();
     //	Load the template
     $body = $this->ci->load->view('email/structure/header', $_send->data, TRUE);
     $body .= $this->ci->load->view('email/' . $_send->template, $_send->data, TRUE);
     $body .= $this->ci->load->view('email/structure/footer', $_send->data, TRUE);
     //	If any errors occurred while attempting to generate the body of this email
     //	then abort the sending and log it
     if (EMAIL_DEBUG && APP_DEVELOPER_EMAIL && $_error->error_has_occurred()) {
         //	The templates error'd, abort the send and let dev know
         $_subject = 'Email #' . $_email->id . ' failed to send due to errors occurring in the templates';
         $_message = 'Hi,' . "\n";
         $_message .= '' . "\n";
         $_message .= 'Email #' . $_email->id . ' was aborted due to errors occurring while building the template' . "\n";
         $_message .= '' . "\n";
         $_message .= 'Please take a look as a matter of urgency; the errors are noted below:' . "\n";
         $_message .= '' . "\n";
         $_message .= '- - - - - - - - - - - - - - - - - - - - - -' . "\n";
         $_message .= '' . "\n";
         $_errors = $_error->recent_errors();
         foreach ($_errors as $error) {
             $_message .= 'Severity: ' . $_error->levels[$error->severity] . "\n";
             $_message .= 'Message: ' . $error->message . "\n";
             $_message .= 'File: ' . $error->filepath . "\n";
             $_message .= 'Line: ' . $error->line . "\n";
             $_message .= '' . "\n";
         }
         $_message .= '' . "\n";
         $_message .= '- - - - - - - - - - - - - - - - - - - - - -' . "\n";
         $_message .= '' . "\n";
         $_message .= 'Additional debugging information:' . "\n";
         $_message .= '' . "\n";
         $_message .= '- - - - - - - - - - - - - - - - - - - - - -' . "\n";
         $_message .= '' . "\n";
         $_message .= print_r($_send, TRUE) . "\n";
         send_developer_mail($_subject, $_message);
         // --------------------------------------------------------------------------
         $this->_set_error('EMAILER: Errors in email template, developers informed');
         // --------------------------------------------------------------------------]
         return FALSE;
     }
     // --------------------------------------------------------------------------
     //	Parse the body for <a> links and replace with a tracking URL
     //	First clear out any previous link caches (production only)
     $this->track_link_cache = array();
     if (ENVIRONMENT == 'production') {
         if ($_send->to->id && !$_send->to->email_verified) {
             $_needs_verified = array('id' => $_send->to->id, 'code' => $_send->to->email_verified_code);
         } else {
             $_needs_verified = FALSE;
         }
         $body = $this->_parse_links($body, $_email->id, $_email->ref, TRUE, $_needs_verified);
     }
     // --------------------------------------------------------------------------
     //	Set the email body
     $this->ci->email->message($body);
     // --------------------------------------------------------------------------
     //	Set the plain text version
     $plaintext = $this->ci->load->view('email/structure/header_plaintext', $_send->data, TRUE);
     $plaintext .= $this->ci->load->view('email/' . $_send->template_pt, $_send->data, TRUE);
     $plaintext .= $this->ci->load->view('email/structure/footer_plaintext', $_send->data, TRUE);
     // --------------------------------------------------------------------------
     //	Parse the body for URLs and replace with a tracking URL (production only)
     if (ENVIRONMENT == 'production') {
         $plaintext = $this->_parse_links($plaintext, $_email->id, $_email->ref, FALSE, $_needs_verified);
     }
     // --------------------------------------------------------------------------
     $this->ci->email->set_alt_message($plaintext);
     // --------------------------------------------------------------------------
     //	Add any attachments
     if (isset($_send->data['attachments']) && is_array($_send->data['attachments']) && $_send->data['attachments']) {
         foreach ($_send->data['attachments'] as $file) {
             if (!$this->_add_attachment($file)) {
                 if (!$graceful) {
                     show_error('EMAILER: Failed to add attachment: ' . $file);
                 } else {
                     $this->_set_error('EMAILER: Insert Failed.');
                     return FALSE;
                 }
             }
         }
     }
     // --------------------------------------------------------------------------
     //	Debugging?
     if (EMAIL_DEBUG) {
         $this->_debugger($_send, $body, $plaintext, $_error->recent_errors());
         return FALSE;
     }
     // --------------------------------------------------------------------------
     //	Send! Turn off error reporting, if it fails we should handle it gracefully
     $_previous_error_reporting = error_reporting();
     error_reporting(0);
     if ($this->ci->email->send()) {
         //	Put error reporting back as it was
         error_reporting($_previous_error_reporting);
         // --------------------------------------------------------------------------
         //	Mail sent, mark the time
         $this->db->set('time_sent', 'NOW()', FALSE);
         $this->db->where('id', $_email->id);
         $this->db->update(NAILS_DB_PREFIX . 'email_archive');
         return TRUE;
     } else {
         //	Put error reporting back as it was
         error_reporting($_previous_error_reporting);
         // --------------------------------------------------------------------------
         //	Failed to send, notify developers
         $_subject = 'Email #' . $_email->id . ' failed to send at SMTP time';
         $_message = 'Hi,' . "\n";
         $_message .= '' . "\n";
         $_message .= 'Email #' . $_email->id . ' failed to send at SMTP time' . "\n";
         $_message .= '' . "\n";
         $_message .= 'Please take a look as a matter of urgency; debugging data is below:' . "\n";
         $_message .= '' . "\n";
         $_message .= '- - - - - - - - - - - - - - - - - - - - - -' . "\n";
         $_message .= '' . "\n";
         $_message .= $this->ci->email->print_debugger();
         $_message .= '' . "\n";
         $_message .= '- - - - - - - - - - - - - - - - - - - - - -' . "\n";
         $_message .= '' . "\n";
         $_message .= 'Additional debugging information:' . "\n";
         $_message .= '' . "\n";
         $_message .= '- - - - - - - - - - - - - - - - - - - - - -' . "\n";
         $_message .= '' . "\n";
         $_message .= print_r($_send, TRUE) . "\n";
         if (ENVIRONMENT == 'production') {
             $this->_set_error('Email failed to send at SMTP time, developers informed');
             send_developer_mail($_subject, $_message);
         } else {
             //	On non-production environments halt execution, this is an error with the configs
             //	and should probably be addressed
             if (!$graceful) {
                 show_error('Email failed to send at SMTP time. Potential configuration error. Investigate, debugging data below: <div style="padding:20px;background:#EEE">' . $this->ci->email->print_debugger() . '</div>');
             } else {
                 $this->_set_error('Email failed to send at SMTP time.');
             }
         }
         // --------------------------------------------------------------------------
         return FALSE;
     }
 }