From 24b8dfd54f1b85d0e19ee3b9af39208d96848aa7 Mon Sep 17 00:00:00 2001 From: e107steved Date: Sun, 15 Nov 2009 17:38:05 +0000 Subject: [PATCH] First cut of updated bulk mail handling, including support for provision of email addresses by plugins. Still very much a work in progress, but should send some sort of email if treated nicely. --- e107_admin/cron.php | 9 +- e107_admin/mailout.php | 1749 ++++++----------- e107_handlers/cron_class.php | 31 +- e107_handlers/mail.php | 119 +- e107_handlers/mail_manager_class.php | 1265 ++++++++++++ e107_handlers/mailout_admin_class.php | 1351 +++++++++++++ e107_handlers/mailout_class.php | 544 +++-- e107_handlers/plugin_class.php | 34 +- e107_languages/English/admin/help/mailout.php | 42 +- e107_languages/English/admin/lan_mailout.php | 176 +- .../languages/English_mailer.php | 23 + 11 files changed, 3862 insertions(+), 1481 deletions(-) create mode 100644 e107_handlers/mail_manager_class.php create mode 100644 e107_handlers/mailout_admin_class.php create mode 100644 e107_plugins/calendar_menu/languages/English_mailer.php diff --git a/e107_admin/cron.php b/e107_admin/cron.php index d0a35c9ad..58bd081cc 100644 --- a/e107_admin/cron.php +++ b/e107_admin/cron.php @@ -11,9 +11,9 @@ | GNU General Public License (http://gnu.org/). | | $Source: /cvs_backup/e107_0.8/e107_admin/cron.php,v $ -| $Revision: 1.14 $ -| $Date: 2009-11-10 15:33:00 $ -| $Author: marj_nl_fr $ +| $Revision: 1.15 $ +| $Date: 2009-11-15 17:38:04 $ +| $Author: e107steved $ +----------------------------------------------------------------------------+ */ @@ -50,7 +50,8 @@ class cron $this->cronAction = e_QUERY; $this->coreCrons['_system_cron'] = array( - 0 => array('name' => "Test Email", 'function' => "sendEmail", 'description' => "Send a test email to ".$pref['siteadminemail']."
Recommended to test the scheduling system."), + 0 => array('name' => 'Test Email', 'function' => 'sendEmail', 'description' => 'Send a test email to '.$pref['siteadminemail'].'
Recommended to test the scheduling system.'), + 1 => array('name' => 'Mail Queue', 'function' => 'procEmailQueue', 'description' => 'Process mail queue'), // 1 => array('name'=>'User Purge', 'function' => 'userPurge', 'description'=>'Purge Unactivated Users'), // 2 => array('name'=>'User UnActivated', 'function' => 'userUnactivated', 'description'=>'Resend activation email to unactivated users.'), // 3 => array('name'=>'News Sticky', 'function' => 'newsPurge', 'description'=>'Remove Sticky News Items') diff --git a/e107_admin/mailout.php b/e107_admin/mailout.php index 2e2fd4a86..6fcb6cc17 100644 --- a/e107_admin/mailout.php +++ b/e107_admin/mailout.php @@ -1,471 +1,525 @@ tp->toDB(varset($_GET['mode'],'makemail')); +$pageMode = varset($_GET['savepage'], $action); // Sometimes we need to know what brought us here - $action gets changed +$mailId = intval(varset($_GET['m'],0)); +$targetId = intval(varset($_GET['t'],0)); + + +// Create mail admin object, load all mail handlers +$mailAdmin = new mailoutAdminClass($action); // This decodes parts of the query using $_GET syntax +if ($mailAdmin->loadMailHandlers() == 0) +{ // No mail handlers loaded + echo 'No mail handlers loaded!!'; + exit; +} + + +$errors = array(); + +$subAction = ''; +$midAction = ''; + + +if (isset($_POST['mailaction'])) { - $qs = explode('.',e_QUERY); - $action = varset($qs[0],''); - switch ($action) - { - case 'justone' : - $mail_plugin = varset($qs[1],''); - $mail_plugin = trim($mail_plugin); - break; + if (is_array($_POST['mailaction'])) + { + foreach ($_POST['mailaction'] as $k => $v) + { + if ($v) // Look for non-empty action + { + $mailId = $k; + $action = $v; + break; + } + } + } +} + + +if (isset($_POST['targetaction'])) +{ + if (is_array($_POST['targetaction'])) + { + foreach ($_POST['targetaction'] as $k => $v) + { + if ($v) // Look for non-empty action + { + $targetId = $k; + $action = $v; + break; + } + } + } +} + +//echo "Action: {$action} MailId: {$mailId} Target: {$targetId}
"; +// ----------------- Actions -----------------------------------------------> +switch ($action) +{ + case 'prefs' : + if (getperms('0')) + { + if (isset($_POST['testemail'])) + { // Send test email - uses standard 'single email' handler + if(trim($_POST['testaddress']) == '') + { + $emessage->add(LAN_MAILOUT_19, E_MESSAGE_ERROR); + $subAction = 'error'; + } + else + { + $mailheader_e107id = USERID; + require_once(e_HANDLER.'mail.php'); + $add = ($pref['mailer']) ? " (".strtoupper($pref['mailer']).")" : ' (PHP)'; + $sendto = trim($_POST['testaddress']); + if (!sendemail($sendto, LAN_MAILOUT_113." ".SITENAME.$add, LAN_MAILOUT_114,LAN_MAILOUT_189)) + { + $emessage->add(($pref['mailer'] == 'smtp') ? LAN_MAILOUT_67 : LAN_MAILOUT_106, E_MESSAGE_ERROR); + } + else + { + $emessage->add(LAN_MAILOUT_81. ' ('.$sendto.')', E_MESSAGE_SUCCESS); + $admin_log->log_event('MAIL_01',$sendto,E_LOG_INFORMATIVE,''); + } + } + } + elseif (isset($_POST['updateprefs'])) + { + saveMailPrefs($emessage); + } + } + break; + + case 'mailedit' : // Edit existing mail + if (isset($_POST['mailaction'])) + { + $action = 'makemail'; + $mailData = $mailAdmin->retrieveEmail($mailId); + if ($mailData === FALSE) + { + $emessage->add(LAN_MAILOUT_164.':'.$mailId, E_MESSAGE_ERROR); + break; + } + } + break; + + case 'makemail' : + $newMail = TRUE; + if (isset($_POST['save_email'])) + { + $subAction = 'new'; + } + elseif (isset($_POST['update_email'])) + { + $subAction = 'update'; + $newMail = FALSE; + } + elseif (isset($_POST['send_email'])) + { // Send bulk email + $subAction = 'send'; + } + if ($subAction != '') + { + $mailData = $mailAdmin->parseEmailPost($newMail); + $errors = $mailAdmin->checkEmailPost($mailData, $subAction == 'send'); // Full check if sending email + if ($errors !== TRUE) + { + $subAction = 'error'; + break; + } + $mailData['mail_selectors'] = $mailAdmin->getAllSelectors(); // Add in the selection criteria + } + + // That's the checking over - now do something useful! + switch ($subAction) + { + case 'send' : // This actually creates the list of recipients in the display routine + $action = 'marksend'; + break; + case 'new' : + // TODO: Check all fields created - maybe + $mailData['mail_content_status'] = MAIL_STATUS_SAVED; + $mailData['mail_create_app'] = 'core'; + $result = $mailAdmin->saveEmail($mailData, TRUE); + if (is_numeric($result)) + { + $mailData['mail_source_id'] = $result; + $emessage->add(LAN_MAILOUT_145, E_MESSAGE_SUCCESS); + } + else + { + $emessage->add(LAN_MAILOUT_146, E_MESSAGE_ERROR); + } + break; + case 'update' : + $mailData['mail_content_status'] = MAIL_STATUS_SAVED; + $result = $mailAdmin->saveEmail($mailData, FALSE); + if (is_numeric($result)) + { + $mailData['mail_source_id'] = $result; + $emessage->add(LAN_MAILOUT_147, E_MESSAGE_SUCCESS); + } + else + { + $emessage->add(LAN_MAILOUT_146, E_MESSAGE_ERROR); + } + break; + } + break; + + case 'mailcancel' : + $action = $pageMode; // Want to return to some other page + if ($mailAdmin->cancelEmail($mailId)) + { + $emessage->add(str_replace('--ID--', $mailId, LAN_MAILOUT_220), E_MESSAGE_SUCCESS); + } + else + { + $errors[] = str_replace('--ID--', $mailId, LAN_MAILOUT_221); + } + break; + + case 'maildelete' : + break; + + case 'mailtargets' : + $action = 'recipients'; + // Intentional fall-through + case 'recipients' : + if (isset($_POST['etrigger_ecolumns'])) + { + $mailAdmin->mailbodySaveColumnPref($action); + } + break; + + case 'marksend' : // Actually do something with an email and list of recipients - entry from email confirm page + $action = 'saved'; + if (isset($_POST['email_cancel'])) // 'Cancel' in this context means 'delete' - don't want it any more + { + $midAction = 'midDeleteEmail'; + } + elseif (isset($_POST['email_hold'])) + { + if ($mailAdmin->activateEmail($mailId, TRUE)) + { + $emessage->add(str_replace('--ID--', $mailId, LAN_MAILOUT_187), E_MESSAGE_SUCCESS); + } + else + { + $errors[] = str_replace('--ID--', $mailId, LAN_MAILOUT_166); + } + $action = 'held'; + } + elseif (isset($_POST['email_send'])) + { + $midAction = 'midMoveToSend'; + $action = 'pending'; + } + break; + + case 'mailsendnow' : // Send mail previously on 'held' list. + $midAction = 'midMoveToSend'; + $action = 'pending'; + break; + + case 'maildeleteconfirm' : + $action = $pageMode; // Want to return to some other page + $midAction = 'midDeleteEmail'; + if (!isset($_POST['mailIDConf']) || (intval($_POST['mailIDConf']) != $mailId)) + { + $errors[] = str_replace(array('--ID--', '--CHECK--'), array($mailId, intval($_POST['mailIDConf'])), LAN_MAILOUT_174); + break; + } + break; + + case 'mailonedelete' : case 'debug' : - $sub_par = varset($qs[1],'sendmail'); - break; - case 'savedmail' : - case 'mailouts' : - $sub_par = varset($qs[1],''); - if ($sub_par) $mail_id = intval(varset($qs[2],0)); - } -} + $emessage->add('Not implemented yet', E_MESSAGE_ERROR); + break; - -// Class handler for core mailout functions -require_once(e_HANDLER."mailout_class.php"); - -$mail_handlers = array(); -$mail_handlers[] = new core_mailout(); // Start by loading the core mailout class - - -$active_mailers = explode(',',varset($pref['mailout_enabled'],'')); - - -// Load additional configured handlers -foreach (explode(',',$pref['mailout_sources']) as $mailer) -{ - if (isset($pref['plug_installed'][$mailer]) && in_array($mailer,$active_mailers)) -// if (isset($pref['plug_installed'][$mailer])) // Check its enabled later - { // Could potentially use this handler - its installed and enabled - if (($mail_plugin === FALSE) || ($mail_plugin == $mailer)) - { - if (!is_readable(e_PLUGIN.$mailer."/mailout_class.php")) - { - echo "Invalid mailer selected: ".$mailer."
"; - exit; - } - require_once(e_PLUGIN.$mailer."/mailout_class.php"); - if (varset($mailer_include_with_default,TRUE) || ($mail_plugin == $mailer)) - { // Definitely need this plugin - $mail_class = 'mailout_'.$mailer; - $temp = new $mail_class; - if ($temp->mailer_enabled) + case 'saved' : // Show template emails - probably no actions + if (isset($_POST['etrigger_ecolumns'])) { - $mail_handlers[] = &$temp; - if (($mail_plugin !== FALSE) && varset($mailer_exclude_default,FALSE)) - { - $mail_handlers[0]->mailer_enabled = FALSE; // Don't need default handler - } + $mailAdmin->mailbodySaveColumnPref($action); + } + break; + + case 'sent' : + case 'pending' : + case 'held' : + if (isset($_POST['etrigger_ecolumns'])) + { + $mailAdmin->mailbodySaveColumnPref($action); + } + break; + + case 'maint' : // Perform any maintenance actions required + if (isset($_POST['email_dross'])) + if ($mailAdmin->dbTidy()) + { + $emessage->add(LAN_MAILOUT_184, E_MESSAGE_SUCCESS); } else { - unset($temp); + $errors[] = LAN_MAILOUT_183; } - } - } - } -} + break; - -//---------------------------------------- -// Send test email - uses standard 'single email' handler -//---------------------------------------- -if (isset($_POST['testemail']) && getperms("0")) -{ - if(trim($_POST['testaddress']) == "") - { - $message = LAN_MAILOUT_19; - } - else - { - $mailheader_e107id = USERID; - require_once(e_HANDLER."mail.php"); - $add = ($pref['mailer']) ? " (".strtoupper($pref['mailer']).")" : " (PHP)"; - $sendto = trim($_POST['testaddress']); - if (!sendemail($sendto, LAN_MAILOUT_113." ".SITENAME.$add, LAN_MAILOUT_114,LAN_MAILOUT_125)) - { - $message = ($pref['mailer'] == "smtp") ? LAN_MAILOUT_67 : LAN_MAILOUT_106; - } - else - { - $message = LAN_MAILOUT_81. "(".$sendto.")"; - $admin_log->log_event('MAIL_01',$sendto,E_LOG_INFORMATIVE,''); - } - } -} - -/* -// Delete any mailout entries that have hung around for a day or more (intentionally commented out - done manually now) -$sql->db_Delete("generic", "gen_type='sendmail' AND gen_datestamp < ".(time()-86400)); -*/ - -//---------------------------------------- -// Saved emails -//---------------------------------------- -if (isset($_POST['save_email'])) -{ - $qry = "0,'massmail', '".time()."', '".USERID."', '".$tp->toDB($_POST['email_subject'])."', '0', \"".$tp->toDB($_POST['email_body'])."\" "; - $message = $sql -> db_Insert("generic", $qry) ? LAN_SAVED : LAN_ERROR; -} - - -if (isset($_POST['update_email'])) -{ - $qry = "gen_user_id = '".USERID."', gen_datestamp = '".time()."', gen_ip = '".$tp->toDB($_POST['email_subject'])."', gen_chardata= \"".$tp->toDB($_POST['email_body'])."\" WHERE gen_id = '".$_POST['update_id']."' "; - $message = $sql -> db_Update("generic", $qry) ? LAN_UPDATED : LAN_UPDATED_FAILED; -} - -/* -if (isset($_POST['delete'])) -{ - $d_idt = array_keys($_POST['delete']); - $message = ($sql -> db_Delete("generic", "gen_id='".$d_idt[0]."'")) ? LAN_DELETED : LAN_DELETED_FAILED; - $action = 'list'; -} - - -if (isset($_POST['edit'])) -{ - $e_idt = array_keys($_POST['edit']); - if($sql -> db_Select("generic", "*", "gen_id='".$e_idt[0]."' ")) - { - $foo = $sql -> db_Fetch(); - } -} -*/ - -if (($action == 'savedmail') && $sub_par && $mail_id) -{ -// echo "Dealing with saved emails {$sub_par} ID {$mail_id}
"; - switch($sub_par) - { - case 'edit' : - if($sql -> db_Select("generic", "*", "gen_id='".$mail_id."' ")) - { - $foo = $sql -> db_Fetch(); - $action = 'makemail'; - } - break; - case 'delete' : - $message = ($sql -> db_Delete("generic", "gen_id='".$mail_id."'")) ? LAN_DELETED : LAN_DELETED_FAILED; - $action = 'list'; - break; default : - $action = 'makemail'; - } -} + $emessage->add('Code malfunction 23! ('.$action.')', E_MESSAGE_ERROR); + $e107->ns->tablerender(LAN_MAILOUT_97, $emessage->render()); + exit; // Could be a hack attempt +} // switch($action) - end of 'executive' tasks - - - $_POST['mail_id'] = time(); // Unique ID for email - used to select our run of emails (as opposed to any other that might be going on) - -// if (!is_object($sql2)) $sql2 = new db; // Should be OK in 0.8 - - - -function ret_extended_field_list($list_name, $add_blank = FALSE) +// ------------------------ Intermediate actions --------------------------- +// (These have more than one route to trigger them) +switch ($midAction) { - $sql = e107::getDb(); - - $ret = "\n"; - return $ret; -} - -// --------------------------------------------- -// Find a block of emails to send -// --------------------------------------------- -if (isset($_POST['submit'])) -{ - $c = 0; // Record count - $dups = 0; // Counter for duplicates - - - $email_subject = $tp->toDB($_POST['email_subject']); - $mail_id = intval(varset($_POST['mail_id'],0)); - -/* Save the actual email, so we aren't reliant on passing $_POST data for immediate use - Format is as follows: - gen_id int(10) unsigned NOT NULL auto_increment, - set to zero (auto assigned) - gen_type varchar(80) NOT NULL default '', - record type being added ('savemail') - gen_datestamp int(10) unsigned NOT NULL default '0', - Mail ID code - to match the destination address records - gen_user_id int(10) unsigned NOT NULL default '0', - User ID of current author - gen_ip varchar(80) NOT NULL default '', - Email subject - gen_intdata int(10) unsigned NOT NULL default '0', - Initially set to zero - set to number of emails initially added - gen_chardata text NOT NULL, - 'From' email address and name, Email body -*/ - $email_data = array('sender_email' => $email_address, - 'sender_name' => $email_name, - 'copy_to' => $tp->toDB($_POST['email_cc']), - 'bcopy_to' => $tp->toDB($_POST['email_bcc']), - 'attach' => $tp->toDB(trim($_POST['email_attachment'])), - 'email_subject' => $tp->toDB(trim($_POST['email_subject'])), - 'email_body' => $tp->toDB($_POST['email_body']), - 'use_theme' => intval(varset($_POST['use_theme'],0)) - ); - $qry = "0,'savemail', '".$mail_id."', '".USERID."', '".$tp->toDB($_POST['email_subject'])."', '0', '".serialize($email_data)."' "; - - - - $message = ($mail_text_id = $sql -> db_Insert("generic", $qry)) ? LAN_SAVED : LAN_ERROR; - - $mail_text_id = intval($mail_text_id); - if ($mail_text_id == 0) - { - Echo "Email not saved.
"; - echo $message; - require_once(FOOTERF); - exit; - } - - - foreach ($mail_handlers as $m) - { // Get email addresses from each handler in turn. Do them one at a time, so that all can use the $sql data object - if ($m->mailer_enabled) - { - // Initialise - $m->select_init(); - - // Get email addresses - add to list, strip duplicates - while ($row = $m->select_add()) - { // Add email addresses to the database ready for sending (the body is never saved in the DB - it gets passed as a $_POST value) - - $email_address = trim($row['user_email']); - $email_name = $row['user_name']; - if ($email_name == '') { $email_name = 'unknown'; } - - $email_target = serialize(array('user_email' => $email_address, - 'user_name' => $email_name, - 'user_signup' => varset($row['user_signup'],''))); - -/* -Table data: - gen_id int(10) unsigned NOT NULL auto_increment, - set to zero (auto assigned) - gen_type varchar(80) NOT NULL default '', - record type being added - 'sendmail' - gen_datestamp int(10) unsigned NOT NULL default '0', - Mail ID code (matches the stored email) - gen_user_id int(10) unsigned NOT NULL default '0', - User ID - zero if not a registered user - gen_ip varchar(80) NOT NULL default '', - User email address (so we can search for duplicates) - gen_intdata int(10) unsigned NOT NULL default '0', - ID number of email text in 'generic' table (previous version used zero here) - gen_chardata text NOT NULL, - User email address, name, signup link ID (previous version stored subject here) -*/ - - - $qry = "0,'sendmail', '".$_POST['mail_id']."', '".$row['user_id']."', '".$email_address."', '".$mail_text_id."', '".$email_target."' "; - - if ($sql2->db_Select('generic', 'gen_ip', "`gen_datestamp`= '{$_POST['mail_id']}' AND `gen_ip`='{$email_address}'")) + case 'midDeleteEmail' : +// $emessage->add($pageMode.': Would delete here: '.$mailId, E_MESSAGE_SUCCESS); +// break; // Delete this + $result = $mailAdmin->deleteEmail($mailId, 'all'); + if (($result === FALSE) || !is_array($result)) { - $dups++; // Found second entry with same email address + $errors[] = str_replace('--ID--', $mailId, LAN_MAILOUT_166); } else { - if($sql2 -> db_Insert("generic", $qry)) - { - $c++; - } - else - { - echo "Error on insert: ".$qry."
"; - } + if (isset($result['content'])) + { + if ($result['content'] === FALSE) + { + $errors[] = str_replace('--ID--', $mailId, LAN_MAILOUT_167); + } + else + { + $emessage->add(str_replace('--ID--', $mailId, LAN_MAILOUT_167), E_MESSAGE_SUCCESS); + } + } + if (isset($result['recipients'])) + { + if ($result['recipients'] === FALSE) + { + $errors[] = str_replace('--ID--', $mailId, LAN_MAILOUT_169); + } + else + { + $emessage->add(str_replace(array('--ID--', '--NUM--'), array($mailId, $result['recipients']), LAN_MAILOUT_170), E_MESSAGE_SUCCESS); + } + } } - } - - // Close - $m->select_close(); - } - } - - $sql->db_Update('generic',"`gen_intdata`={$c} WHERE `gen_id`={$mail_text_id}"); - $admin_log->log_event('MAIL_02','ID: '.$mail_text_id.' '.$c.'[!br!]'.$_POST['email_from_name']." <".$_POST['email_from_email'],E_LOG_INFORMATIVE,''); + break; + case 'midMoveToSend' : + if ($mailAdmin->activateEmail($mailId, FALSE)) + { + $emessage->add(LAN_MAILOUT_185, E_MESSAGE_SUCCESS); + } + else + { + $errors[] = str_replace('--ID--', $mailId, LAN_MAILOUT_188); + } + break; +} - -// We've got all the email addresses here - display a confirmation form - $debug = (e_MENU == "debug") ? "?[debug]" : ""; - - $text = "
-
-
"; - - $text .= "\n"; - $text .= "\n"; - - $text .= "
"; - - $text .= "
{$c} ".LAN_MAILOUT_24."
"; - - $text .= "

- -
"; - $text .= "

".LAN_MAILOUT_118."


"; - - - -// Preview Email -// -------------- - $text .= " -
- - - - - - - - - "; - - -// Add in core and any plugin selectors here - foreach ($mail_handlers as $m) - { - if ($m->mailer_enabled) - { - $text .= ""; - } - } - - -// Support 'cc' and 'bcc' as standard mailout addresses - $text .= ($_POST['email_cc']) ? " - - - - ": ""; - - $text .= ($_POST['email_bcc']) ? " - - - - ": ""; - - $text .= " - - - - "; - - // Attachment - if ($email_data['attach']) - { - $text .= " - - - - "; - } - - // Figures - number of emails to send, number of duplicates stripped - $text .= " - - - - "; - - // Email text - $text .=" - - - -
".LAN_MAILOUT_01." / ".LAN_MAILOUT_02."".$_POST['email_from_name']." <".$_POST['email_from_email'].">
".$m->mailer_name."".$m->show_select(FALSE)."
".LAN_MAILOUT_04."".$_POST['email_cc']." 
".LAN_MAILOUT_05."".$_POST['email_bcc']." 
".LAN_MAILOUT_51."".$_POST['email_subject']." 
".LAN_MAILOUT_07."".$email_data['attach']." 
".LAN_MAILOUT_71." ".$c." ".LAN_MAILOUT_69.$dups.LAN_MAILOUT_70."
".stripslashes($tp->toHTML($_POST['email_body'],TRUE))."
-
"; - - - $ns->tablerender(LAN_MAILOUT_39." ({$c}) ", $text); - require_once(e_ADMIN."footer.php"); - exit; -} // End of previewed email - - - - -//. Update Preferences. - -if (isset($_POST['updateprefs']) && getperms('0')) +// --------------------- Display errors and results ------------------------ +if (is_array($errors) && (count($errors) > 0)) { + foreach ($errors as $e) + { + $emessage->add($e, E_MESSAGE_ERROR); + } + unset($errors); +} +if ($emessage->hasMessage()) +{ + $e107->ns->tablerender(LAN_MAILOUT_97, $emessage->render()); +} + + +// ---------------------- Display required page ---------------------------- +// At this point $action determines which page display is required - one of a +// fairly limited number of choices +$mailAdmin->newMode($action); +//echo "Action: {$action} MailId: {$mailId} Target: {$targetId}
"; + +switch ($action) +{ + case 'prefs' : + if (getperms('0')) + { + show_prefs($mailAdmin); + } + break; + + case 'maint' : + if (getperms('0')) + { + show_maint(FALSE); + } + break; + + case 'debug' : + if (getperms('0')) + { + show_maint(TRUE); + } + break; + + case 'saved' : // Show template emails + case 'sent' : + case 'pending' : + case 'held' : + $mailAdmin->showEmailList($action, -1, -1); + break; + + case 'maildelete' : // NOTE:: need to set previous page in form + $mailAdmin->showDeleteConfirm($mailId, $pageMode); + break; + + case 'marksend' : // Show the send confirmation page + $mailAdmin->sendEmailCircular($mailData); + break; + + case 'recipients' : + $mailAdmin->showmailRecipients($mailId, $action); + break; + + case 'makemail' : + default : + if (!is_array($mailData)) + { + $mailData = array(); // Empty array just in case + } + $mailAdmin->show_mailform($mailData); + break; +} + + + +require_once(e_ADMIN."footer.php"); + + + + +// Update Preferences. (security handled elsewhere) +function saveMailPrefs(&$emessage) +{ + global $pref; + $e107 = e107::getInstance(); unset($temp); if (!in_array($_POST['mailer'], array('smtp', 'sendmail', 'php'))) $_POST['mailer'] = 'php'; $temp['mailer'] = $_POST['mailer']; @@ -493,8 +547,11 @@ if (isset($_POST['updateprefs']) && getperms('0')) $temp['smtp_options'] = implode(',',$smtp_opts); + $temp['mail_sendstyle'] = $e107->tp->toDB($_POST['mail_sendstyle']); $temp['mail_pause'] = intval($_POST['mail_pause']); $temp['mail_pausetime'] = intval($_POST['mail_pausetime']); + $temp['mail_workpertick'] = intval($_POST['mail_workpertick']); + $temp['mail_workpertick'] = min($temp['mail_workpertick'],1000); $temp['mail_bounce_email'] = $e107->tp->toDB($_POST['mail_bounce_email']); $temp['mail_bounce_pop3'] = $e107->tp->toDB($_POST['mail_bounce_pop3']); $temp['mail_bounce_user'] = $e107->tp->toDB($_POST['mail_bounce_user']); @@ -505,530 +562,24 @@ if (isset($_POST['updateprefs']) && getperms('0')) $temp['mailout_enabled'] = implode(',',$_POST['mail_mailer_enabled']); $temp['mail_log_options'] = intval($_POST['mail_log_option']).','.intval($_POST['mail_log_email']); - if ($admin_log->logArrayDiffs($temp, $pref, 'MAIL_03')) + if ($e107->admin_log->logArrayDiffs($temp, $pref, 'MAIL_03')) { - save_prefs(); // Only save if changes - $message = LAN_SETSAVED; + save_prefs(); // Only save if changes - generates its own message +// $emessage->add(LAN_SETSAVED, E_MESSAGE_SUCCESS); } else { - $message = IMALAN_20; + $emessage->add(LAN_NO_CHANGE, E_MESSAGE_INFO); } } -if (isset($message)) -{ - $ns->tablerender("", "
".$message."
"); -} - - - -// ----------------- Actions -----------------------------------------------> - -//if((!e_QUERY && !$_POST['delete']) || $_POST['edit']) $action = 'makemail'; - -if (!varsettrue($action)) $action = 'makemail'; -switch ($action) -{ - case "prefs" : - if (getperms("0")) - { - show_prefs(); - } - break; - - case 'makemail' : - show_mailform($foo); - break; - - case "list" : - showList(); - break; - - case 'debug' : - showList($sub_par); - break; - - case 'mailouts' : - showMailouts($sub_par,$mail_id); -} - -require_once(e_ADMIN."footer.php"); - - - -//--------------------------------------------- -// List of incomplete mailouts -//--------------------------------------------- -function showMailouts($sub_par,$mail_id) -{ - global $images_path; - $e107 = e107::getInstance(); -// gen_datestamp int(10) unsigned NOT NULL default '0', - Mail ID code - to match the destination address records -// gen_user_id int(10) unsigned NOT NULL default '0', - User ID of current author -// gen_ip varchar(80) NOT NULL default '', - Email subject -// gen_intdata int(10) unsigned NOT NULL default '0', - Initially set to zero - set to number of emails initially added - - $message = ''; - if ($sub_par && $mail_id) - { - switch ($sub_par) - { - case 'delete' : - if ($e107->sql->db_Select('generic','gen_datestamp',"`gen_datestamp`={$mail_id} AND `gen_type`='savemail'")) - { - $message = $e107->sql->db_Delete('generic',"`gen_datestamp`={$mail_id} AND (`gen_type`='sendmail' OR `gen_type`='savemail')") ? LAN_DELETED : LAN_DELETED_FAILED; - $e107->admin_log->log_event('MAIL_04',$mail_id,E_LOG_INFORMATIVE,''); - } - else - { // Should only happen if people fiddle! - $message = "Error - database record not found"; - echo "DB error
"; - } - break; - - case 'detail' : // Show the detail of an email run above the main list - if ($e107->sql->db_Select('generic','gen_id,gen_datestamp,gen_chardata',"`gen_datestamp`={$mail_id} AND `gen_type`='savemail'")) - { - $row = $e107->sql->db_Fetch(); - // Display a little bit of the email - $mail = unserialize($row['gen_chardata']); - $text = " - - - - - \n - - - - \n - - - - \n"; - if ($e107->sql->db_Select('generic','gen_id,gen_datestamp,gen_chardata',"`gen_datestamp`={$mail_id} AND `gen_type`='sendmail'")) - { - $text .= "\n"; - } - $text .= " -
".LAN_MAILOUT_51."".$mail['email_subject']."
".LAN_MAILOUT_103."".(isset($mail['send_results']) ? implode('
',$mail['send_results']) : LAN_MAILOUT_104)."
".LAN_MAILOUT_105.""; - $spacer = ''; - $i = 0; - while (($row = $e107->sql->db_Fetch()) && ($i < 10)) - { - $this_mail = unserialize($row['gen_chardata']); - if (isset($this_mail['send_result'])) - { - $text .= $spacer.LAN_MAILOUT_03.' '.$this_mail['user_name'].' '.LAN_MAILOUT_107.' '.$this_mail['user_email'].' '.LAN_MAILOUT_108.' '.$this_mail['send_result']; - $spacer = '
'; - $i++; - } - } - $text .= "
- "; - $e107->ns->tablerender(LAN_MAILOUT_102." :: ".LAN_MAILOUT_97,$text); - } - else - { // Should only happen if people fiddle! - $message = "Error - database record not found"; - echo "DB error
"; - } - break; - - case 'resend' : - // Echo "resend: {$mail_id}
"; - if ($e107->sql->db_Select('generic','gen_id,gen_datestamp,gen_chardata',"`gen_datestamp`={$mail_id} AND `gen_type`='savemail'")) - { // Put up confirmation - $row = $e107->sql->db_Fetch(); - - $debug = (e_MENU == "debug") ? "[debug]" : ""; - $mailer_url = e_HANDLER."phpmailer/mailout_process.php?".$debug."{$row['gen_datestamp']}.{$row['gen_id']}"; - - $c = $e107->sql->db_Count('generic','(*)',"WHERE `gen_datestamp`={$mail_id} AND `gen_type`='sendmail'"); // Count of mails to go - - $text = "
-
- "; - $text .= "
{$c} ".LAN_MAILOUT_24."
"; - - $text .= "

- -
"; - $text .= "


"; - $e107->ns->tablerender(LAN_MAILOUT_99,$text); - - // Display a little bit of the email - $mail = unserialize($row['gen_chardata']); - $text = " - - - - - \n - - - - \n - - - - \n -
".LAN_MAILOUT_51."".$mail['email_subject']."
".LAN_MAILOUT_100."".$mail['email_body']."
- "; - $e107->ns->tablerender(LAN_MAILOUT_101,$text); - - return; - } - else - { // Should only happen if people fiddle! - $message = "Error - database record not found"; - echo "DB error
"; - } - break; - case 'orphans' : // Delete any orphaned emails - if ($e107->sql->db_Select('generic','gen_datestamp',"`gen_datestamp`={$mail_id} AND `gen_type`='sendmail'")) - { - $message = $e107->sql->db_Delete('generic',"`gen_datestamp`={$mail_id} AND `gen_type`='sendmail'") ? LAN_DELETED : LAN_DELETED_FAILED; - $e107->admin_log->log_event('MAIL_04',$mail_id,E_LOG_INFORMATIVE,''); - } - else - { // Should only happen if people fiddle! - $message = "Error - database record not found"; - echo "DB error
"; - } - break; - default : - echo "Invalid parameter: {$sub_par}
"; - } - } - - - if ($message) $e107->ns -> tablerender("
".LAN_MAILOUT_78."
", $message); - - // Need to select main email entries; count number of addresses attached to each - $gen = new convert; - $qry = "SELECT - u.user_name, g.*, - COUNT(m.gen_datestamp) AS pending - FROM `#generic` AS g - LEFT JOIN `#user` as u ON g.gen_user_id=u.user_id - LEFT JOIN `#generic` AS m ON m.gen_datestamp = g.gen_datestamp AND m.gen_type='sendmail' - WHERE g.gen_type='savemail' - GROUP BY g.gen_datestamp - ORDER BY g.gen_id ASC"; - $count = $e107->sql -> db_Select_gen($qry); - - $emails_found = array(); // Log ID and count for later - - $text = "
"; - - if (!$count) - { - $text = "
".LAN_MAILOUT_79."
"; - $e107->ns -> tablerender(ADLAN_136." :: ".LAN_MAILOUT_78, $text); - require_once(e_ADMIN."footer.php"); - exit; - } - - $text .= " -
- - - - - - - - - - - - - - - - - - - - "; - - while ($row = $e107->sql->db_Fetch()) - { - $datestamp = $gen->convert_date($row['gen_datestamp'], "short"); - - if ($row['pending']) $emails_found[$row['gen_datestamp']] = $row['pending']; // Log the mailshot in a list if any emails to go - $text .= " - - - - - - - - - "; - } - - $text .= "
".LAN_MAILOUT_84."".LAN_MAILOUT_80."".LAN_MAILOUT_85."".LAN_MAILOUT_06."".LAN_MAILOUT_82."".LAN_MAILOUT_83."".LAN_OPTIONS."
".$row['gen_datestamp'] ."".$datestamp."".$row['user_name']."".$row['gen_ip']."".$row['gen_intdata']."".$row['pending']." -
"; - $text .= "".LAN_MAILOUT_109.""; - if ($row['pending']) - { - $text .= "".LAN_MAILOUT_86.""; - } - $text .= " - ".LAN_DELETE." -
-
\n



"; - $e107->ns -> tablerender(ADLAN_136." :: ".LAN_MAILOUT_78, $text); - - // Now see if we can find any 'orphaned' mailout entries - $qry = "SELECT - g.gen_datestamp, - COUNT(g.gen_datestamp) AS pending - FROM `#generic` AS g - WHERE g.gen_type='sendmail' - GROUP BY g.gen_datestamp - ORDER BY g.gen_id ASC"; - $count = $e107->sql -> db_Select_gen($qry); - // Echo "There are {$count} groups of unsent emails: ".count($emails_found)." in previous table
"; - if ($count > count($emails_found)) - { - $text = " -
- - - - - - - - - - - \n - "; - while ($row = $e107->sql->db_Fetch()) - { - if (!isset($emails_found[$row['gen_datestamp']])) - { - $text .= " - - - - \n - "; - } - // echo "ID: {$row['gen_datestamp']} Unsent: {$row['pending']}"; - } - $text .= "
".LAN_MAILOUT_84."".LAN_MAILOUT_83."".LAN_OPTIONS."
".$row['gen_datestamp'] ."".$row['pending']." - -
\n



"; - $e107->ns -> tablerender("
".LAN_MAILOUT_98."
", $text); - } -} - - - -//--------------------------------------------- -// Display Mailout Form -//--------------------------------------------- - -function show_mailform($foo="") -{ - global $pref,$HANDLERS_DIRECTORY; - global $mail_handlers; - $e107 = e107::getInstance(); - $tp = e107::getParser(); - $frm = e107::getForm(); - - - - $email_subject = $foo['gen_ip']; - $email_body = $tp->toForm($foo['gen_chardata']); - $email_id = $foo['gen_id']; - $text = ""; - - if(strpos($_SERVER['SERVER_SOFTWARE'],"mod_gzip") && !is_readable(e_HANDLER."phpmailer/.htaccess")) - { - $warning = LAN_MAILOUT_40." ".$HANDLERS_DIRECTORY."phpmailer/ ".LAN_MAILOUT_41; - $e107->ns -> tablerender(LAN_MAILOUT_42, $warning); - } - - $debug = (e_MENU == "debug") ? "?[debug]" : ""; - $text .= "
-
- - - - - - - - - "; - - - $text .=" - - - - "; - - -// Add in the core and any plugin selectors here - foreach ($mail_handlers as $m) - { - if ($m->mailer_enabled) - { - $text .= ""; - } - } - - - -// CC, BCC - $text .= " - - - - - - - - - "; - - - -// Close one table, open another - to give a boundary between addressees and content - $text .= "
".LAN_MAILOUT_01.": - -
".LAN_MAILOUT_02.": - -
".$m->mailer_name."".$m->show_select(TRUE)."
".LAN_MAILOUT_04.": - -
".LAN_MAILOUT_05.": - -
- - - - - "; - -// Subject - $text .= " - - - - "; - - -// Attachment. //TODO needs to be pluginized. eg. e_mailout.php - $text .= " - - - "; - - - $text .= " - - - - - - - - "; - - $text .=" - - - -
".LAN_MAILOUT_51.": - -
".LAN_MAILOUT_07.": "; - $text .= ""; - - $text .= "
".LAN_MAILOUT_09.": - -
- -
-
"; - - global $eplug_bb; - - $eplug_bb[] = array( - 'name' => 'shortcode', - 'onclick' => 'expandit', - 'onclick_var' => 'sc_selector', - 'icon' => e_IMAGE.'generic/bbcode/shortcode.png', - 'helptext' => LAN_MAILOUT_11, - 'function' => 'sc_Select', - 'function_var' => 'sc_selector' - ); - - $text .= display_help('helpb','mailout'); - - if(e_WYSIWYG) - { - $text .=" - - - "; - } - - $text .=" -
"; - - - $text .= "
"; - if(isset($_POST['edit'])) - { - $text .= ""; - $text .= $frm->admin_button('update_email', LAN_UPDATE); - } - else - { - - $text .= $frm->admin_button('save_email', LAN_SAVE); - } - - - - $text .= $frm->admin_button('submit', LAN_MAILOUT_08); - - $text .= " -
- -
-
"; - - $e107->ns->tablerender(ADLAN_136." :: ".LAN_MAILOUT_56, $text); -} //---------------------------------------------------- // MAILER OPTIONS //---------------------------------------------------- -function show_prefs() +function show_prefs($mailAdmin) { global $pref; $e107 = e107::getInstance(); @@ -1053,7 +604,7 @@ function show_prefs() ".LAN_MAILOUT_110."
".$frm->admin_button(testemail, LAN_MAILOUT_112)."  - + @@ -1061,68 +612,71 @@ function show_prefs() ".LAN_MAILOUT_115."
".LAN_MAILOUT_116."
"; + $mailers = array('php','smtp','sendmail'); + foreach($mailers as $opt) + { + $sel = ($pref['mailer'] == $opt) ? "selected='selected'" : ""; + $text .= "\n"; + } + $text .=" ".LAN_MAILOUT_116."
"; // SMTP. --------------> $smtp_opts = explode(',',varset($pref['smtp_options'],'')); - $smtpdisp = ($pref['mailer'] != "smtp") ? "display:none;" : ""; - $text .= "
- "; - $text .= " + $smtpdisp = ($pref['mailer'] != 'smtp') ? "style='display:none;'" : ''; + $text .= "
+
+ + + + + "; + $text .= " + - - - + - - + - "; + $selected = (in_array('secure=SSL',$smtp_opts) ? " selected='selected'" : ''); + $text .= "\n"; + $selected = (in_array('secure=TLS',$smtp_opts) ? " selected='selected'" : ''); + $text .= "\n"; + $selected = (in_array('pop3auth',$smtp_opts) ? " selected='selected'" : ''); + $text .= "\n"; + $text .= "\n
".LAN_MAILOUT_94.""; $text .= " - "; - - - $checked = (in_array('useVERP',$smtp_opts) ? "checked='checked'" : ""); $text .= " - @@ -1130,13 +684,13 @@ function show_prefs() // Sendmail. --------------> - $senddisp = ($pref['mailer'] != "sendmail") ? "display:none;" : ""; - $text .= "
".LAN_MAILOUT_87.":   +
".LAN_MAILOUT_88.": (".LAN_OPTIONAL.")   + ".LAN_MAILOUT_88.": (".LAN_OPTIONAL.")  
".LAN_MAILOUT_89.": (".LAN_OPTIONAL.")   + ".LAN_MAILOUT_89.": (".LAN_OPTIONAL.")  
".LAN_MAILOUT_90.":  + ".LAN_MAILOUT_90." \n
".LAN_MAILOUT_94."
".LAN_MAILOUT_57.":  + ".LAN_MAILOUT_57." "; $checked = (varsettrue($pref['smtp_keepalive']) ) ? "checked='checked'" : ""; $text .= "
".LAN_MAILOUT_95.":  + ".LAN_MAILOUT_95."
"; + $senddisp = ($pref['mailer'] != 'sendmail') ? "style='display:none;'" : ""; + $text .= "
"; $text .= " - - + @@ -1147,27 +701,41 @@ function show_prefs() $text .=" + + + + + \n + + - \n"; - - + \n + + + + \n"; - if (isset($pref['mailout_sources'])) + if (isset($pref['e_mailout_list'])) { // Allow selection of email address sources - $text .= " + $text .= " - - + \n + \n + ".LAN_MAILOUT_76. + "\n"; - $text .= " - -
".LAN_MAILOUT_20.":   + ".LAN_MAILOUT_20.":  
".LAN_MAILOUT_222.""; + $text .= $mailAdmin->sendStyleSelect(varset($pref['mail_sendstyle'], 'textonly'), 'mail_sendstyle'); + $text .= + "".LAN_MAILOUT_223." +
".LAN_MAILOUT_25." ".LAN_MAILOUT_26." ".LAN_MAILOUT_27. - " ".LAN_MAILOUT_29.". + " ".LAN_MAILOUT_29.".
".LAN_MAILOUT_30."
".LAN_MAILOUT_156." + ".LAN_MAILOUT_157." +
".LAN_MAILOUT_77." + "; $mail_enable = explode(',',$pref['mailout_enabled']); - foreach (explode(',',$pref['mailout_sources']) as $mailer) - { + foreach ($pref['e_mailout_list'] as $mailer => $v) { $check = (in_array($mailer,$mail_enable)) ? "checked='checked'" : ""; $text .= $mailer." 
"; } @@ -1178,21 +746,18 @@ function show_prefs() $check = ($mail_log_email == 1) ? " checked='checked'" : ""; $text .= "
".LAN_MAILOUT_72." -
+
".LAN_MAILOUT_76. - "
- + $text .= "
".LAN_MAILOUT_31." @@ -1206,19 +771,21 @@ function show_prefs() - - - + + @@ -1247,181 +814,80 @@ function show_prefs() -//-------------------------------------------------------- -// Show list of saved emails -//-------------------------------------------------------- -// Default is what the user wants - saved emails -// Debug modes list any type of data in the generic table - don't believe the column headings! -function showList($type='massmail') +//----------------------------------------------------------- +// MAINTENANCE OPTIONS +//----------------------------------------------------------- +function show_maint($debug = FALSE) { - global $images_path; - - $ns = e107::getRender(); - $sql = e107::getDb(); - $tp = e107::getParser(); - - $gen = new convert; - if (!(trim($type))) $type = 'massmail'; - $qry ="SELECT g.*,u.* FROM #generic AS g LEFT JOIN #user AS u ON g.gen_user_id = u.user_id WHERE g.gen_type = '{$type}' ORDER BY g.gen_datestamp DESC"; - $count = $sql -> db_Select_gen($qry); + $e107 = e107::getInstance(); + $text = "
"; - $text = "
"; - - if (!$count) - { - $text = "
".LAN_MAILOUT_22."
"; - $ns -> tablerender(ADLAN_136." :: ".LAN_MAILOUT_97, $text); - require_once(e_ADMIN."footer.php"); - exit; - } - - $text .= " -
-
Auto-process script".substr($_SERVER['DOCUMENT_ROOT'],0,-1).e_HANDLER_ABS."bounce_handler.php"; - - //FIXME: for Windows, the is_executable() function only checks the file - // extensions of exe, com, bat and cmd. - if(!is_executable(e_HANDLER."bounce_handler.php")) - { - //FIXME hardcoded text and wrong info - $text .= " IMPORTANT! You need to CHMOD this file to 0755"; - } + Auto-process script".(e_DOCROOT ? substr(e_DOCROOT, 0, -1) : '/').e_HANDLER_ABS."bounce_handler.php"; + if(!is_readable(e_HANDLER.'bounce_handler.php')) + { + $text .= "
".LAN_MAILOUT_161.""; + } + elseif(!is_executable(e_HANDLER.'bounce_handler.php')) // Seems to give wrong answers on Windoze + { + $text .= "
".LAN_MAILOUT_162.""; + } + + // TODO: Determine type of bounce processing $text .= "
".LAN_MAILOUT_32."
".LAN_MAILOUT_32."
".LAN_MAILOUT_33."
".LAN_MAILOUT_34."
".LAN_MAILOUT_35."
- - - - - - - - - - - - - - - "; - - $glArray = $sql -> db_getList(); - foreach($glArray as $row2) - { - $datestamp = $gen->convert_date($row2['gen_datestamp'], "short"); - - $text .= " - - - - - - - "; - } + +
+
".LAN_MAILOUT_49."".LAN_MAILOUT_50."".LAN_MAILOUT_51."".LAN_MAILOUT_52."".LAN_OPTIONS."
".$row2['gen_id'] ."".$row2['user_name']."".$row2['gen_ip']."".$datestamp." -
"; - $text .= "".LAN_EDIT.""; -// -// toJS(LAN_CONFIRMDEL." [".$row2['gen_ip']."]")."') \" src='".$images_path."delete_16.png' alt='".LAN_DELETE."' title='".LAN_DELETE."' style='border:0px' /> $text .= " - toJS(LAN_CONFIRMDEL." [".$row2['gen_ip']."]")."') \">".LAN_DELETE." -
-
+ + + + + + "; - $text .= "
\n


"; - $ns -> tablerender(ADLAN_136." :: ".LAN_MAILOUT_97, $text); + $text .= "".LAN_MAILOUT_182." "; + $text .= "\n"; + + $e107->ns->tablerender("
".ADLAN_136." :: ".ADLAN_40."
", $text); + +// $text .= ""; } -// Generate list of userclasses, including the number of members in each class. -function userclasses($name) -{ - $sql = e107::getDb(); - - $text .= ""; - - return $text; -} function mailout_adminmenu() { - $action = (e_QUERY) ? e_QUERY : "post"; - if($action == "edit") + $e107 = e107::getInstance(); + $action = $e107->tp->toDB(varset($_GET['mode'],'makemail')); + if($action == 'mailedit') { - $action = "post"; + $action = 'makemail'; } - $var['post']['text'] = LAN_MAILOUT_56; + $var['post']['text'] = LAN_MAILOUT_190; $var['post']['link'] = e_SELF; - $var['post']['perm'] = "W"; + $var['post']['perm'] = 'W'; - $var['list']['text'] = LAN_MAILOUT_97; // Saved emails - $var['list']['link'] = e_SELF."?list"; - $var['list']['perm'] = "W"; + $var['saved']['text'] = LAN_MAILOUT_191; // Saved emails + $var['saved']['link'] = e_SELF.'?mode=saved'; + $var['saved']['perm'] = 'W'; - $var['mailouts']['text'] = LAN_MAILOUT_78; // Email runs - $var['mailouts']['link'] = e_SELF."?mailouts"; - $var['mailouts']['perm'] = "W"; + $var['pending']['text'] = LAN_MAILOUT_193; // Pending email runs + $var['pending']['link'] = e_SELF.'?mode=pending'; + $var['pending']['perm'] = 'W'; - if(getperms("0")){ + $var['held']['text'] = LAN_MAILOUT_194; // Held email runs + $var['held']['link'] = e_SELF.'?mode=held'; + $var['held']['perm'] = 'W'; + + $var['sent']['text'] = LAN_MAILOUT_192; // Completed email runs + $var['sent']['link'] = e_SELF.'?mode=sent'; + $var['sent']['perm'] = 'W'; + + if(getperms("0")) + { $var['prefs']['text'] = LAN_PREFS; - $var['prefs']['link'] = e_SELF."?prefs"; - $var['prefs']['perm'] = "0"; + $var['prefs']['link'] = e_SELF.'?mode=prefs'; + $var['prefs']['perm'] = '0'; + + $var['maint']['text'] = ADLAN_40; + $var['maint']['link'] = e_SELF.'?mode=maint'; + $var['maint']['perm'] = '0'; } - show_admin_menu(ADLAN_136, $action, $var); + show_admin_menu(LAN_MAILOUT_15, $action, $var); } -function sc_Select($container='sc_selector') -{ - $text =" - - -\n - -"; - - return $text; -} - - - - - - - - - - - - - function headerjs() @@ -1429,16 +895,17 @@ function headerjs() $text = " "; @@ -1454,5 +920,4 @@ function headerjs() } - ?> diff --git a/e107_handlers/cron_class.php b/e107_handlers/cron_class.php index 84b48e193..bd1b1fef2 100644 --- a/e107_handlers/cron_class.php +++ b/e107_handlers/cron_class.php @@ -10,13 +10,14 @@ | GNU General Public License (http://gnu.org). | | $Source: /cvs_backup/e107_0.8/e107_handlers/cron_class.php,v $ -| $Revision: 1.3 $ -| $Date: 2009-10-24 12:01:24 $ -| $Author: e107coders $ +| $Revision: 1.4 $ +| $Date: 2009-11-15 17:38:04 $ +| $Author: e107steved $ +----------------------------------------------------------------------------+ */ if (!defined('e107_INIT')) { exit; } +define ('CRON_MAIL_DEBUG', TRUE); class _system_cron { @@ -32,14 +33,28 @@ class _system_cron function sendEmail() // Test Email. { global $pref; - require_once(e_HANDLER."mail.php"); + require_once(e_HANDLER.'mail.php'); $message = "Your Cron test worked correctly. Sent at ".date("r")."."; - + sendemail($pref['siteadminemail'], "e107 - TEST Email Sent by cron.".date("r"), $message, $pref['siteadmin'],$pref['siteadminemail'], $pref['siteadmin']); } - - + function procEmailQueue() + { + global $pref; + if (CRON_MAIL_DEBUG) + { + $e107 = e107::getInstance(); + $e107->admin_log->e_log_event(10,debug_backtrace(),'DEBUG','CRON Email','Email run started',FALSE,LOG_TO_ROLLING); + } + require_once(e_HANDLER.'mail_manager_class.php'); + $mailManager = new e107MailManager(); + $mailManager->doEmailTask(varset($pref['mail_workpertick'],5)); + if (CRON_MAIL_DEBUG) + { + $e107->admin_log->e_log_event(10,debug_backtrace(),'DEBUG','CRON Email','Email run completed',FALSE,LOG_TO_ROLLING); + } + } } @@ -48,7 +63,7 @@ class _system_cron - /* $Id: cron_class.php,v 1.3 2009-10-24 12:01:24 e107coders Exp $ */ + /* $Id: cron_class.php,v 1.4 2009-11-15 17:38:04 e107steved Exp $ */ /**####################################################################################################**\ Version: V1.01 diff --git a/e107_handlers/mail.php b/e107_handlers/mail.php index ae1105d8c..3c0554da2 100644 --- a/e107_handlers/mail.php +++ b/e107_handlers/mail.php @@ -9,8 +9,8 @@ * e107 Main * * $Source: /cvs_backup/e107_0.8/e107_handlers/mail.php,v $ - * $Revision: 1.13 $ - * $Date: 2009-09-01 19:53:07 $ + * $Revision: 1.14 $ + * $Date: 2009-11-15 17:38:04 $ * $Author: e107steved $ */ @@ -26,7 +26,6 @@ Three main scenarios to handle: - Personalised mailshots - template email modified to personalise for each recipient (based on DB list) TODO: -1. Look at VERP - implement and check 2. Bulk mailing - look at using the batching constants with SMTPKeepAlive to reset the connection every so often 3. mail (PHP method) - note that it has parameters for additional headers and other parameters 4. Check that language support works - PHPMailer defaults to English if other files not available @@ -35,20 +34,15 @@ TODO: - Use rolling log for errors - error string(s) available - sort out entry - Look at support of some other logging options - Debug option to just log, not send emails (variables in place, and supported by current bulk mailer) -6. Capability to identify and log caller (for tracking down which bit of code sent emails) -7. Look at how cc, bcc addresses are handled in bulk mailing scenarios - may need to disable them on later sends. -8. Include theme info in header if enabled? 9. Make sure SMTPDebug can be set (TRUE/FALSE) 10. Get rid of mime_content_type() - deprecated (function $this->mime_types() does something similar, given a file extension) -11. Add public/protected/private to all functions and variables 12. Check support for port number - ATM we just override for SSL. Looks as if phpmailer can take it from end of server link. -13. Possibly strip bbcode from plain text mailings -14. Note option for class constants -16. Add a routine or class which adds a list of recipients and an email to the mailout DB +13. Possibly strip bbcode from plain text mailings - best done by caller? 18. Note object iteration - may be useful for dump of object state 19. Consider overriding error handler 20. Look at using new prefs structure 21. Should we always send an ID? +22. Force singleton so all mail sending flow controlled a bit Tested so far (with PHP4 version) @@ -137,7 +131,7 @@ if (!defined('e107_INIT')) { exit; } //define('MAIL_DEBUG',TRUE); -define('LOG_CALLER', TRUE); +//define('LOG_CALLER', TRUE); require_once(e_HANDLER.'phpmailer/class.phpmailer.php'); @@ -237,7 +231,7 @@ class e107Email extends PHPMailer $pop->Authorise($overrides['smtp_server'], 110, 30, $overrides['smtp_username'], $overrides['smtp_password'], 1); } - $this->Mailer = "smtp"; + $this->Mailer = 'smtp'; $this->localUseVerp = isset($smtp_options['useVERP']); if (isset($smtp_options['secure'])) { @@ -245,7 +239,7 @@ class e107Email extends PHPMailer { case 'TLS' : $this->SMTPSecure = 'tls'; - $this->Port = 465; // Can also use port 587 + $this->Port = 465; // Can also use port 587, and maybe even 25 break; case 'SSL' : $this->SMTPSecure = 'ssl'; @@ -322,10 +316,10 @@ class e107Email extends PHPMailer } if ($this->logHandle !== FALSE) { - fwrite($this->logHandle,"=====".date('H:i:s y.m.d')."----------------------------------------------------------------=====\r\n"); + fwrite($this->logHandle,"\n\n=====".date('H:i:s y.m.d')."----------------------------------------------------------------=====\r\n"); if ($logInfo) { - fwrite($this->logHandle,' Start of mail run by '.USERNAME." - {$count} emails to go. ID: {$mail_id}. Subject: {$mail_subject}\r\n"); + fwrite($this->logHandle,' Mailer opened by '.USERNAME." - ID: {$mail_id}. Subject: {$this->Subject} Log action: {$this->logEnable}\r\n"); if ($this->add_email) { fwrite($this->logHandle, 'From: '.$this->From.' ('.$this->FromName.")\r\n"); @@ -587,24 +581,25 @@ class e107Email extends PHPMailer public function arraySet($paramlist) { if (isset($paramlist['SMTPDebug'])) $this->SMTPDebug = $paramlist['SMTPDebug']; // 'FALSE' is a valid value! - if (varsettrue($paramlist['subject'])) $this->Subject = $paramlist['subject']; - if (varsettrue($paramlist['from'])) $this->From = $paramlist['from']; - if (varsettrue($paramlist['fromname'])) $this->FromName = $paramlist['fromname']; - if (varsettrue($paramlist['replyto'])) $this->AddAddressList('replyto',$paramlist['replyto'],varsettrue($paramlist['replytonames'],'')); + if (varsettrue($paramlist['mail_subject'])) $this->Subject = $paramlist['mail_subject']; + if (varsettrue($paramlist['mail_sender_email'])) $this->From = $paramlist['mail_sender_email']; + if (varsettrue($paramlist['mail_sender_name'])) $this->FromName = $paramlist['mail_sender_name']; + if (varsettrue($paramlist['mail_replyto'])) $this->AddAddressList('replyto',$paramlist['mail_replyto'],varsettrue($paramlist['mail_replytonames'],'')); if (isset($paramlist['send_html'])) $this->allow_html = $paramlist['send_html']; // 'FALSE' is a valid value! if (isset($paramlist['add_html_header'])) $this->add_HTML_header = $paramlist['add_html_header']; // 'FALSE' is a valid value! - if (varsettrue($paramlist['message'])) $this->makeBody($paramlist['message'], $this->allow_html, $this->add_HTML_header); - if (varsettrue($paramlist['attachments'])) $this->attach($paramlist['attachments']); - if (varsettrue($paramlist['cc'])) $this->AddAddressList('cc',$paramlist['cc'],varsettrue($paramlist['ccnames'],'')); - if (varsettrue($paramlist['bcc'])) $this->AddAddressList('bcc',$paramlist['bcc'],varsettrue($paramlist['bccnames'],'')); + if (varsettrue($paramlist['mail_body'])) $this->makeBody($paramlist['mail_body'], $this->allow_html, $this->add_HTML_header); + if (varsettrue($paramlist['mail_attach'])) $this->attach($paramlist['mail_attach']); + if (varsettrue($paramlist['mail_copy_to'])) $this->AddAddressList('cc',$paramlist['mail_copy_to'],varsettrue($paramlist['mail_cc_names'],'')); + if (varsettrue($paramlist['mail_bcopy_to'])) $this->AddAddressList('bcc',$paramlist['mail_bcopy_to'],varsettrue($paramlist['mail_bcc_names'],'')); if (varsettrue($paramlist['bouncepath'])) { $this->Sender = $paramlist['bouncepath']; // Bounce path $this->save_bouncepath = $paramlist['bouncepath']; // Bounce path } if (varsettrue($paramlist['returnreceipt'])) $this->ConfirmReadingTo = $paramlist['returnreceipt']; - if (varsettrue($paramlist['inline-images'])) $this->addInlineImages($paramlist['inline-images']); - if (varsettrue($paramlist['priority'])) $this->Priority = $paramlist['priority']; + if (varsettrue($paramlist['mail_inline_images'])) $this->addInlineImages($paramlist['mail_inline_images']); + if (varsettrue($paramlist['mail_priority'])) $this->Priority = $paramlist['mail_priority']; + if (varsettrue($paramlist['e107_header'])) $this->AddCustomHeader("X-e107-id: {$paramlist['e107_header']}"); if (varsettrue($paramlist['extra_header'])) { if (is_array($paramlist['extra_header'])) @@ -627,30 +622,35 @@ class e107Email extends PHPMailer } - // Send an email where the bulk of the data is passed in an array. Returns 0 on success. - // (Even if the array is null, because everything previously set up, this is the preferred entry point) - // Where parameter not present in the array, doesn't get changed - useful for bulk mailing - // If doing bulk mailing with repetitive calls, set $bulkmail parameter true, and must call allSent() when completed - // Some of these parameters have been made compatible with the array calculated by render_email() in signup.php - // Possible array parameters: - // $eml['subject'] - // $eml['from'] - // $eml['fromname'] - // $eml['replyto'] - Optional 'reply to' field - // $eml['replytonames'] - Name(s) corresponding to 'reply to' field - only used if 'replyto' used - // $eml['send_html'] - if TRUE, includes HTML part in messages (only those added after this flag) - // $eml['add_html_header'] - if TRUE, adds the 2-line DOCTYPE declaration to the front of the HTML part (but doesn't add ... - // $eml['message'] - message body. May be HTML or text. Added according to the current state of the HTML enable flag - // $eml['attachments'] - string if one file, array of filenames if one or more. - // $eml['cc'] - comma-separated list - // $eml['bcc'] - comma-separated list - // $eml['bouncepath'] - Sender field (used for bounces) - // $eml['returnreceipt'] - email address for notification of receipt (reading) - // $eml['inline-images'] - array of files for inline images - // $eml['priority'] - Email priority (1 = High, 3 = Normal, 5 = low) - // $eml['extra_header'] - additional headers - // $eml['wordwrap'] - Set wordwrap value - // $eml['split'] - If true, sends an individual email to each recipient + /* + Send an email where the bulk of the data is passed in an array. Returns 0 on success. + (Even if the array is null, because everything previously set up, this is the preferred entry point) + Where parameter not present in the array, doesn't get changed - useful for bulk mailing + If doing bulk mailing with repetitive calls, set $bulkmail parameter true, and must call allSent() when completed + Some of these parameters have been made compatible with the array calculated by render_email() in signup.php + Possible array parameters: + $eml['mail_subject'] + $eml['mail_sender_email'] - 'From' email address + $eml['mail_sender_name'] - 'From' name + $eml['mail_replyto'] - Optional 'reply to' field + $eml['mail_replytonames'] - Name(s) corresponding to 'reply to' field - only used if 'replyto' used + $eml['send_html'] - if TRUE, includes HTML part in messages (only those added after this flag) + $eml['add_html_header'] - if TRUE, adds the 2-line DOCTYPE declaration to the front of the HTML part (but doesn't add ...) + $eml['mail_body'] - message body. May be HTML or text. Added according to the current state of the HTML enable flag + $eml['mail_attach'] - string if one file, array of filenames if one or more. + $eml['mail_copy_to'] - comma-separated list of cc addresses. + $eml['mail_cc_names''] - comma-separated list of cc names. Optional, used only if $eml['mail_copy_to'] specified + $eml['mail_bcopy_to'] - comma-separated list + $eml['mail_bcc_names''] - comma-separated list of bcc names. Optional, used only if $eml['mail_copy_to'] specified + $eml['bouncepath'] - Sender field (used for bounces) + $eml['returnreceipt'] - email address for notification of receipt (reading) + $eml['mail_inline_images'] - array of files for inline images + $eml['priority'] - Email priority (1 = High, 3 = Normal, 5 = low) + $eml['e107_header'] - Adds specific 'X-e107-id:' header + $eml['extra_header'] - additional headers (format is name: value + $eml['wordwrap'] - Set wordwrap value + $eml['split'] - If true, sends an individual email to each recipient + */ public function sendEmail($send_to, $to_name, $eml = '', $bulkmail = FALSE) { // $e107 = e107::getInstance(); @@ -681,7 +681,7 @@ class e107Email extends PHPMailer { $result = $this->Send(); // Actually send email - if (!$bulkmail && $this->SMTPKeepAlive && ($this->Mailer == 'smtp')) $this->SmtpClose(); + if (!$bulkmail && !$this->SMTPKeepAlive && ($this->Mailer == 'smtp')) $this->SmtpClose(); } else { // Debug @@ -697,17 +697,23 @@ class e107Email extends PHPMailer $this->SendCount = 0; } - $this->logLine("Send to {$to_name} at {$send_to} Mail-ID={$mail_custom} - {$result}"); + $this->logLine("Send to {$to_name} at {$send_to} Mail-ID={$mail_custom} - ".($result ? 'Success' : 'Fail')); $this->ClearAddresses(); // In case we send another email $this->ClearCustomHeaders(); - if ($result) return TRUE; - + if ($result) + { + $this->closeLog(); + return TRUE; + } + + $this->logLine('Error info: '.$this->ErrorInfo); // Error sending email $e107 = e107::getInstance(); $e107->admin_log->e_log_event(3,debug_backtrace(),"MAIL","Send Failed",$this->ErrorInfo,FALSE,LOG_TO_ROLLING); $this->TotalErrors++; + $this->closeLog(); return $this->ErrorInfo; } @@ -764,7 +770,7 @@ class e107Exception extends Exception //----------------------------------------------------- // Legacy interface for backward compatibility //----------------------------------------------------- -// (Preferred interface is to instantiate an e107_mail object, then call sendEmail method with an array of parameters +// (Preferred interface is to instantiate an e107Mail object, then call sendEmail method with an array of parameters // If $send_from is blank, uses the 'replyto' name and email if set, otherwise site admins details // $inline is a comma-separated list of embedded images to be included @@ -813,13 +819,12 @@ function sendemail($send_to, $subject, $message, $to_name, $send_from='', $from_ if (varsettrue($returnreceipt)) $mail->ConfirmReadingTo($returnreceipt); - if ($mail->sendEmail($send_to,$to_name)) + if ($mail->sendEmail($send_to,$to_name) === TRUE) { // Success return TRUE; } - // TODO: Possibly Log this somewhere (sendEmail method logs to rolling log) - echo "Mail sending error: ".$mail->ErrorInfo."
"; + // Error info already logged return FALSE; } diff --git a/e107_handlers/mail_manager_class.php b/e107_handlers/mail_manager_class.php new file mode 100644 index 000000000..dd5d9d756 --- /dev/null +++ b/e107_handlers/mail_manager_class.php @@ -0,0 +1,1265 @@ + 1 = retries to go (i.e. pending) + mail_detail_id Email body link + mail_e107_priority Our internal priority - generally high for single emails, low for bulk emails + mail_send_date Earliest date/time when email may be sent. Once mail sent, actual time/date of sending (or time of failure to send) + mail_target_info Array of target-specific info for substitution into email + +mail_content - Details of the email to be sent to a number of people + mail_source_id + mail_content_status 0 = sent, 2 = pending, 9 = saved? + mail_togo_count Number of recipients to go + mail_sent_count Number of successful sends (including bounces) + mail_fail_count Number of unsuccessful sends + mail_bounce_count Number of bounced emails + mail_start_send Time/date of sending first email + mail_end_send Time/date of sending last email + mail_create_date + mail_creator User ID + mail_create_app ID string for application/plugin creating mail + mail_last_date Don't send after this date/time + mail_title A description of the mailout - not sent + mail_subject + mail_body + mail_other Evaluates to an array of misc info - cc, bcc, attachments etc + + +Within internal arrays, a flat structure is adopted. Variables relating to DB values all begin 'mail_' - others are internal (volatile) control variables + +*/ + +if (!defined('e107_INIT')) { exit; } + +define('MAIL_STATUS_SENT', 0); // Mail sent. Email handler happy, but may have bounced (or may be yet to bounce) +define('MAIL_STATUS_BOUNCED', 1); +define('MAIL_STATUS_CANCELLED', 2); +define('MAIL_STATUS_FAILED', 5); // Failure on initial send - rejected by selected email handler + // This must be the numerically highest 'processing complete' code +define('MAIL_STATUS_PENDING', 10); // Mail which is in the sending list (even if outside valid sending window) + // This must be the numerically lowest 'not sent' code + // E107_EMAIL_MAX_TRIES values used in here for retry counting +define('MAIL_STATUS_MAX_ACTIVE', 19); // Highest allowable 'not sent or processed' code +define('MAIL_STATUS_SAVED', 20); // Identifies an email which is just saved (or in process of update) +define('MAIL_STATUS_HELD',21); // Held pending release +define('MAIL_STATUS_TEMP', 22); // Tags entries which aren't yet in any list + + +class e107MailManager +{ + const E107_EMAIL_PRIORITY_LOW = 1; // 'E107' priorities, to determine what to do next. + const E107_EMAIL_PRIORITY_MED = 3; // Distinct from the priority which can be assigned to the... + const E107_EMAIL_PRIORITY_HIGH = 5; // actual email when sending. Use LOW or MED for bulk mail, HIGH for individual emails. + + const E107_EMAIL_MAX_TRIES = 3; // Maximum number of tries by us (mail server may do more) + // - max allowable value is MAIL_STATUS_MAX_ACTIVE - MAIL_STATUS_PENDING + + private $debugMode = 0; + protected $e107; + protected $db = NULL; // Use our own database object - this one for reading data + protected $db2 = NULL; // Use our own database object - this one for updates + protected $queryActive = FALSE; // Keeps track of unused records in currently active query + protected $mailCounters = array(); // Counters to track adding recipients + protected $queryCount = array(); // Stores total number of records if SQL_CALC_ROWS is used (index = db object #) + protected $currentBatchInfo = array(); // Used during batch send to hold info about current mailout + protected $mailBody = ''; // Buffers current mail body + + protected $mailer = NULL; // Mailer class when required + + // Array defines DB types to be used + protected $dbTypes = array( + 'mail_recipients' => array + ( + 'mail_target_id' => 'int', + 'mail_recipient_id' => 'int', + 'mail_recipient_email' => 'todb', + 'mail_recipient_name' => 'todb', + 'mail_status' => 'int', + 'mail_detail_id' => 'int', + 'mail_send_date' => 'int', + 'mail_target_info' => 'string' // Don't want entities here! + ), + 'mail_content' => array( + 'mail_source_id' => 'int', + 'mail_content_status' => 'int', + 'mail_togo_count' => 'int', + 'mail_sent_count' => 'int', + 'mail_fail_count' => 'int', + 'mail_bounce_count' => 'int', + 'mail_start_send' => 'int', + 'mail_end_send' => 'int', + 'mail_create_date' => 'int', + 'mail_creator' => 'int', + 'mail_create_app' => 'todb', + 'mail_e107_priority' => 'int', + 'mail_last_date' => 'int', + 'mail_title' => 'todb', + 'mail_subject' => 'todb', + 'mail_body' => 'todb', + 'mail_other' => 'string' // Don't want entities here! + ) + ); + + // Array defines defaults for 'NOT NULL' fields where a default can't be set in the field definition + protected $dbNull = array('mail_recipients' => array + ( + 'mail_target_info' => '' + ), + 'mail_content' => array( + 'mail_body' => '', + 'mail_other' => '' + ) + ); + + // List of fields which are combined into the 'mail_other' field of the email + protected $dbOther = array( + 'mail_sender_email' => 1, + 'mail_sender_name' => 1, + 'mail_copy_to' => 1, + 'mail_bcopy_to' => 1, + 'mail_attach' => 1, + 'mail_send_style' => 1, + 'mail_selectors' => 1 // Only used internally + ); + + /** + * Constructor + * + * + * @return void + */ + public function __construct() + { + $this->e107 = e107::getInstance(); + } + + + /** + * Generate an array of data which can be passed directly to the DB routines. + * Only valid DB fields are copied + * Combining/splitting of fields is done as necessary + * (This is essentially the translation between internal storage format and db storage format. If + * the DB format changes, only this routine and its counterpart should need changing) + * + * @param $data - array of email-related data in internal format + * @param $addMissing - if TRUE, undefined fields are added + * + * @return void + */ + public function mailToDb(&$data, $addMissing = FALSE) + { + $res = array(); + $res1 = array(); + // Generate the 'mail_other' array first + foreach ($this->dbOther as $f => $v) + { + if (isset($data[$f])) + { + $res1[$f] = $data[$f]; + } + elseif ($addMissing) + { + $res1[$f] = ''; + } + } + + // Now do the main email array + foreach ($this->dbTypes['mail_content'] as $f => $v) + { + if (isset($data[$f])) + { + $res[$f] = $data[$f]; + } + elseif ($addMissing) + { + $res[$f] = ''; + } + } + $array = new ArrayData; + $res['mail_other'] = $array->WriteArray($res1, TRUE); // Ready to write to DB + return $res; + } + + + /** + * Given an array (row) of data retrieved from the DB table, converts to internal format. + * Combining/splitting of fields is done as necessary + * (This is essentially the translation between internal storage format and db storage format. If + * the DB format changes, only this routine and its counterpart should need changing) + * + * @param $data - array of DB-sourced email-related data + * @param $addMissing - if TRUE, undefined fields are added + * + * @return array of data + */ + public function dbToMail(&$data, $addMissing = FALSE) + { + $res = array(); + + // Now do the main email array + foreach ($this->dbTypes['mail_content'] as $f => $v) + { + if (isset($data[$f])) + { + $res[$f] = $data[$f]; + } + elseif ($addMissing) + { + $res[$f] = ''; + } + } + + if (isset($data['mail_other'])) + { + $array = new ArrayData; + $tmp = $array->ReadArray($data['mail_other']); + if (is_array($tmp)) + { + $res = array_merge($res,$tmp); + } + unset($res['mail_other']); + } + elseif ($addMissing) + { + foreach ($this->dbOther as $f => $v) + { + $res[$f] = ''; + } + } + return $res; + } + + + + /** + * Generate an array of data which can be passed directly to the DB routines. + * Only valid DB fields are copied + * Combining/splitting of fields is done as necessary + * (This is essentially the translation between internal storage format and db storage format. If + * the DB format changes, only this routine and its counterpart should need changing) + * + * @param $data - array of email target-related data in internal format + * @param $addMissing - if TRUE, undefined fields are added + * + * @return void + */ + public function targetToDb(&$data, $addMissing = FALSE) + { // Direct correspondence at present (apart from needing to convert potential array $data['mail_target_info']) - but could change + $res = array(); + foreach ($this->dbTypes['mail_recipients'] as $f => $v) + { + if (isset($data[$f])) + { + $res[$f] = $data[$f]; + } + elseif ($addMissing) + { + $res[$f] = ''; + } + } + if (isset($data['mail_target_info']) && is_array($data['mail_target_info'])) + { + $array = new ArrayData; + $tmp = $array->WriteArray($data['mail_target_info'], TRUE); + $res['mail_target_info'] = $tmp; + } + return $res; + } + + + + /** + * Given an array (row) of data retrieved from the DB table, converts to internal format. + * Combining/splitting of fields is done as necessary + * (This is essentially the translation between internal storage format and db storage format. If + * the DB format changes, only this routine and its counterpart should need changing) + * + * @param $data - array of DB-sourced target-related data + * @param $addMissing - if TRUE, undefined fields are added + * + * @return void + */ + public function dbToTarget(&$data, $addMissing = FALSE) + { // Direct correspondence at present - but could change + $res = array(); + foreach ($this->dbTypes['mail_recipients'] as $f => $v) + { + if (isset($data[$f])) + { + $res[$f] = $data[$f]; + } + elseif ($addMissing) + { + $res[$f] = ''; + } + } + if (isset($data['mail_target_info'])) + { + $array = new ArrayData; + $tmp = $array->ReadArray($data['mail_target_info']); + $res['mail_target_info'] = $tmp; + } + return $res; + } + + + + + /** + * Set the internal debug/logging level + * + * @return void + */ + public function controlDebug($level = 0) + { + $this->debugMode = $level; + } + + + // Internal function to create a db object for our use if none exists + protected function checkDB($which = 1) + { + if (($which == 1) && ($this->db == NULL)) + { + $this->db = new db; + } + if (($which == 2) && ($this->db2 == NULL)) + { + $this->db2 = new db; + } + } + + + // Internal function to create a mailer object for our use if none exists + protected function checkMailer() + { + if ($this->mailer != NULL) return; + if (!class_exists('e107Email')) + { + require_once(e_HANDLER.'mail.php'); + } + $this->mailer = new e107Email; // Could add in overrides here + } + + + + /** + * Select the next $count emails in the send queue + * $count gives the maximum number. '*' does 'select all' + * @return Returns FALSE on error. + * @return Returns a 'handle' on success (actually the ID in the DB of the email) + */ + public function selectEmails($count = 1) + { + if (is_numeric($count)) + { + if ($count < 1) $count = 1; + $count = ' LIMIT '.$count; + } + else + { + $count = ''; + } + $this->checkDB(1); // Make sure DB object created + $query = "SELECT mt.*, ms.* FROM `#mail_recipients` AS mt + LEFT JOIN `#mail_content` AS ms ON mt.`mail_detail_id` = ms.`mail_source_id` + WHERE ms.`mail_content_status` = ".MAIL_STATUS_PENDING." + AND mt.`mail_status` >= ".MAIL_STATUS_PENDING." + AND mt.`mail_status` <= ".MAIL_STATUS_MAX_ACTIVE." + AND mt.`mail_send_date` <= ".time()." + AND (ms.`mail_last_date` >= ".time()." OR ms.`mail_last_date`=0) + ORDER BY ms.`mail_e107_priority` DESC {$count}"; +// echo $query.'
'; + $result = $this->db->db_Select_gen($query); + if ($result !== FALSE) + { + $this->queryActive = $result; // Note number of emails to go + } + return $result; + } + + + /** + * Get next email from selection + * @return Returns array of email data if available - FALSE if no further data, no active query, or other error + */ + public function getNextEmail() + { + if (!$this->queryActive) + { + return FALSE; + } + if ($result = $this->db->db_Fetch(MYSQL_ASSOC)) + { + $this->queryActive--; + return $result; + } + else + { + $this->queryActive = FALSE; // Make sure no further attempts to read emails + return FALSE; + } + } + + + /** + * Call to see whether any emails left to try in current selection + * @return Returns number left unread in query - FALSE if no active query + */ + public function emailsToGo() + { + return $this->queryActive; // Just return saved number + } + + + /** + * Call to send next email from selection + * + * @return Returns TRUE if successful, FALSE on fail (or no more to go) + */ + public function sendNextEmail() + { + $counterList = array('mail_source_id','mail_togo_count', 'mail_sent_count', 'mail_fail_count', 'mail_start_send'); + + if (($email = $this->getNextEmail()) === FALSE) + { + return FALSE; + } + + if (count($this->currentBatchInfo)) + { + //print_a($this->currentBatchInfo); + if ($this->currentBatchInfo['mail_source_id'] != $email['mail_source_id']) + { // New email body etc started + //echo "New email body: {$this->currentBatchInfo['mail_source_id']} != {$email['mail_source_id']}
"; + $this->currentBatchInfo = array(); // New source email - clear stored info + } + } + if (count($this->currentBatchInfo) == 0) + { + //echo "First email of batch: {$email['mail_source_id']}
"; + foreach ($counterList as $k) + { + $this->currentBatchInfo[$k] = $email[$k]; // This copies across all the counts + } + } + + if (($this->currentBatchInfo['mail_sent_count'] > 0) || ($this->currentBatchInfo['mail_fail_count'] > 0)) + { // Only send these on first email - otherwise someone could get inundated! + unset($email['mail_copy_to']); + unset($email['mail_bcopy_to']); + } + + $targetData = array(); // Arrays for updated data + + $this->checkMailer(); // Make sure we have a mailer object to play with + + if ($this->currentBatchInfo['mail_start_send'] == 0) + { + $this->currentBatchInfo['mail_start_send'] = time(); // Log when we started processing this email + } + + if (!$this->currentMailBody) + { + $this->currentMailBody = $this->makeEmailBody($email['mail_body'], $email['mail_send_style']); + } + // Do any substitutions + $search = array(); + $replace = array(); + foreach ($email['mail_target_info'] as $k => $v) + { + $search[] = '|'.$k.'|'; + $replace[] = $v; + } + $email['mail_body'] = str_replace($search, $replace, $this->currentMailBody); + $email['send_html'] = $email['mail_send_style'] != 'textonly'; + + // Set up any extra mailer parameters that need it + if (!vartrue($email['e107_header'])) + { + $email['e107_header'] = intval(mail_source_id).'/'.intval(mail_target_id).'/'.md5($email['mail_recipient_email']); // Set up an ID + } + + // Try and send + $result = FALSE; // Will be result of send + $result = $this->mailer->sendEmail($email['mail_recipient_email'], $email['mail_recipient_name'], $email, TRUE); + + $this->checkDB(2); // Make sure DB object created + + // Now update email status in DB. We just create new arrays of changed data + if ($result === TRUE) + { // Success! + $targetData['mail_status'] = MAIL_STATUS_SENT; + $targetData['mail_send_date'] = time(); + $this->currentBatchInfo['mail_togo_count']--; + $this->currentBatchInfo['mail_sent_count']++; + } + else + { // Failure + // If fail and still retries, downgrade priority + if ($targetData['mail_status'] > MAIL_STATUS_PENDING) + { + $targetData['mail_status'] = max($targetData['mail_status'] - 1, MAIL_STATUS_PENDING); // One off retry count + $targetData['mail_e107_priority'] = max($email['mail_e107_priority'] - 1, 1); // Downgrade priority to avoid clag-ups + } + else + { + $targetData['mail_status'] = MAIL_STATUS_FAILED; + $this->currentBatchInfo['mail_togo_count'] = max($this->currentBatchInfo['mail_togo_count'] - 1, 0); + $this->currentBatchInfo['mail_fail_count']++; + $targetData['mail_send_date'] = time(); + } + } + + if (isset($this->currentBatchInfo['mail_togo_count']) && ($this->currentBatchInfo['mail_togo_count'] == 0)) + { + $this->currentBatchInfo['mail_end_send'] = time(); + $this->currentBatchInfo['mail_content_status'] = MAIL_STATUS_SENT; + } + + // Update DB record, mail record with status (if changed). Must use different sql object + if (count($targetData)) + { + //print_a($targetData); + $this->db2->db_Update('mail_recipients', array('data' => $targetData, + '_FIELD_TYPES' => $this->dbTypes['mail_recipients'], + 'WHERE' => '`mail_target_id` = '.intval($email['mail_target_id']))); + } + if (count($this->currentBatchInfo)) + { + //print_a($this->currentBatchInfo); + $this->db2->db_Update('mail_content', array('data' => $this->currentBatchInfo, + '_FIELD_TYPES' => $this->dbTypes['mail_content'], + 'WHERE' => '`mail_source_id` = '.intval($email['mail_source_id']))); + } + + return $result; + } + + + + /** + * Call to do a number of 'units' of email processing - from a cron job, for example + * Each 'unit' sends one email from the queue - potentially it could do some other task. + * @param $limit - numbe rof units of work to do - zero to clear the queue (or do maximum allowed by a hard-coded limit) + * @return None + */ + public function doEmailTask($limit = 0) + { + if ($count = $this->selectEmails($limit)) + { + while ($count > 0) + { + $this->sendNextEmail(); + $count--; + } + if ($this->mailer) + { + $this->mailer->allSent(); // Tidy up on completion + } + } + } + + + + /** + * Saves an email to the DB + * @param $emailData + * @param $isNew - TRUE if a new email, FALSE if editing + * + * + * @return mail ID for success, FALSE on error + */ + public function saveEmail($emailData, $isNew = FALSE) + { + $this->checkDB(2); // Make sure we have a DB object to use + + $dbData = $this->mailToDB($emailData, FALSE); // Convert array formats +// print_a($dbData); +// return TRUE; + if ($isNew) + { + unset($dbData['mail_source_id']); // Just in case - there are circumstances where might be set + $result = $this->db2->db_Insert('mail_content', array('data' => $dbData, + '_FIELD_TYPES' => $this->dbTypes['mail_content'], + '_NOTNULL' => $this->dbNull['mail_content'])); + } + else + { + if (isset($dbData['mail_source_id'])) + { + $result = $this->db2->db_Update('mail_content', array('data' => $dbData, + '_FIELD_TYPES' => $this->dbTypes['mail_content'], + 'WHERE' => '`mail_source_id` = '.intval($dbData['mail_source_id']))); + if ($result !== FALSE) { $result = $dbData['mail_source_id']; } + } + else + { + echo "Programming bungle! No mail_source_id in function saveEmail()
"; + $result = FALSE; + } + } + return $result; + } + + + /** + * Retrieve an email from the DB + * @param $mailID - number for email (assumed to be integral) + * @param $addMissing - if TRUE, any unset fields are added + * + * @return FALSE on error. Array of data on success. + */ + public function retrieveEmail($mailID, $addMissing = FALSE) + { + if (!is_numeric($mailID) || ($mailID == 0)) + { + return FALSE; + } + $this->checkDB(2); // Make sure we have a DB object to use + if ($this->db2->db_Select('mail_content', '*', '`mail_source_id`='.$mailID) === FALSE) + { + return FALSE; + } + $mailData = $this->db2->db_Fetch(MYSQL_ASSOC); + return $this->dbToMail($mailData, $addMissing); // Convert to 'flat array' format + } + + + /** + * Delete an email from the DB, including (potential) recipients + * @param $mailID - number for email (assumed to be integral) + * @param $actions - allows selection of whic DB to delete from + * + * @return FALSE on code error. Array of results on success. + */ + public function deleteEmail($mailID, $actions='all') + { + $result = array(); + if ($actions == 'all') $actions = 'content,recipients'; + $actArray = explode(',', $actions); + if (!is_numeric($mailID) || ($mailID == 0)) + { + return FALSE; + } + + $this->checkDB(2); // Make sure we have a DB object to use + if (isset($actArray['content'])) + { + $result['content'] = $this->db2->db_Delete('mail_content', '`mail_source_id`='.$mailID); + } + if (isset($actArray['recipients'])) + { + $result['recipients'] = $this->db2->db_Delete('mail_recipients', '`mail_detail_id`='.$mailID); + } + return $result; + } + + + + /** + * Initialise a set of counters prior to adding + * @param $handle - as returned by makeEmail() + * @return none + */ + public function mailInitCounters($handle) + { + $this->mailCounters[$handle] = array('add' => 0, 'dups' => 0, 'dberr' => 0); + } + + + + /** + * Add a recipient to the DB, provide that email not already on the list. + * @param $handle - as returned by makeEmail() + * @param $mailRecip is an array of relevant info + * @param $priority - 'E107' priority for email (different to the priority included in the email) + * @return mixed - FALSE if error + * 'dup' if duplicate of existing email + * integer - number of email recipient in DB + */ + public function mailAddNoDup($handle, $mailRecip, $initStatus = MAIL_STATUS_TEMP, $priority = E107_EMAIL_PRIORITY_LOW) + { + if (($handle <= 0) || !is_numeric($handle)) return FALSE; + if (!isset($this->mailCounters[$handle])) return 'nocounter'; + $this->checkDB(1); // Make sure DB object created + $result = $this->db->db_Select('mail_recipients', 'mail_target_id', "`mail_detail_id`={$handle} AND `mail_recipient_email`='{$mailRecip['mail_recipient_email']}'"); + if ($result === FALSE) + { + return FALSE; + } + elseif ($result != 0) + { + $this->mailCounters[$handle]['dups']++; + return 'dup'; + } + $mailRecip['mail_status'] = $initStatus; + $mailRecip['mail_detail_id'] = $handle; + $mailRecip['mail_send_date'] = time(); + $data = $this->targetToDb($mailRecip); // Convert internal types + if ($this->db->db_Insert('mail_recipients', array('data' => $data, '_FIELD_TYPES' => $this->dbTypes['mail_recipients']))) + { + $this->mailCounters[$handle]['add']++; + } + else + { + $this->mailCounters[$handle]['dberr']++; + return FALSE; + } + } + + + /** + * Update the mail record with the number of recipients as per counters + * @param $handle - as returned by makeEmail() + * @return mixed - FALSE if error + * - number set into counter if success + */ + public function mailUpdateCounters($handle) + { + if (($handle <= 0) || !is_numeric($handle)) return FALSE; + if (!isset($this->mailCounters[$handle])) return 'nocounter'; + $this->checkDB(2); // Make sure DB object created + $query = '`mail_togo_count`='.intval($this->mailCounters[$handle]['add']).' WHERE `mail_source_id`='.$handle; + if ($this->db2->db_Update('mail_content', $query)) + { + return $this->mailCounters[$handle]['add']; + } + return FALSE; + } + + + + /** + * Retrieve the counters for a mail record + * @param $handle - as returned by makeEmail() + * @return boolean - FALSE if error + * - array of counters if success + */ + public function mailRetrieveCounters($handle) + { + if (isset($this->mailCounters[$handle])) + { + return $this->mailCounters[$handle]; + } + return FALSE; + } + + + + /** + * Update status for email, including all recipient entries (called once all recipients added) + * @var int $handle - as returned by makeEmail() + * @var $hold boolean - TRUE to set status to held, false to release for sending + * @var $firstTime int - only valid if $hold === FALSE - earliest time/date when email may be sent + * @var $lastTime int - only valid if $hold === FALSE - latest time/date when email may be sent + * @return boolean TRUE on no errors, FALSE on errors + */ + public function activateEmail($handle, $hold = FALSE, $firstTime = 0, $lastTime = 0) + { + if (($handle <= 0) || !is_numeric($handle)) return FALSE; + $this->checkDB(1); // Make sure DB object created + $ft = ''; + $lt = ''; + if (!$hold) + { // Sending email - set sensible first and last times + if ($lastTime < time() + 3600) // Force at least an hour to send emails + { + if ($firstTime < time()) + { + $lastTime = time() + 86400; // Standard delay - 24 hours + } + else + { + $lastTime = $firstTime + 86400; + } + } + if ($firstTime > 0) $ft = ', `mail_send_date` = '.$firstTime; + $lt = ', `mail_end_send` = '.$lastTime; + } + $query = '`mail_content_status` = '.($hold ? MAIL_STATUS_HELD : MAIL_STATUS_PENDING).$lt.' WHERE `mail_source_id` = '.intval($handle); +// echo "Update mail body: {$query}
"; + // Set status of email body first + if (!$this->db->db_Update('mail_content',$query)) + { + return FALSE; + } + // Now set status of individual emails + $query = '`mail_status` = '.($hold ? MAIL_STATUS_HELD : (MAIL_STATUS_PENDING + e107MailManager::E107_EMAIL_MAX_TRIES)).$ft.' WHERE `mail_detail_id` = '.intval($handle); +// echo "Update individual emails: {$query}
"; + if (FALSE === $this->db->db_Update('mail_recipients',$query)) + { + return FALSE; + } + return TRUE; + } + + + /** + * Cancel sending of an email, including marking all unsent recipient entries + * $handle - as returned by makeEmail() + * @return boolean - TRUE on success, FALSE on failure + */ + public function cancelEmail($handle) + { + if (($handle <= 0) || !is_numeric($handle)) return FALSE; + $this->checkDB(1); // Make sure DB object created + // Set status of email body first - in this context, 'SENT' really means 'COMPLETED' + if (!$this->db->db_Update('mail_content','`mail_content_status` = '.MAIL_STATUS_SENT.' WHERE `mail_source_id` = '.intval($handle))) + { + return FALSE; + } + // Now set status of individual emails + if (FALSE === $this->db->db_Update('mail_recipients','`mail_status` = '.MAIL_STATUS_CANCELLED.' WHERE `mail_detail_id` = '.intval($handle).' AND `mail_status` >'.MAIL_STATUS_FAILED)) + { + return FALSE; + } + return TRUE; + } + + + /** + * Does a query to select one or more emails for which status is required. + * @var $start - sets the offset of the first email to return based on the search criteria + * @var $count - sets the maximum number of emails to return + * @var $fields - allows selection of which db fields are returned in each result + * @var $filters - array contains filter/selection criteria - basically setting limits on each field + * @return Returns number of records found (maximum $count); FALSE on error + */ + public function selectEmailStatus($start = 0, $count = 0, $fields = '*', $filters = FALSE, $orderField = 'mail_source_id', $sortOrder = 'asc') + { + $this->checkDB(1); // Make sure DB object created + if (!is_array($filters) && $filters) + { // Assume a textual email type + switch ($filters) + { + case 'pending' : + $filters = array('`mail_content_status` = '.MAIL_STATUS_PENDING); + break; + case 'held' : + $filters = array('`mail_content_status` = '.MAIL_STATUS_HELD); + break; + case 'pendingheld' : + $filters = array('((`mail_content_status` = '.MAIL_STATUS_PENDING.') OR (`mail_content_status` = '.MAIL_STATUS_HELD.'))'); + break; + case 'sent' : + $filters = array('`mail_content_status` = '.MAIL_STATUS_SENT); + break; + case 'failed' : + $filters = array('`mail_content_status` = '.MAIL_STATUS_FAILED); + break; + case 'saved' : + $filters = array('`mail_content_status` = '.MAIL_STATUS_SAVED); + break; + } + } + if (!is_array($filters)) + { + $filters = array(); + } + $query = "SELECT SQL_CALC_FOUND_ROWS {$fields} FROM `#mail_content`"; + if (count($filters)) + { + $query .= ' WHERE '.implode (' AND ', $filters); + } + if ($orderField) + { + $query .= " ORDER BY `{$orderField}`"; + } + if ($sortOrder) + { + $sortOrder = strtoupper($sortOrder); + $query .= ($sortOrder == 'DESC') ? ' DESC' : ' ASC'; + } + if ($count) + { + $query .= " LIMIT {$start}, {$count}"; + } +// echo "{$start}, {$count} Mail query: {$query}
"; + $result = $this->db->db_Select_gen($query); + if ($result !== FALSE) + { + $this->queryCount[1] = $this->db->total_results; // Save number of records found + } + else + { + $this->queryCount[1] = 0; + } + return $result; + } + + + /** + * Returns the total number of records matching the search done in the most recent call to selectEmailStatus() + * @return integer - number of emails matching criteria + */ + public function getEmailCount() + { + return $this->queryCount[1]; + } + + + + /** + * Returns the detail of the next email which satisfies the query done in selectEmailStatus() + * @return Returns an array of data relating to a single email if available (in 'flat' format). FALSE on no data or error + */ + public function getNextEmailStatus() + { + $result = $this->db->db_Fetch(); + if (is_array($result)) { return $this->dbToMail($result); } + return FALSE; + } + + + + /** + * Does a query to select from the list of email targets which have been used + * @var $start - sets the offset of the first email to return based on the search criteria + * @var $count - sets the maximum number of emails to return + * @var $fields - allows selection of which db fields are returned in each result + * @var $filters - array contains filter/selection criteria + * 'handle=nn' picks out a specific email + * @return Returns number of records found; FALSE on error + */ + public function selectTargetStatus($handle, $start = 0, $count = 0, $fields = '*', $filters = FALSE, $orderField = 'mail_target_id', $sortOrder = 'asc') + { + $handle = intval($handle); + if ($filters === FALSE) { $filters = array(); } // Might not need this line + + $this->checkDB(2); // Make sure DB object created + + // TODO: Implement filters if needed + $query = "SELECT SQL_CALC_FOUND_ROWS {$fields} FROM `#mail_recipients` WHERE `mail_detail_id`={$handle}"; + if ($orderField) + { + $query .= " ORDER BY `{$orderField}`"; + } + if ($sortOrder) + { + $sortOrder = strtoupper($sortOrder); + $query .= ($sortOrder == 'DESC') ? ' DESC' : ' ASC'; + } + if ($count) + { + $query .= " LIMIT {$start}, {$count}"; + } +// echo "{$start}, {$count} Target query: {$query}
"; + $result = $this->db2->db_Select_gen($query); + if ($result !== FALSE) + { + $this->queryCount[2] = $this->db2->total_results; // Save number of records found + } + else + { + $this->queryCount[2] = 0; + } +// echo "Result: {$result}. Total: {$this->queryCount[2]}
"; + return $result; + } + + + /** + * Returns the total number of records matching the search done in the most recent call to selectTargetStatus() + * @return integer - number of emails matching criteria + */ + public function getTargetCount() + { + return $this->queryCount[2]; + } + + + + /** + * Returns the detail of the next recipient which satisfies the query done in selectTargetStatus() + * @return Returns an array of data relating to a single email if available (in 'flat' format). FALSE on no data or error + */ + public function getNextTargetStatus() + { + $result = $this->db2->db_Fetch(MYSQL_ASSOC); + if (is_array($result)) { return $this->dbToTarget($result); } + return FALSE; + } + + + + /** + * Creates email body text according to options + * @param $text string - text to process + * @param $format string - options: + * textonly - generate plain text email + * texthtml - HTML format email, no theme info + * texttheme - HTML format email, including current theme stylesheet etc + * @return string - updated body + */ + protected function makeEmailBody($text, $format = 'textonly') + { + global $pref; + if ($format == 'textonly') + { // Plain text email - strip bbcodes etc + return str_replace($search,$replace,stripslashes($this->e107->tp->toText($this->message_body, STRIP))); + } + + // HTML format email here + $mail_head = "\n"; + $mail_head .= "\n"; + $mail_head .= "\n"; + if ($format == 'texttheme') + { + $styleFile = THEME.'emailstyle.css'; + if (!is_readable($styleFile)) { $styleFile = e_THEME.$pref['sitetheme']."/style.css"; } + $style_css = file_get_contents($styleFile); + $mail_head .= ""; + } + $mail_head .= "\n"; + + + $message_body = $mail_head."\n"; + if ($format == 'texttheme') + { + $message_body .= "
\n"; + $message_body .= $tp -> toEmail($text)."
"; + } + else + { + $message_body .= $tp -> toEmail($text).""; + $message_body = str_replace(""", '"', $message_body); + $message_body = str_replace('src="', 'src="'.SITEURL, $message_body); + $message_body = str_replace("src='", "src='".SITEURL, $message_body); + } + + return stripslashes($message_body); + } + + + + +/// TODO: Below here can probably be removed in due course + + // Called to do the setup for the mail run - gets an email body, stores it in this instance. Returns TRUE on success, FALSE on error + function setupMailRun($mail_id, $mail_text_id) + { + global $sql, $tp; + + if (($mail_id == 0) || ($mail_text_id == 0)) return FALSE; + + // Get the email itself from the 'generic' table + $qry = "SELECT * FROM #generic WHERE `gen_id` = {$mail_text_id} AND gen_type='savemail' and gen_datestamp = '".$mail_id."' "; + if (!$sql -> db_Select_gen($qry)) + { +// echo "Can't access email in DB
"; + return FALSE; + } + + if (!$row = $sql->db_Fetch()) + { +// echo "Can't read email
"; + return FALSE; + } + $email_info = unserialize($row['gen_chardata']); // Gives us sender_name, sender_email, email_body + + + if (varsettrue($email_info['sender_email'])) $this->From = $email_info['sender_email']; + if (varsettrue($email_info['sender_name'])) $this->FromName = $email_info['sender_name']; + + $message_subject = stripslashes($tp -> toHTML($email_info['email_subject'],FALSE,RAWTEXT)); + $this->SMTPDebug = (e_MENU == "debug") ? TRUE : FALSE; + + if($email_info['copy_to']) + { + $tmp = explode(",",$email_info['copy_to']); + foreach($tmp as $addc) + { + $this->AddCC(trim($addc)); + } + } + + if($email_info['bcopy_to']) + { + $tmp = explode(",",$email_info['bcopy_to']); + foreach($tmp as $addc) + { + $this->AddBCC(trim($addc)); + } + } + + + $attach = trim($email_info['attach']); + + if(is_readable(e_DOWNLOAD.$attach)) + { + $attach_link = e_DOWNLOAD.$attach; + } + else + { + $attach_link = e_FILE.'public/'.$attach; + } + + if (($temp = strrchr($attach,'/')) !== FALSE) + { // Just specify filename as attachment - no path + $attach = substr($temp,1); + } + + if ($attach != "" && !$this->AddAttachment($attach_link, $attach)) + { + echo "Problem with attachment: {$attach_link}->{$attach}
"; // problem with attachment. + return FALSE; + } + + $email_info['use_theme'] = varset($email_info['use_theme'],FALSE); + + $this->makeEmailBody($email_info['email_body'],$email_info['use_theme']); // Create and save email body + return TRUE; + } // end - function setupMailRun() + + + + + + + + // Sends a single bulk email, assuming everything else is already set up. + // Passed the data row from the DB (by reference, to save memory) + function sendBulkEmail(&$row) + { + $mail_info = unserialize($row['gen_chardata']); // Has most of the info needed + + $activator = (substr(SITEURL, -1) == "/" ? SITEURL."signup.php?activate.".$row['gen_user_id'].".".$mail_info['user_signup'] : SITEURL."/signup.php?activate.".$row['gen_user_id'].".".$mail_info['user_signup']); + $signup_link = ($mail_info['user_signup']) ? "{$activator}" : ""; + + // Allow username in subject + $mail_subject = str_replace(array('|USERNAME|','{USERNAME}'),$mail_info['user_name'],$message_subject); + $mail_handler->Subject = $mail_subject; + + + // Allow username, userID, signup link in body + $search = array('|USERNAME|','|LOGINNAME|','|USERID|','|SIGNUP_LINK|'); + $replace = array($mail_info['user_name'],$mail_info['login_name'],$row['gen_user_id'],$signup_link); + + // Handle any substitution - build the arrays + $search = array(); + $replace = array(); + foreach ($mail_info['mail_target_info'] as $s => $v) + { + $search[] = '|'.$s.'|'; + $replace[] = $v; + } + if (count($search)) + { + $mes_body = str_replace($search,$replace,$this->message_body); + // $alt_body = str_replace($search,$replace,stripslashes($tp->toText($email_info['email_body'], STRIP))); + $alt_body = str_replace($search,$replace,stripslashes($tp->toText($this->message_body, STRIP))); // Is this right? + } + + $mail_handler->Body = $mes_body; + $mail_handler->AltBody = $alt_body; + + $mail_handler->AddAddress($mail_info['user_email'], $mail_info['user_name']); + if ($row['gen_user_id']) + { + $mail_custom = $row['gen_user_id']; + } + else + { + $mail_custom = md5($mail_info['user_name'].$mail_info['user_email']); + } + $mail_custom = "X-e107-id: ".$mail_id.'/'.$mail_custom; // Will become xx-yy-md5(time) where 'xx' is recipient record ID, 'yy' is mail ID + $mail_handler->AddCustomHeader($mail_custom); + + + $debug_message = ''; + if (($logenable == 0) || ($logenable == 2)) + { // Actually send email + $mail_result = $mail->Send(); + } + else + { // Debug mode - decide result of email here + $mail_result = TRUE; + if (($logenable == 3) && (($c % 7) == 4)) $mail_result = FALSE; // Fail one email in 7 for testing + $debug_message = 'Debug'; + } + if ($mail_result) + { + $send_ok++; + $sql2->db_Delete('generic',"gen_id={$row['gen_id']}"); // Mail sent - delete from database + } + else + { + $send_fail++; + $mail_info['send_result'] = 'Fail: '.$mail->ErrorInfo.$debug_message; + $temp = serialize($mail_info); + // Log any error info we can + $sql2->db_Update('generic',"`gen_chardata`='{$temp}' WHERE gen_id={$row['gen_id']}"); + } + + if ($logenable) + { + fwrite($loghandle,date("H:i:s d.m.y")." Send to {$mail_info['user_name']} at {$mail_info['user_email']} Mail-ID={$mail_custom} - {$mail_result}\r\n"); + } + + $mail->ClearAddresses(); + $mail->ClearCustomHeaders(); + + +// --------- One email sent + + $cur = round((($c / $count) * 100) + $unit); + + if($pause_count > $pause_amount) + { + sleep($pause_time); + $pause_count = 1; + } + + // Default sleep to reduce server-load: 1 second. + sleep(1); + + $c++; + $pause_count++; + } + + +} + +?> \ No newline at end of file diff --git a/e107_handlers/mailout_admin_class.php b/e107_handlers/mailout_admin_class.php new file mode 100644 index 000000000..ce9be8dc9 --- /dev/null +++ b/e107_handlers/mailout_admin_class.php @@ -0,0 +1,1351 @@ + array + ( 'mail_target_id' => array('title' => LAN_MAILOUT_143, 'thclass' => 'center', 'forced' => TRUE), + 'mail_recipient_id' => array('title' => LAN_MAILOUT_142, 'thclass' => 'center'), + 'mail_recipient_name' => array('title' => LAN_MAILOUT_141, 'forced' => TRUE), + 'mail_recipient_email' => array('title' => LAN_MAILOUT_140, 'thclass' => 'left', 'forced' => TRUE), + 'mail_status' => array('title' => LAN_MAILOUT_138, 'thclass' => 'center', 'proc' => 'contentstatus'), + 'mail_detail_id' => array('title' => LAN_MAILOUT_137), + 'mail_send_date' => array('title' => LAN_MAILOUT_139, 'proc' => 'sdatetime'), + 'mail_target_info' => array('title' => LAN_MAILOUT_148, 'proc' => 'array'), + 'options' => array('title' => LAN_OPTIONS, 'forced' => TRUE) + ), + 'mail_content' => array( + 'mail_source_id' => array('title' => LAN_MAILOUT_137, 'thclass' => 'center', 'forced' => TRUE), + 'mail_title' => array('title' => LAN_MAILOUT_135, 'forced' => TRUE), + 'mail_subject' => array('title' => LAN_MAILOUT_06, 'forced' => TRUE), + 'mail_content_status' => array('title' => LAN_MAILOUT_136, 'thclass' => 'center', 'proc' => 'contentstatus'), + 'mail_togo_count' => array('title' => LAN_MAILOUT_83), + 'mail_sent_count' => array('title' => LAN_MAILOUT_82), + 'mail_fail_count' => array('title' => LAN_MAILOUT_128), + 'mail_bounce_count' => array('title' => LAN_MAILOUT_144), + 'mail_start_send' => array('title' => LAN_MAILOUT_131, 'proc' => 'sdatetime'), + 'mail_end_send' => array('title' => LAN_MAILOUT_132, 'proc' => 'sdatetime'), + 'mail_create_date' => array('title' => LAN_MAILOUT_130, 'proc' => 'sdatetime'), + 'mail_creator' => array('title' => LAN_MAILOUT_85, 'proc' => 'username'), + 'mail_create_app' => array('title' => LAN_MAILOUT_133), + 'mail_e107_priority' => array('title' => LAN_MAILOUT_134), + 'mail_last_date' => array('title' => LAN_MAILOUT_129, 'proc' => 'sdatetime'), + 'mail_body' => array('title' => LAN_MAILOUT_100, 'proc' => 'trunc200'), + // 'mail_other' = array('title' => LAN_MAILOUT_84), + 'mail_sender_email' => array('title' => LAN_MAILOUT_149), + 'mail_sender_name' => array('title' => LAN_MAILOUT_150), + 'mail_copy_to' => array('title' => LAN_MAILOUT_151), + 'mail_bcopy_to' => array('title' => LAN_MAILOUT_152), + 'mail_attach' => array('title' => LAN_MAILOUT_153), + 'mail_send_style' => array('title' => LAN_MAILOUT_154), + 'mail_selectors' => array('title' => LAN_MAILOUT_155, 'proc' => 'selectors', 'nolist' => 'TRUE'), + 'options' => array('title' => LAN_OPTIONS, 'forced' => TRUE) + ) + ); + + // List of fields to be hidden for each action ('nolist' attribute true) + protected $hideFields = array( + 'orphans' => array(), + 'saved' => 'mail_content_status,mail_togo_count,mail_sent_count,mail_fail_count,mail_bounce_count,mail_start_send,mail_end_send,mail_e107_priority,mail_last_date,mail_selectors', + 'sent' => 'mail_togo_count,mail_last_date,mail_selectors', +// 'pending' => 'mail_togo_count,mail_sent_count,mail_fail_count,mail_bounce_count,mail_start_send,mail_end_send,mail_e107_priority,mail_last_date,mail_selectors', + 'pending' => 'mail_start_send,mail_end_send,mail_e107_priority,mail_last_date,mail_selectors', + 'held' => 'mail_sent_count,mail_fail_count,mail_bounce_count,mail_start_send,mail_end_send,mail_e107_priority,mail_last_date,mail_selectors', + 'resend' => 'mail_Selectors', + 'recipients' => 'mail_detail_id' + ); + + // Array of info associated with each task we might do + protected $tasks = array( + 'makemail' => array('title' => LAN_MAILOUT_190, 'defaultSort' => '', 'defaultTable' => ''), + 'saved' => array('title' => LAN_MAILOUT_191, 'defaultSort' => 'mail_source_id', 'defaultTable' => 'mail_content'), + 'marksend' => array('title' => 'Internal: marksend', 'defaultSort' => 'mail_source_id', 'defaultTable' => 'mail_content'), + 'sent' => array('title' => LAN_MAILOUT_192, 'defaultSort' => 'mail_source_id', 'defaultTable' => 'mail_content'), + 'pending' => array('title' => LAN_MAILOUT_193, 'defaultSort' => 'mail_source_id', 'defaultTable' => 'mail_content'), + 'held' => array('title' => LAN_MAILOUT_194, 'defaultSort' => 'mail_source_id', 'defaultTable' => 'mail_content'), + 'recipients' => array('title' => LAN_MAILOUT_173, 'defaultSort' => 'mail_recipient_email', 'defaultTable' => 'mail_recipients'), + 'mailtargets' => array('title' => LAN_MAILOUT_173, 'defaultSort' => 'mail_recipient_email', 'defaultTable' => 'mail_recipients'), + 'prefs' => array('title' => ADLAN_40, 'defaultSort' => '', 'defaultTable' => ''), + 'maint' => array('title' => ADLAN_40, 'defaultSort' => '', 'defaultTable' => '') + ); + + + // Options for mail listing dropdown + protected $modeOptions = array( + 'saved' => array( + 'mailedit' => LAN_MAILOUT_163, + 'maildelete' => LAN_DELETE + ), + 'pending' => array( +// 'mailsendnow' => LAN_MAILOUT_158, + 'mailhold' => LAN_MAILOUT_159, + 'mailcancel' => LAN_MAILOUT_160, + 'mailtargets' => LAN_MAILOUT_181 + ), + 'held' => array( + 'mailsendnow' => LAN_MAILOUT_158, + 'mailcancel' => LAN_MAILOUT_160, + 'mailtargets' => LAN_MAILOUT_181 + ), + 'sent' => array( + 'mailsendnow' => LAN_EDIT, + 'maildelete' => LAN_DELETE, + 'mailtargets' => LAN_MAILOUT_181 + ), + 'recipients' => array( + 'mailonedelete' => LAN_DELETE + ) + ); + + + // List of fields to be included in email display for various options + protected $mailDetailDisplay = array( + 'basic' => array('mail_source_id' => 1, 'mail_title' => 1, 'mail_subject' => 1, 'mail_body' => 200), + 'send' => array('mail_source_id' => 1, 'mail_title' => 1, 'mail_subject' => 1, 'mail_body' => 500) + ); + + + /** + * Constructor + * + * + * @return void + */ + public function __construct($mode = '') + { + parent::__construct(); +// $saveMode = $mode; + $dbTable = ''; + if (isset($this->tasks[$mode])) + { + $dbTable = $this->tasks[$mode]['defaultTable']; + } + if(isset($_GET['frm'])) + { + $temp = intval($_GET['frm']); + if ($temp < 0) $temp = 0; + $this->showFrom = $temp; + } + if(isset($_GET['count'])) + { + $temp = min(intval($_GET['count']), 50); // Limit to 50 per page + $temp = max($temp, 5); // ...and minimum 5 per page + $this->showCount = $temp; + } + if (isset($_GET['fld'])) + { + $temp = $this->e107->tp->toDB($_GET['fld']); + if (is_array($this->fields[$dbTable][$temp])) + { + $this->sortField = $temp; + } + } + if (isset($_GET['asc'])) + { + $temp = strtolower($this->e107->tp->toDB($_GET['asc'])); + if (($temp == 'asc') || ($temp == 'desc')) + { + $this->sortOrder = $temp; + } + } + $this->newMode($mode); + } + + + + /** + * Set up new mode + * + * @param $mode - display mode + * @return none + */ + public function newMode($mode = '') + { + global $user_pref; + $this->mode = $mode; + $curTable = $this->tasks[$this->mode]['defaultTable']; + if (is_array($user_pref['admin_mailout_columns'][$mode])) + { // Use saved list of fields to view if it exists + $this->fieldPref = $user_pref['admin_mailout_columns'][$mode]; + } + else + { // Default list is minimal fields only + $this->fieldPref = array(); + foreach ($this->fields[$curTable] as $f => $v) + { + if (vartrue($v['forced'])) + { + $this->fieldPref[] = $f; + } + } + } + + // Possibly the sort field needs changing + if (!isset($this->fields[$curTable][$this->sortField])) + { + $this->sortField = $this->tasks[$mode]['defaultSort']; + } + + // Now hide any fields that need to be for this mode + if (isset($this->hideFields[$mode])) + { + $hideList = array_flip(explode(',',$this->hideFields[$mode])); + foreach ($this->fields[$curTable] as $f => $v) + { + $this->fields[$curTable][$f]['nolist'] = isset($hideList[$f]); + } + foreach ($this->fieldPref as $k => $v) // Remove from list of active fields (shouldn't often do anything) + { + if (isset($hideList[$v])) + { + unset($this->fieldPref[$k]); + } + } + } + } + + + + protected function calcFieldSpec($mode, $noOptions = FALSE) + { + if (!isset($this->tasks[$mode])) + { + echo "CalcfieldSpec({$mode}) - programming bungle
"; + return FALSE; + } + $ret = array(); + $curTable = $this->tasks[$this->mode]['defaultTable']; + foreach ($this->fields[$curTable] as $f => $v) + { + if ((vartrue($v['forced']) && !vartrue($v['nolist'])) || in_array($f, $this->fieldPref)) + { + if (($f != 'options') || ($noOptions === FALSE)) + { + $ret[] = $f; + } + } + } + return $ret; + } + + + /** + * Save the column visibility prefs for this mode + * + * @param $target - display mode + * @return none + */ + public function mailbodySaveColumnPref($target) + { + global $user_pref; + if (!$target) return; + if (!isset($this->tasks[$target])) + { + echo "Invalid prefs target: {$target}
"; + return; + } + if (isset ($_POST['etrigger_ecolumns'])) + { + $user_pref['admin_mailout_columns'][$target] = $_POST['e-columns']; + save_prefs('user'); + $this->fieldPref = $user_pref['admin_mailout_columns'][$target]; + } + } + + + protected function getUserName($uid) + { + if (!isset($this->userCache[$uid])) + { + // Look up user + $this->checkDB(2); // Make sure DB object created + if ($this->db2->db_Select('user','user_name, user_loginname', 'user_id='.intval($uid))) + { + $row = $this->db2->db_Fetch(MYSQL_ASSOC); + $this->userCache[$uid] = $row['user_name'].' ('.$row['user_loginname'].')'; + } + else + { + $this->userCache[$uid] = 'UID: '.$uid; + } + } + return $this->userCache[$uid]; + } + + + /** + * Convert numeric represntation of mail status to a text string + * + * @param integer $status - numeric value of status + * @return string text value + */ + public function statusToText($status) + { + switch (intval($status)) + { + case MAIL_STATUS_SENT : + return LAN_MAILOUT_211; + case MAIL_STATUS_BOUNCED : + return LAN_MAILOUT_213; + case MAIL_STATUS_CANCELLED : + return LAN_MAILOUT_218; + case MAIL_STATUS_FAILED : + return LAN_MAILOUT_212; + case MAIL_STATUS_PENDING : + return LAN_MAILOUT_214; + case MAIL_STATUS_SAVED : + return LAN_MAILOUT_215; + case MAIL_STATUS_HELD : + return LAN_MAILOUT_217; + default : + if (($status > MAIL_STATUS_PENDING) && ($status <= MAIL_STATUS_ACTIVE)) return LAN_MAILOUT_214; + } + return LAN_MAILOUT_216.' ('.$status.')'; // General coding error + } + + + + /** + * Generate the HTML for displaying actions box for emails + * + * Options given depend on $mode, and also values in the email data. + * + * @param $mailData - array of email-related info + * @return HTML for display + */ + public function makeMailOptions($mode,$mailData) + { + if (!is_numeric($mailData['mail_source_id']) || ($mailData['mail_source_id'] == 0)) + { + echo "makeMailOptions ({$mode}): Programming bungle!"; + print_a($mailData); + return 'Error'; + } + $text .= "\n"; + return $text; + } + + + /** + * Generate the HTML for displaying actions box for emails + * + * Options given depend on $mode, and also values in the email data. + * + * @param $mailData - array of email-related info + * @return HTML for display + */ + public function makeTargetOptions($mode,$targetData) + { + if (!is_numeric($targetData['mail_target_id']) || ($targetData['mail_target_id'] == 0)) + { + echo "makeTargetOptions ({$mode}): Programming bungle!"; + print_a($targetData); + return 'Error'; + } + $text .= "\n"; + return $text; + } + + + /** + * Generate the HTML for displaying email selection fields + * + * @param $options - comma-separate string of handlers to load + * 'core' - core handler + * plugin name - obvious! + * 'all' - obvious! + * @return Number of handlers loaded + */ + public function loadMailHandlers($options = 'all') + { + global $pref; + + + + $ret = 0; + $toLoad = explode(',', $options); + if (in_array('core', $toLoad) || ($options == 'all')) + { + require_once(e_HANDLER.'mailout_class.php'); + $this->mailHandlers[] = new mailout_core($this); // Start by loading the core mailout class + $ret++; + } + + $active_mailers = explode(',',varset($pref['mailout_enabled'],'')); + + // Load additional configured handlers + foreach ($pref['e_mailout_list'] as $mailer => $v) + { + if (isset($pref['plug_installed'][$mailer]) && in_array($mailer,$active_mailers) && (($options == 'all') || in_array('core', $toLoad))) + { // Could potentially use this handler - its installed and enabled + if (!is_readable(e_PLUGIN.$mailer.'/e_mailout.php')) + { + echo 'Invalid mailer selected: '.$mailer.'
'; + exit; + } + require_once(e_PLUGIN.$mailer.'/e_mailout.php'); + if (varset($mailerIncludeWithDefault,TRUE)) + { // Definitely need this plugin + $mailClass = 'mailout_'.$mailer; + $temp = new $mailClass; + if ($temp->mailerEnabled) + { + $this->mailHandlers[] = &$temp; + $ret++; + if (varset($mailerExcludeDefault,FALSE) && isset($this->mailHandlers[0]) && ($this->mailHandlers[0]->mailerSource == 'core')) + { + $this->mailHandlers[0]->mailerEnabled = FALSE; // Don't need default (core) handler + $ret--; + } + } + else + { + unset($temp); + } + } + } + } + + return $ret; + } + + + /** + * Generate the HTML for displaying email selection fields + * + * @param $options - comma-separate string of areas to display: + * plugins - selectors from any available plugins + * cc - field for 'cc' options + * bcc - field for 'bcc' options + * src=plugname - selector from the specified plugin + * 'all' - all available fields + * @return text for display + */ + public function emailSelector($options = 'all', $selectorInfo = FALSE) + { + $ret = ''; + foreach ($this->mailHandlers as $m) + { + if ($m->mailerEnabled) + { + $ret .= "".$m->mailerName."".$m->showSelect(TRUE, varset($selectorInfo[$m->mailerSource], FALSE)).""; + } + } + return $ret; + } + + + /** + * Get the selector details from each mail plugin (to add to mail data) + * + * @return array of selectors - key is the plugin name, value is the selector data (often itself an array) + */ + public function getAllSelectors() + { + $ret = array(); + foreach ($this->mailHandlers as $m) + { + if ($m->mailerEnabled) + { + $ret[$m->mailerSource] = $m->returnSelectors(); + } + } + return $ret; + } + + + // Generate list of userclasses, including the number of members in each class. + // Returns a userclass selection dropdown + public function userClassesTotals($name, $curSel) + { + $fixedClasses = array('all' => LAN_MAILOUT_12,'unverified' => LAN_MAILOUT_13, 'admin' => LAN_MAILOUT_53, 'self' => LAN_MAILOUT_54); + + $ret = ''; + $this->checkDB(2); // Make sure DB object created + $ret .= "\n"; + + return $ret; + } + + + + // Return a list of extended user fields + // TODO: Exclude system fields, and maybe others. + public function ret_extended_field_list($list_name, $curval = '', $add_blank = FALSE) + { + $this->checkDB(2); // Make sure DB object created + $ret = "\n"; + return $ret; + } + + + /** + * Creates an array of data from standard $_POST fields + * + * @param $newMail - set TRUE for initial creation, FALSE when updating + * @return array of data + */ + public function parseEmailPost($newMail = TRUE) + { + $ret = array( 'mail_title' => $this->e107->tp->toDB($_POST['email_title']), + 'mail_subject' => $this->e107->tp->toDB($_POST['email_subject']), + 'mail_body' => $this->e107->tp->toDB($_POST['email_body']), + 'mail_sender_email' => $this->e107->tp->toDB($_POST['email_from_email']), + 'mail_sender_name' => $this->e107->tp->toDB($_POST['email_from_name']), + 'mail_copy_to' => $this->e107->tp->toDB($_POST['email_cc']), + 'mail_bcopy_to' => $this->e107->tp->toDB($_POST['email_bcc']), + 'mail_attach' => $this->e107->tp->toDB(trim($_POST['email_attachment'])), + 'mail_send_style' => $this->e107->tp->toDB(varset($_POST['send_style'],'textonly')) + ); + if (isset($_POST['mail_source_id'])) + { + $ret['mail_source_id'] = intval($_POST['mail_source_id']); + } + if ($newMail) + { + $ret['mail_creator'] = USERID; + $ret['mail_create_date'] = time(); + } + return $ret; + } + + + + /** + * Does some basic checking on email data. + * + * @param $email - array of data in parseEmailPost() format + * @param $fulLCheck - TRUE to check all fields that are required (immediately prior to sending); FALSE to just check a few basics (prior to save) + * @return TRUE if OK. Array of error messages if any errors found + */ + public function checkEmailPost($email, $fullCheck = FALSE) + { + $errList = array(); + if (count($email) < 3) + { + $errList[] = LAN_MAILOUT_201; + return $errList; + } + if (!trim($email['mail_subject'])) $errList[] = LAN_MAILOUT_200; + if (!trim($email['mail_body'])) $errList[] = LAN_MAILOUT_202; + if (!trim($email['mail_sender_name'])) $errList[] = LAN_MAILOUT_203; + if (!trim($email['mail_sender_email'])) $errList[] = LAN_MAILOUT_204; + switch ($email['mail_send_style']) + { + case 'textonly' : + case 'texthtml' : + case 'texttheme' : + break; + default : + $errList[] = LAN_MAILOUT_205; + } + if (count($errList) == 0) + { + return TRUE; + } + return $errList; + } + + + + /** + * Generate a table which shows some information about an email. + * Intended to be part of a 2-column table - includes the row detail, but not the surrounding table definitions + * + * @param $mailSource - array of mail information + * @param $options - controls how much information is displayed + * @return text for display + */ + public function showMailDetail(&$mailSource, $options='basic') + { + if (!isset($this->mailDetailDisplay[$options])) + { + return "Programming bungle - invalid option value: {$options}"; + } + + $res = ''; + foreach ($this->mailDetailDisplay[$options] as $k => $v) + { + $res .= ''.$this->fields['mail_content'][$k]['title'].''; + $res .= ($v > 1) ? $this->e107->tp->text_truncate($mailSource[$k], $v, '...') : $mailSource[$k]; + $res .= ''."\n"; + } + return $res; + } + + + + /** + * Generate the HTML for dropdown to select mail sending style (text/HTML/styled + * + * @param $curval - current value + * @param $name name of item + * @return text for display + */ + public function sendStyleSelect($curval = '', $name = 'send_style') + { + + $emFormat = array( + 'textonly' => LAN_MAILOUT_125, + 'texthtml' => LAN_MAILOUT_126, + 'texttheme' => LAN_MAILOUT_127 + ); + + $text = "\n"; + return $text; + } + + + /** + * Generate the HTML to show the mailout form. Used for both sending and editing + * + * @param $mailSource - array of mail information + * @return text for display + */ + function show_mailform(&$mailSource) + { + global $pref,$HANDLERS_DIRECTORY; + global $mailAdmin; + + if (!is_array($mailSource)) + { + $this->e107->ns->tablerender('ERROR!!', 'Coding error - mail not array (521)'); + exit; + } + + $email_subject = varset($mailSource['mail_subject'], ''); + $email_body = $this->e107->tp->toForm(varset($mailSource['mail_body'],'')); + $email_id = varset($mailSource['mail_source_id'],''); + $text = ''; + + if(strpos($_SERVER['SERVER_SOFTWARE'],'mod_gzip') && !is_readable(e_HANDLER.'phpmailer/.htaccess')) + { + $warning = LAN_MAILOUT_40.' '.$HANDLERS_DIRECTORY.'phpmailer/ '.LAN_MAILOUT_41; + $this->e107->ns->tablerender(LAN_MAILOUT_42, $warning); + } + + $debug = (e_MENU == "debug") ? "?[debug]" : ""; + $text .= "
+
+ + + + + + + + + + + + + + "; + + + $text .=" + + + + "; + + + // Add in the core and any plugin selectors here + $text .= $this->emailSelector('all', varset($mailSource['mail_selectors'], FALSE)); + + + + // CC, BCC + $text .= " + + + + + + + + + "; + + + + // Close one table, open another - to give a boundary between addressees and content + $text .= "
".LAN_MAILOUT_111.": + +
".LAN_MAILOUT_01.": + +
".LAN_MAILOUT_02.": + +
".LAN_MAILOUT_04.": + +
".LAN_MAILOUT_05.": + +
+ + + + + "; + + // Subject + $text .= " + + + + "; + + + // Attachment. + if ($this->e107->isInstalled('download')) + { + // TODO - use download plugin API + $text .= " + + + "; + } + + + $text .= " + + + \n + + + "; + + $text .=" + + + +
".LAN_MAILOUT_51.": + +
".LAN_MAILOUT_07.": "; + $text .= ""; + + $text .= "
".LAN_MAILOUT_09.": \n"; + + $text .= $this->sendStyleSelect($mailSource['mail_send_style']); + $text .=" +
+ +
+
"; + + global $eplug_bb; + + $eplug_bb[] = array( + 'name' => 'shortcode', + 'onclick' => 'expandit', + 'onclick_var' => 'sc_selector', + 'icon' => e_IMAGE.'generic/bbcode/shortcode.png', + 'helptext' => LAN_MAILOUT_11, + 'function' => array($this,'sc_Select'), + 'function_var' => 'sc_selector' + ); + + $text .= display_help('helpb','mailout'); + + if(e_WYSIWYG) + { + $text .=" + + + "; + } + + $text .=" +
"; + + + $text .= "
"; + if($email_id) + { + $text .= ""; + $text .= ""; + } + else + { + $text .= ""; + } + + $text .="  + +
+ +
+
"; + + $this->e107->ns->tablerender(LAN_MAILOUT_15, $text); // Render the complete form + } + + + // Helper function manages the shortcodes which can be inserted + function sc_Select($container='sc_selector') + { + $text =" + \n + + \n + "; + + return $text; + } + + + + + /** + * Return dropdown for arithmetic comparisons + * + * @param $name string name of select structure + * @param $curval string current value + * @return text for display + */ + public function comparisonSelect($name, $curval = '') + { + $compVals = array(' ' => ' ', '<' => LAN_MAILOUT_175, '=' => LAN_MAILOUT_176, '>' => LAN_MAILOUT_177); + $ret = "\n"; + return $ret; + } + + + /** + * Show a screen to confirm deletion of an email + * + * @param $mailid - number of email + * @param $nextPage - 'mode' specification for page to return to following delete + * @return text for display + */ + public function showDeleteConfirm($mailID, $nextPage = 'saved') + { + $mailData = $this->retrieveEmail($mailID); + + $text = "
"; + + if ($mailData === FALSE) + { + $text = "
".LAN_MAILOUT_79."
"; + $this->e107->ns-> tablerender("
".LAN_MAILOUT_171."
", $text); + exit; + } + + $text .= " +
+
+ + + + + + + "; + + $text .= $this->showMailDetail($mailData, 'basic'); + $text .= '"; + if ($mailData['mail_content_status'] != MAIL_STATUS_SAVED) + { + $text .= ''; + } + + $text .= "
'.LAN_MAILOUT_172.''.$this->statusToText($mailData['mail_content_status'])."
'.LAN_MAILOUT_173.''.($mailData['mail_togo_count'] + $mailData['mail_sent_count'] + $mailData['mail_fail_count']).'
\n
"; + + $text .= "
+ +   +
"; + + $text .= "
"; + $this->e107->ns->tablerender("
".ADLAN_136." :: ".LAN_MAILOUT_171."
", $text); + } + + + + /** + * Generate the HTML to show a list of emails of a particular type, in tabular form + * + * @param $type - type of email to display + * @param $from - offset into table of candidates + * @param $amount - number to return + * @return text for display + */ + public function showEmailList($type, $from = 0, $amount = 10) + { + // Need to select main email entries; count number of addresses attached to each + $gen = new convert; + $frm = e107::getForm(); + + if ($from < 0) { $from = $this->showFrom; } + if ($amount < 0) { $amount = $this->showCount; } + // in $_GET, so = sort order, sf = sort field + $count = $this->selectEmailStatus($from, $amount, '*', $type, $this->sortField, $this->sortOrder); + $totalCount = $this->getEmailCount(); + + $emails_found = array(); // Log ID and count for later + + $text = "
"; + + if (!$count) + { + $text = "
".LAN_MAILOUT_79."
"; + $this->e107->ns-> tablerender("
".$this->tasks[$type]['title']."
", $text); + require_once(e_ADMIN."footer.php"); + exit; + } + + $text .= " +
+
+ "; + + $fieldPrefs = $this->calcFieldSpec($type, TRUE); // Get columns to display + + // Must use '&' rather than '&' in query pattern + $text .= $frm->colGroup($this->fields['mail_content'],$this->fieldPref).$frm->thead($this->fields['mail_content'],$this->fieldPref,'mode='.$type."&fld=[FIELD]&asc=[ASC]&frm=[FROM]").""; + + while ($row = $this->getNextEmailStatus(FALSE)) + { +// print_a($row); + $text .= ''; + foreach ($fieldPrefs as $fieldName) + { // Output column data value + $text .= ''; + } + // Add in options here + $text .= ''; + $text .= ''; + } + $text .= "
'; + if (isset($row[$fieldName])) + { + $proctype = varset($this->fields['mail_content'][$fieldName]['proc'], 'default'); + switch ($proctype) + { + case 'username' : + $text .= $this->getUserName($row[$fieldName]); + break; + case 'sdatetime' : + $text .= $gen->convert_date($row[$fieldName], 'short'); + break; + case 'trunc200' : + $text .= $this->e107->tp->text_truncate($row[$fieldName], 200, '...'); + break; + case 'contentstatus' : + $text .= $this->statusToText($row[$fieldName]); + break; + case 'selectors' : + $text .= 'cannot display'; + break; + case 'default' : + default : + $text .= $row[$fieldName]; + } + } + else + { // Special stuff + } + $text .= ''.$this->makeMailOptions($type,$row).'


\n"; + + if ($totalCount > $count) + { + $parms = "{$totalCount},{$amount},{$from},".e_SELF."?mode={$type}&count={$amount}&frm=[FROM]&fld={$this->sortField}&asc={$this->sortOrder}"; + $text .= $this->e107->tp->parseTemplate("{NEXTPREV={$parms}}"); + } + + $text .= '

'; + $this->e107->ns->tablerender("
".ADLAN_136." :: ".$this->tasks[$type]['title']."
", $text); + } + + + + + /** + * Generate a list of emails to send + * Returns various information to display in a confirmation screen + * + * The email and its recipients are stored in the DB with a tag of 'MAIL_STATUS-TEMP' + * + * @param $mailData array Details of the email, selection criteria etc + * @return text for display + */ + public function sendEmailCircular($mailData) + { + // Start by saving the email + $mailData['mail_content_status'] = MAIL_STATUS_TEMP; + $mailData['mail_create_app'] = 'core'; + $result = $this->saveEmail($mailData, TRUE); + if (is_numeric($result)) + { + $mailMainID = $mailData['mail_source_id'] = $result; + } + else + { + // TODO: Handle error + } + + + $this->mailInitCounters($mailMainID); // Initialise counters for emails added + + foreach ($this->mailHandlers as $m) + { // Get email addresses from each handler in turn. Do them one at a time, so that all can use the $sql data object + if ($m->mailerEnabled && isset($mailData['mail_selectors'][$m->mailerSource])) + { + // Initialise + $mailerCount = $m->selectInit($mailData['mail_selectors'][$m->mailerSource]); + if ($mailerCount > 0) + { + // Get email addresses - add to list, strip duplicates + while ($row = $m->selectAdd()) + { // Add email addresses to the database ready for sending (the body is never saved in the DB - it gets passed as a $_POST value) + $result = $this->mailAddNoDup($mailMainID, $row, MAIL_STATUS_TEMP); + if ($result === FALSE) + { + // Error + } + } + } + $m->select_close(); // Close + // Update the stats after each handler + $this->mailUpdateCounters($mailMainID); + } + } + + $counters = $this->mailRetrieveCounters($mailMainID); +// $this->e107->admin_log->log_event('MAIL_02','ID: '.$mailMainID.' '.$counters['add'].'[!br!]'.$_POST['email_from_name']." <".$_POST['email_from_email'],E_LOG_INFORMATIVE,''); + + + +// We've got all the email addresses here - display a confirmation form +// Include start/end dates for send + $text = "
"; + + $text .= " +
+
+ + + + + + + "; + + $text .= $this->showMailDetail($mailData, 'send'); + + + // Add in core and any plugin selectors here + foreach ($mail_handlers as $m) + { + if ($m->mailer_enabled) + { + $text .= ''; + } + } + + // Figures - number of emails to send, number of duplicates stripped + $text .= '"; + $text .= ''; + + $text .= ""; + $text .= "
'.LAN_MAILOUT_180.'
'.$m->mailer_name.'
'.$m->show_select(FALSE).'
'.LAN_MAILOUT_173.''.($mailData['mail_togo_count'])."
'.LAN_MAILOUT_71.' '.$counters['add'].' '.LAN_MAILOUT_69.$counters['dups'].LAN_MAILOUT_70.'
Add in start/end dates here
\n
"; + + $text .= "
+ +   +   +
"; + + $this->e107->ns->tablerender("
".ADLAN_136." :: ".LAN_MAILOUT_179."
", $text); + +// $text .= "
"; + + } // End of previewed email + + + + + + /** + * Show recipients of an email + * + * @param $mailid - number of email + * @param $nextPage - 'mode' specification for page to return to following delete + * @return text for display + */ + public function showmailRecipients($mailID, $nextPage = 'saved') + { + $gen = new convert; + $frm = e107::getForm(); + + $mailData = $this->retrieveEmail($mailID); + + $text = "
"; + + if ($mailData === FALSE) + { + $text = "
".LAN_MAILOUT_79."
"; + $this->e107->ns-> tablerender("
".LAN_MAILOUT_171."
", $text); + exit; + } + + $text .= " + +
+ + + + + + + "; + + $text .= $this->showMailDetail($mailData, 'basic'); + $text .= '"; + if ($mailData['mail_content_status'] != MAIL_STATUS_SAVED) + { + $text .= ''; + } + + $text .= "
'.LAN_MAILOUT_172.''.$this->statusToText($mailData['mail_content_status'])."
'.LAN_MAILOUT_173.''.($mailData['mail_togo_count'] + $mailData['mail_sent_count'] + $mailData['mail_fail_count']).'
\n
"; + + +// List of recipients + // in $_GET, asc = sort order, fld = sort field + $count = $this->selectTargetStatus($mailID, $this->showFrom, $this->showCount, '*', FALSE, $this->sortField, $this->sortOrder); + $totalCount = $this->getTargetCount(); + + $text .= " +
+
+ "; + + + $fieldPrefs = $this->calcFieldSpec('recipients', TRUE); // Get columns to display + + // Must use '&' rather than '&' in query pattern + $text .= $frm->colGroup($this->fields['mail_recipients'],$this->fieldPref).$frm->thead($this->fields['mail_recipients'],$this->fieldPref,'mode='.'recipients&m='.$mailID."&fld=[FIELD]&asc=[ASC]&frm=[FROM]").""; + + while ($row = $this->getNextTargetStatus(FALSE)) + { +// print_a($row); + $text .= ''; + foreach ($fieldPrefs as $fieldName) + { // Output column data value + $text .= ''; + } + // Add in options here + $text .= ''; + $text .= ''; + } + + $text .= "
'; + if (isset($row[$fieldName])) + { + $proctype = varset($this->fields['mail_recipients'][$fieldName]['proc'], 'default'); + switch ($proctype) + { + case 'username' : + $text .= $this->getUserName($row[$fieldName]); + break; + case 'sdatetime' : + $text .= $gen->convert_date($row[$fieldName], 'short'); + break; + case 'trunc200' : + $text .= $this->e107->tp->text_truncate($row[$fieldName], 200, '...'); + break; + case 'contentstatus' : + $text .= $this->statusToText($row[$fieldName]); + break; + case 'selectors' : + $text .= 'cannot display'; + break; + case 'array' : + if (is_array($row[$fieldName])) + { + $nl = ''; + foreach ($row[$fieldName] as $k => $v) + { + if ($v) + { + $text .= $nl.$k.' => '.$v; + $nl = '
'; + } + } + } + else + { + $text .= 'bad data: '; + } + break; + case 'default' : + default : + $text .= $row[$fieldName]; + } + } + else + { // Special stuff + $text .= 'special'; + } + $text .= '
'.$this->makeTargetOptions('recipients',$row).'
\n


"; + + if ($totalCount > $count) + { + $parms = "{$totalCount},{$this->showCount},{$this->showFrom},".e_SELF."?mode=recipients&m={$mailID}&count={$this->showCount}&frm=[FROM]&fld={$this->sortField}&asc={$this->sortOrder}&savepage={$nextPage}"; + $text .= $this->e107->tp->parseTemplate("{NEXTPREV={$parms}}"); + } + + $text .= "
"; + + $this->e107->ns->tablerender("
".ADLAN_136." :: ".LAN_MAILOUT_181."
", $text); + } + + + public function dbTidy() + { + $this->checkDB(2); // Make sure DB object created + if ($this->db2->db_Delete('mail_content', '`mail_content_status` = '.MAIL_STATUS_TEMP) === FALSE) + { + return FALSE; + } + if ($this->db2->db_Delete('mail_recipients', '`mail_status` = '.MAIL_STATUS_TEMP) === FALSE) + { + return FALSE; + } + return TRUE; + } +} + + +?> diff --git a/e107_handlers/mailout_class.php b/e107_handlers/mailout_class.php index 2b75c6eb7..41c37fc28 100644 --- a/e107_handlers/mailout_class.php +++ b/e107_handlers/mailout_class.php @@ -1,248 +1,372 @@ sql object for database access - it will effectively have exclusive use of this during the email address search phase It is the responsibility of each class to manager permission restrictions where required. +TODO: + 1. accept varying date formats for last visit + 2. Use XHTML calendar for last visit + 3. Sort classes for table cells + */ // These variables determine the circumstances under which this class is loaded (only used during loading, and may be overwritten later) - $mailer_include_with_default = TRUE; // Mandatory - if false, show only when mailout for this specific plugin is enabled - $mailer_exclude_default = TRUE; // Mandatory - if TRUE, when this plugin's mailout is active, the default isn't loaded + $mailerIncludeWithDefault = TRUE; // Mandatory - if false, show only when mailout for this specific plugin is enabled + $mailerExcludeDefault = TRUE; // Mandatory - if TRUE, when this plugin's mailout is active, the default (core) isn't loaded -class core_mailout +class mailout_core { - var $mail_count = 0; - var $mail_read = 0; - var $mailer_name = LAN_MAILOUT_68; // Text to identify the source of selector (displayed on left of admin page) - var $mailer_enabled = TRUE; // Mandatory - set to FALSE to disable this plugin (e.g. due to permissions restrictions) + protected $mailCount = 0; + protected $mailRead = 0; + protected $e107; + public $mailerSource = 'core'; // Plugin name (core mailer is special case) Must be directory for this file + public $mailerName = LAN_MAILOUT_68; // Text to identify the source of selector (displayed on left of admin page) + public $mailerEnabled = TRUE; // Mandatory - set to FALSE to disable this plugin (e.g. due to permissions restrictions) + protected $adminHandler = NULL; // Filled in with the name of the admin handler on creation - // Constructor - function core_mailout() - { - } - - // Data selection routines - - // Initialise data selection - save any queries or other information into internal variables, do initial DB queries as appropriate. - // Return number of records available (or 1 if unknown) on success, FALSE on failure - // Could in principle read all addresses and buffer them for later routines, if this is more convenient - function select_init() - { - global $sql; // We can use this OK + // List of fields used by selectors + private $selectFields = array('email_to', + 'extended_1_name','extended_1_value', + 'extended_2_name', 'extended_2_value', + 'user_search_name', 'user_search_value', + 'last_visit_match', 'last_visit_date' + ); - switch ($_POST['email_to']) + // Constructor + public function __construct(&$mailerAdminHandler = NULL) { - // Build the query for the user database - case "all" : - case "admin" : - switch ($_POST['email_to']) + $this->e107 = e107::getInstance(); + if ($mailerAdminHandler == NULL) { - case "admin": - $insert = "u.user_admin='1' "; - break; - case "all": - $insert = "u.user_ban='0' "; - break; + global $mailAdmin; + $mailerAdminHandler = $mailAdmin; } - $qry = ", ue.* FROM #user AS u LEFT JOIN #user_extended AS ue ON ue.user_extended_id = u.user_id WHERE {$insert} "; - break; - - case "unverified" : - $qry = " FROM #user AS u WHERE u.user_ban='2'"; - break; - - case "self" : - $qry = " FROM #user AS u WHERE u.user_id='".USERID."'"; - break; - - default : - $insert = "u.user_class REGEXP concat('(^|,)',{$_POST['email_to']},'(,|$)') AND u.user_ban='0' "; - $qry = ", ue.* FROM #user AS u LEFT JOIN #user_extended AS ue ON ue.user_extended_id = u.user_id WHERE {$insert} "; + $this->adminHandler = $mailerAdminHandler; } - - - // Determine which fields we actually need (u.user_sess is the signup link) - $qry = "SELECT u.user_id, u.user_name, u.user_email, u.user_sess".$qry; - - if($_POST['extended_1_name'] && $_POST['extended_1_value']) - { - $qry .= " AND ".$_POST['extended_1_name']." = '".$_POST['extended_1_value']."' "; - } - - if($_POST['extended_2_name'] && $_POST['extended_2_value']) - { - $qry .= " AND ".$_POST['extended_2_name']." = '".$_POST['extended_2_value']."' "; - } - - if($_POST['user_search_name'] && $_POST['user_search_value']) - { - $qry .= " AND u.".$_POST['user_search_name']." LIKE '%".$_POST['user_search_value']."%' "; - } - - $qry .= " ORDER BY u.user_name"; - if (!( $this->mail_count = $sql->db_Select_gen($qry))) return FALSE; - $this->mail_read = 0; - return $this->mail_count; - } - - - // Return an email address to add. Return FALSE if no more addresses to add - // Returns an array with appropriate elements defined: - // 'user_id' - non-zero if a registered user, zero if a non-registered user. (Always non-zero from this class) - // 'user_name' - user name - // 'user_email' - email address to use - // 'user_signup' - signup link (zero if not applicable) - function select_add() - { - global $sql; - if (!($row = $sql->db_Fetch())) return FALSE; - $ret = array('user_id' => $row['user_id'], - 'user_name' => $row['user_name'], - 'user_email' => $row['user_email'], - 'user_signup' => $row['user_sess'] - ); - $this->mail_read++; -// echo "Return value: ".$row['user_name']."
"; - return $ret; - } - - - // Called once all email addresses read, to do any housekeeping needed - function select_close() - { - // Nothing to do here - } - // Called to show current selection criteria, and optionally allow edit - // Returns HTML which is displayed in a table cell. Typically we return a complete table - // $allow_edit is TRUE to allow user to change the selection; FALSE to just display current settings - - //TODO - remove HTML markup from this class! (see below) + /** + * Return data representing the user's selection criteria as entered in the $_POST array. + * + * This is stored in the DB with a saved email. (Just return an empty string or array if this is undesirable) + * The returned value is passed back to selectInit() and showSelect when needed. + * + * @return Selection data - may be string, array or whatever suits + */ + public function returnSelectors() + { + $res = array(); + foreach ($this->selectFields as $k) + { + if (varsettrue($_POST[$k])) + { + $res[$k] = $this->e107->tp->toDB($_POST[$k]); + } + } + return $res; + } + + + /** + * Called to initialise data selection routine. + * Needs to save any queries or other information into internal variables, do initial DB queries as appropriate. + * Could in principle read all addresses and buffer them for later routines, if this is more convenient + * + * @param $selectVals - array of selection criteria as returned by returnSelectors() + * + * @return Return number of records available (or 1 if unknown) on success, FALSE on failure + */ + public function selectInit($selectVals = FALSE) + { + $where = array(); + $incExtended = array(); + if ($selectVals === FALSE) + { + $selectVals = array('email_to' => 'all'); + } + switch (varset($selectVals['email_to'], 'all')) + { + // Build the query for the user database + case 'all' : + $where[] = 'u.`user_ban`=0'; + break; + case 'admin' : + $where[] = 'u.`user_admin`=1'; + break; + case 'unverified' : + $where[] = 'u.`user_ban`=2'; + break; + case 'self' : + $where[] = 'u.`user_id`='.USERID; + break; + default : + if (is_numeric($selectVals['email_to'])) + { + $where[] = "u.`user_class` REGEXP concat('(^|,)',{$selectVals['email_to']},'(,|$)')"; + } + $where[] = "u.`user_ban`=0"; + } + + if (vartrue($selectVals['extended_1_name']) && vartrue($selectVals['extended_1_value'])) + { + $where[] = '`'.$selectVals['extended_1_name']."` = '".$selectVals['extended_1_value']."' "; + $incExtended[] = $selectVals['extended_1_name']; + } + + if (vartrue($selectVals['extended_2_name']) && vartrue($selectVals['extended_2_value'])) + { + $where[] = "ue.`".$selectVals['extended_2_name']."` = '".$selectVals['extended_2_value']."' "; + $incExtended[] = $selectVals['extended_2_name']; + } + + if (vartrue($selectVals['user_search_name']) && vartrue($selectVals['user_search_value'])) + { + $where[]= "u.`".$selectVals['user_search_name']."` LIKE '%".$selectVals['user_search_value']."%' "; + } + + if (vartrue($selectVals['last_visit_match']) && vartrue($selectVals['last_visit_date'])) + { + foreach(array(':', '-', ',') as $sep) + { + if (strpos($selectVals['last_visit_date'], ':')) + { + $tmp = explode($sep, $selectVals['last_visit_date']); + break; + } + } + $lvDate = gmmktime(0, 0, 0, $tmp[1], $tmp[0], $tmp[2]); // Require dd-mm-yy for now + if (($lvDate > 0) && ($lvDate <= time())) + { + switch ($selectVals['last_visit_match']) + { + case '<' : + case '>' : + $where[]= "u.`user_lastvisit`".$selectVals['last_visit_match'].$lvDate; + break; + case '=' : + $where[]= "u.`user_lastvisit`>=".$lvDate; + $where[]= "u.`user_lastvisit`<=".intval($lvDate + 86400); + break; + } + } + } + $where[] = "u.`user_email` != ''"; // Ignore all records with empty email address + + // Now assemble the query from the pieces + // Determine which fields we actually need (u.user_sess is the signup link) + $qry = 'SELECT u.user_id, u.user_name, u.user_email, u.user_loginname, u.user_sess, u.user_lastvisit'; + if (count($incExtended)) + { + foreach ($incExtended as $if) + { + $qry .= ', ue.`'.$if.'`'; + } + } + $qry .= " FROM `#user` AS u "; + if (count($incExtended)) + { + $qry .= "LEFT JOIN `#user_extended` AS ue ON ue.`user_extended_id` = u.`user_id`"; + } + + $qry .= ' WHERE '.implode(' AND ',$where).' ORDER BY u.user_name'; +// echo "Selector query: ".$qry.'
'; + if (!( $this->mail_count = $this->e107->sql->db_Select_gen($qry))) return FALSE; + $this->mail_read = 0; + return $this->mail_count; + } + + + + /** + * Return an email address to add to the recipients list. Return FALSE if no more addresses to add + * + * @return FALSE if no more addresses available; else an array: + * 'mail_recipient_id' - non-zero if a registered user, zero if a non-registered user. (Always non-zero from this class) + * 'mail_recipient_name' - user name + * 'mail_recipient_email' - email address to use + * 'mail_target_info' - array of info which might be substituted into email, usually using the codes defined by the editor. + * Array key is the code within '|...|', value is the string for substitution + */ + public function selectAdd() + { + if (!($row = $this->e107->sql->db_Fetch(MYSQL_ASSOC))) return FALSE; + $ret = array('mail_recipient_id' => $row['user_id'], + 'mail_recipient_name' => $row['user_name'], // Should this use realname? + 'mail_recipient_email' => $row['user_email'], + 'mail_target_info' => array( + 'USERID' => $row['user_id'], + 'DISPLAYNAME' => $row['user_name'], + 'SIGNUP_LINK' => $row['user_sess'], + 'USERNAME' => $row['user_loginname'], + 'USERLASTVISIT' => $row['user_lastvisit'] + ) + ); + $this->mail_read++; + return $ret; + } + + + // Called once all email addresses read, to do any housekeeping needed + public function select_close() + { + // Nothing to do here + } - function show_select($allow_edit = FALSE) - { - global $sql; - $ret = ""; - if ($allow_edit) - { - // User class select - $ret .= " - - - "; - - // User Search Field. - $u_array = array("user_name"=>LAN_MAILOUT_43,"user_login"=>LAN_MAILOUT_44,"user_email"=>LAN_MAILOUT_45); - $ret .= " - - - - "; - - - - // Extended user fields - $ret .= " - - - - - "; - } - else - { - if(is_numeric($_POST['email_to'])) + // Called to show current selection criteria, and optionally allow edit + // + // + /** + * Called to show current selection criteria, and optionally allow edit + * + * @param $allow_edit is TRUE to allow user to change the selection; FALSE to just display current settings + * @param $selectVals is the current selection information - in the same format as returned by returnSelectors() + * + * @return Returns HTML which is displayed in a table cell. Typically we return a complete table + */ + public function showSelect($allow_edit = FALSE, $selectVals = FALSE) { - $sql->db_Select("userclass_classes", "userclass_name", "userclass_id = '{$_POST['email_to']}'"); - $row = $sql->db_Fetch(); - $_to = LAN_MAILOUT_23.$row['userclass_name']; - } - else - { - $_to = $_POST['email_to']; - } - $ret .= " - -
".LAN_MAILOUT_03.": - ".userclasses("email_to", $_POST['email_to'])."
".LAN_MAILOUT_46." - ".LAN_MAILOUT_47." - -
".LAN_MAILOUT_46.ret_extended_field_list('extended_1_name', TRUE).LAN_MAILOUT_48." - -
".LAN_MAILOUT_46.ret_extended_field_list('extended_2_name', TRUE).LAN_MAILOUT_48." - -
".LAN_MAILOUT_03."".$_to." "; - if($_POST['email_to'] == "self"){ + $ret = ""; + + if ($allow_edit) + { + // User class select + $ret .= " + + + "; + + // User Search Field. + $u_array = array('user_name'=>LAN_MAILOUT_43,'user_login'=>LAN_MAILOUT_44,'user_email'=>LAN_MAILOUT_45); + $ret .= " + + + + "; + + // User last visit + $ret .= " + + "; + + + // Extended user fields + $ret .= " + + + + + "; + } + else + { // Display existing values + if(is_numeric($selectVals['email_to'])) + { + $this->e107->sql->db_Select('userclass_classes', 'userclass_name', "userclass_id = ".intval($selectVals['email_to'])); + $row = $this->e107->sql->db_Fetch(); + $_to = LAN_MAILOUT_23.$row['userclass_name']; + } + else + { + $_to = $selectVals['email_to']; + } + $ret .= " + + "; + $ret .= ""; - if ($_POST['user_search_name'] && $_POST['user_search_value']) - { - $ret .= " - - - - "; - } + if (vartrue($selectVals['user_search_name']) && vartrue($selectVals['user_search_value'])) + { + $ret .= " + + + + "; + } - if ($_POST['extended_1_name'] && $_POST['extended_1_value']) - { - $ret .= " - - - - "; - } - if ($_POST['extended_2_name'] && $_POST['extended_2_value']) - { - $ret .= " - - - - "; - } + if (vartrue($selectVals['last_visit_match']) && vartrue($selectVals['last_visit_date'])) + { + $ret .= " + + + + "; + } + + if (vartrue($selectVals['extended_1_name']) && vartrue($selectVals['extended_1_value'])) + { + $ret .= " + + + + "; + } + if (vartrue($selectVals['extended_2_name']) && vartrue($selectVals['extended_2_value'])) + { + $ret .= " + + + + "; + } + } + + return $ret.'
".LAN_MAILOUT_03.": + ".$this->adminHandler->userClassesTotals('email_to', varset($selectVals['email_to'], ''))."
".LAN_MAILOUT_46." + ".LAN_MAILOUT_47." + +
".LAN_MAILOUT_56.' '.$this->adminHandler->comparisonSelect('last_visit_match', $selectVals['last_visit_match'])." + +
".LAN_MAILOUT_46.$this->adminHandler->ret_extended_field_list('extended_1_name', varset($selectVals['extended_1_name'], ''), TRUE).LAN_MAILOUT_48." + +
".LAN_MAILOUT_46.$this->adminHandler->ret_extended_field_list('extended_2_name', varset($selectVals['extended_2_name'], ''), TRUE).LAN_MAILOUT_48." + +
".LAN_MAILOUT_03."".$_to." "; + if($selectVals['email_to'] == "self") + { $text .= "<".USEREMAIL.">"; } - $ret .= "
".$_POST['user_search_name']."".$_POST['user_search_value']." 
".$selectVals['user_search_name']."".varset($selectVals['user_search_value'])." 
".$_POST['extended_1_name']."".$_POST['extended_1_value']." 
".$_POST['extended_2_name']."".$_POST['extended_2_value']." 
".LAN_MAILOUT_56."".$selectVals['last_visit_match'].' '.gmstrtotime("%D-%M-%Y",$selectVals['last_visit_date'])." 
".$selectVals['extended_1_name']."".$selectVals['extended_1_value']." 
".$selectVals['extended_2_name']."".$selectVals['extended_2_value']." 
'; } - - - return $ret.'
'; - } } diff --git a/e107_handlers/plugin_class.php b/e107_handlers/plugin_class.php index 1ee13e237..6ecfe6f89 100644 --- a/e107_handlers/plugin_class.php +++ b/e107_handlers/plugin_class.php @@ -1,25 +1,24 @@ tp->toDB(varset($_GET['mode'],'makemail')); switch ($action) { @@ -27,22 +29,31 @@ if (e_QUERY) list($action,$junk) = explode('.',e_QUERY); else $action = 'makemai $text = 'Send mail with constraints specified by an optional plugin'; break; case 'debug' : - $text = 'For devs only. A second query parameter matches the gen_type field in the \'generic\' table. Ignore the column headings'; + $text = 'For devs only. Not used at present'; break; - case 'list' : + case 'saved' : $text = 'Select and use a saved email template to send a mailshot. Delete any template no longer required'; break; - case 'mailouts' : - $text = 'List of stored mailshots. Allows you to see whether they have been sent, and re-send any emails which failed.
'; - $text .= 'You can also view some detail of the email, including the error reason for some of those that failed.
'; - $text .= 'To retry outstanding emails, click on the \'resend\' icon. Then click on \'Proceed\', which will open a progress window.'; - $text .= ' To abort a mailshot, click on the \'Cancel\' button in the main screen.'; + case 'pending' : + $text = 'List of mailshots released for sending, together with current status.'; + break; + case 'held' : + $text = 'List of emails which have been prepared for sending, but not yet released'; + break; + case 'sent' : + $text = 'List of completed mailshots. Allows you to see the sending results.
'; break; case 'savedmail' : case 'makemail' : - $text = 'Create an email, and select the list of recipients. You can save the email text as a template for later, or send immediately.
'; - $text .= 'Any attachment is selected from the list of valid downloads.'; + $text = 'Create an email, give it a meaningful title, and select the list of recipients. You can save everything as a template for later, or send immediately.
'; + $text .= 'Email addresses may be contributed by plugins (such as newsletter), and duplicates are removed when the mail is sent
'; + $text .= 'Any attachment is selected from the list of valid downloads.
'; + $text .= 'Mail may be sent as plain text (most universal, and least at risk of being classed as spam), or as HTML (in which case a plain text alternative is automatically generated). The theme style + may optionally be added to the email'; break; + case 'recipients' : + $text = 'Shows all recipients or potential recipients of an email, together with current status'; + break; case 'prefs' : $text = 'Configure mailshot options.
A test email is sent using the current method and settings.

'; @@ -54,13 +65,16 @@ if (e_QUERY) list($action,$junk) = explode('.',e_QUERY); else $action = 'makemai $text .= 'Email Address Sources
If you have additional mail-related plugins, you can select which of them may contribute email addresses to the list.

'; $text .= 'Logging
- The logging option creates a text file in the stats plugin\'s log directory. This must be deleted periodically. The \'logging + The logging option creates a text file in the system log directory. This must be deleted periodically. The \'logging only\' options allow you to see exactly who would receive emails if actually sent. The \'with errors\' option fails every 7th email, primarily for testing'; break; + case 'maint' : + $text = 'Maintenance functions for the mail database'; + break; default : $text = 'Undocumented option'; } -$ns -> tablerender("Mail Help", $text); +$ns -> tablerender('Mail Help', $text); ?> \ No newline at end of file diff --git a/e107_languages/English/admin/lan_mailout.php b/e107_languages/English/admin/lan_mailout.php index 449de801e..e431288b1 100644 --- a/e107_languages/English/admin/lan_mailout.php +++ b/e107_languages/English/admin/lan_mailout.php @@ -1,13 +1,18 @@ \ No newline at end of file diff --git a/e107_plugins/calendar_menu/languages/English_mailer.php b/e107_plugins/calendar_menu/languages/English_mailer.php new file mode 100644 index 000000000..6d02be18a --- /dev/null +++ b/e107_plugins/calendar_menu/languages/English_mailer.php @@ -0,0 +1,23 @@ +