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_notify_complete' => array('title' => LAN_MAILOUT_243, 'nolist' => 'TRUE'), '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'), 'mail_include_images' => array('title' => LAN_MAILOUT_224, 'proc' => 'yesno'), '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_notify_complete,mail_last_date,mail_selectors', 'sent' => 'mail_togo_count,mail_last_date,mail_selectors,mail_notify_complete', // '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_notify_complete,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_notify_complete,mail_last_date,mail_selectors', 'resend' => 'mail_Selectors,mail_notify_complete', '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( 'mailsendimmediately' => "Send Immediately", '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( 'mailcopy' => LAN_MAILOUT_251, '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(); // require_once(e_HANDLER.'calendar/calendar_class.ph_'); // $this->_cal = new DHTML_Calendar(true); $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 ($curTable) { if (isset($user_pref['admin_mailout_columns'][$mode]) && 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]); } } } } /** * Calculate the list of fields (columns) to be displayed for a given mode * * @param string $mode - display mode * @param boolean $noOptions - set TRUE to suppress inclusion of any 'options' column. FALSE to include 'options' (default) * @return array of field definitions */ 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]; } } /** * Get the user name associated with a user ID. * The result is cached in case required again * * @param int $uid - User ID * * @return string with user name and user login name (UID if user not found) */ 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]; } /** * Generate the HTML for displaying actions box for emails * * Options given depend on $mode, and also values in the email data. * * @param array $mailData - array of email-related info * @return string 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['core'] = new core_mailout; // 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($mailer, $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 = $mailer.'_mailout'; $temp = new $mailClass; if ($temp->mailerEnabled) { $this->mailHandlers[$mailer] = $temp; $ret++; if (varset($mailerExcludeDefault,FALSE) && isset($this->mailHandlers['core'])) { $this->mailHandlers['core']->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-separated 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 = ''; $tab = ''; $tabc = ''; $ret .= "
\n"; foreach ($this->mailHandlers as $key => $m) { if ($m->mailerEnabled) { $tab .= "
  • ".$m->mailerName."
  • "; $tabc .= "
    "; $content = $m->showSelect(TRUE, varset($selectorInfo[$key], FALSE)); if(is_array($content)) { $tabc .= " "; foreach($content as $var) { $tabc .= ""; } $tabc .= "
    ".$var['caption']."".$var['html']."
    "; } else { $tabc .= $content; //BC (0.8 only) but should be deprecated } $tabc .= "
    "; } } // $ret .= ""; // This hides tabs! $ret .= ""; $ret .= $tabc; $ret .= "
    "; 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 $key => $m) { if ($m->mailerEnabled) { $ret[$key] = $m->returnSelectors(); } } return $ret; } /** * Creates a 'select' dropdown of userclasses, including the number of members in each class. * * @param string $name - name for \n"; foreach ($fixedClasses as $k => $v) { $sel = ($k == $curSel) ? " selected='selected'" : ''; $ret .= "\n"; } $query = "SELECT uc.*, count(u.user_id) AS members FROM #userclass_classes AS uc LEFT JOIN #user AS u ON u.user_class REGEXP concat('(^|,)',uc.userclass_id,'(,|$)') GROUP BY uc.userclass_id "; $this->db2->db_Select_gen($query); while ($row = $this->db2->db_Fetch()) { $public = ($row['userclass_editclass'] == e_UC_PUBLIC)? "(".LAN_MAILOUT_10.")" : ""; $selected = ($row['userclass_id'] == $curSel) ? " selected='selected'" : ''; $ret .= "\n"; } $ret .= " \n"; return $ret; } /** * Creates a 'select' dropdown of non-system user fields * * @param string $list_name - name for \n"; if ($add_blank) $ret .= "\n"; foreach ($ue->fieldDefinitions as $fd) { if ($fd['user_extended_struct_text'] != '_system_') { $value = 'ue.user_'.$fd['user_extended_struct_name']; $selected = ($value == $curval) ? " selected='selected'" : ''; $ret .= "\n"; } } $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) { $tp = e107::getParser(); $ret = array( 'mail_title' => $_POST['email_title'], 'mail_subject' => $_POST['email_subject'], 'mail_body' => $_POST['email_body'], 'mail_sender_email' => $_POST['email_from_email'], 'mail_sender_name' => $_POST['email_from_name'], 'mail_copy_to' => $_POST['email_cc'], 'mail_bcopy_to' => $_POST['email_bcc'], 'mail_attach' => trim($_POST['email_attachment']), 'mail_send_style' => varset($_POST['send_style'],'textonly'), 'mail_include_images' => (isset($_POST['mail_include_images']) ? 1 : 0) ); $ret = $tp->toDB($ret); // recursive 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') { $tp = e107::getParser(); 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) ? $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 */ //FIXME use $frm->selectbox() instead. 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; $sql = e107::getDb(); $ns = e107::getRender(); $tp = e107::getParser(); $frm = e107::getForm(); $mes = e107::getMessage(); if (!is_array($mailSource)) { $mes = e107::getMessage(); $mes->add('Coding error - mail not array (521)', E_MESSAGE_ERROR); //$ns->tablerender('ERROR!!', ); //exit; } $email_subject = varset($mailSource['mail_subject'], ''); $email_body = $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; $ns->tablerender(LAN_MAILOUT_42, $warning); } $debug = (e_MENU == "debug") ? "?[debug]" : ""; $text .= "
    ".$this->emailSelector('all', varset($mailSource['mail_selectors'], FALSE))." "; // Add in the core and any plugin selectors here /*$text .= " ";*/ $text .= " "; // Attachment. if (e107::isInstalled('download')) { // TODO - use download plugin API if($sql->db_Select("download", "download_url,download_name", "download_id !='' ORDER BY download_name")) { $text .= ""; } } // TODO File-Picker from Media-Manager. $text .= " \n "; $text .="
    ".LAN_MAILOUT_111.": ".$frm->text('email_title',varset($mailSource['mail_title'],''))."
    ".LAN_MAILOUT_01.": ".$frm->text('email_from_name',varset($mailSource['mail_from_name'],USERNAME))."
    ".LAN_MAILOUT_02.": ".$frm->text('email_from_email',varset($mailSource['mail_from_email'],USEREMAIL))."
    ".LAN_MAILOUT_03.": ".$this->emailSelector('all', varset($mailSource['mail_selectors'], FALSE))."
    ".LAN_MAILOUT_04.": ".$frm->text('email_cc',varset($mailSource['mail_cc'],''))."
    ".LAN_MAILOUT_05.": ".$frm->text('email_bcc',varset($mailSource['mail_bcc'],''))."
    ".LAN_MAILOUT_51.": ".$frm->text('email_subject',varset($email_subject,''))."
    ".LAN_MAILOUT_07.": "; $text .= ""; $text .= "
    ".LAN_MAILOUT_09.": \n"; 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 .= $this->sendStyleSelect(varset($mailSource['mail_send_style'], '')); $checked = (isset($mailSource['mail_include_images']) && $mailSource['mail_include_images']) ? " checked='checked'" : ''; $text .= "  ".LAN_MAILOUT_225; $text .="
    ".$frm->bbarea('email_body',$email_body,'mailout','helpb')."
    "; // $text .= display_help('helpb','mailout'); if(e_WYSIWYG) { $text .=" "; } $text .="
    "; $text .= "
    "; if($email_id) { $text .= $frm->hidden('mail_source_id',$email_id); $text .= $frm->admin_button('update_email',LAN_UPDATE); //$text .= ""; //$text .= ""; } else { $text .= $frm->admin_button('save_email',LAN_SAVE,'other'); } $text .= $frm->admin_button('send_email',LAN_MAILOUT_08); // $text .= "
    "; $ns->tablerender(LAN_MAILOUT_15,$mes->render(). $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(); switch ($type) { case 'sent' : $searchType = 'allcomplete'; break; default : $searchType = $type; } 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, '*', $searchType, $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); return; } $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 'yesno' : $text .= $row[$fieldName] ? LAN_YES : LAN_NO; 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' of its a new email (no change if already on hold) * * @param array $mailData - Details of the email, selection criteria etc * @param boolean $fromHold - FALSE if this is a 'new' email to send, TRUE if its already been put on hold (selects processing path) * @return text for display */ public function sendEmailCircular($mailData, $fromHold = FALSE) { $sql = e107::getDb(); $mes = e107::getMessage(); $frm = e107::getForm(); if ($fromHold) { // Email data already generated $mailMainID = $mailData['mail_source_id']; if ($mailMainID == 0) return FALSE; if (FALSE === ($mailData = $this->retrieveEmail($mailMainID))) // Get the new data { return FALSE; } $counters['add'] = $mailData['mail_togo_count']; // Set up the counters $counters['dups'] = 0; } else { // 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 $key => $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'][$key])) { // Initialise $mailerCount = $m->selectInit($mailData['mail_selectors'][$key]); 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 ($this->mailHandlers as $key => $m) { if ($m->mailerEnabled && ($contentArray = $m->showSelect(FALSE,$mailData['mail_selectors'][$key]))) { $text .= ''; $text .= ''; } } // Figures - number of emails to send, number of duplicates stripped $text .= '"; $text .= ''; $text .= "
    '.LAN_MAILOUT_180.'
    '.$m->mailerName.'
      '; foreach($contentArray as $val) { $text .= "
    • ".$val['caption']." : ".$val['html']."
    • "; } $text .= '
    '.LAN_MAILOUT_173.''.($mailData['mail_togo_count'])."
    '.LAN_MAILOUT_71.' '.$counters['add'].' '.LAN_MAILOUT_69.$counters['dups'].LAN_MAILOUT_70.'
    \n
    "; $text .= $this->makeAdvancedOptions(TRUE); // Show the table of advanced options $text .= "
    "; $text .= $frm->admin_button('email_sendnow',"Send Now"); $text .= $frm->admin_button('email_send',"Send Later"); // $text .= ""; if (!$fromHold) { $text .= $frm->admin_button('email_hold',LAN_HOLD); $text .= $frm->admin_button('email_cancel',LAN_CANCEL); // $text .= " "; // $text .= " "; } $text .= "
    "; e107::getRender()->tablerender("
    ".ADLAN_136." :: ".LAN_MAILOUT_179."
    ",$mes->render(). $text); } // End of previewed email protected function makeAdvancedOptions($initHide = FALSE) { // Separate table for advanced mailout options // mail_notify_complete field $text = " ".LAN_MAILOUT_242."
    "; $text .= ""; $text .= ""; // Can comment the two lines above, uncomment two lines below, and default time/date is shown. May or may not be preferable // $text .= ""; // $text .= ""; $text .= ""; $text .= "
    ".LAN_MAILOUT_238."".$this->makeCalendar('mail_earliest_time', '', CORE_DATE_ORDER)."
    ".LAN_MAILOUT_239."".$this->makeCalendar('mail_latest_time', '', CORE_DATE_ORDER)."
    ".LAN_MAILOUT_238."".$this->makeCalendar('mail_earliest_time', time(), CORE_DATE_ORDER)."
    ".LAN_MAILOUT_239."".$this->makeCalendar('mail_latest_time', time()+86400, CORE_DATE_ORDER)."
    ".LAN_MAILOUT_240."".LAN_MAILOUT_241."
    \n
    "; return $text; } public function makeCalendar($calName, $calVal = '', $dateOrder = 'dmy') { // Determine formatting strings this way, to give sensible default switch ($dateOrder) { case 'mdy' : $dateString = '%m/%d/%Y %H:%I'; $dispString = 'm/d/Y H:I'; break; case 'ymd' : $dateString = '%Y/%m/%d %H:%I'; $dispString = 'Y/m/d H:I'; break; case 'dmy' : default : $dateString = '%d/%m/%Y %H:%I'; $dispString = 'd/m/Y H:I'; } $calOptions = array( 'showsTime' => TRUE, 'showOthers' => false, 'weekNumbers' => false, 'ifFormat' => $dateString ); $calAttrib = array( 'class' => 'tbox', 'size' => 15, // Number of characters 'name' => $calName, 'value' => (($calVal == '') ? '' : date($dispString,$calVal)) ); list($dformat,$tformat) = explode(" ",$dateString); $options['type'] = 'datetime'; $options['dateFormat'] = $dformat; $options['timeFormat'] = $tformat; return e107::getForm()->datepicker($calName,$calVal,$options); // return $this->_cal->make_input_field($calOptions, $calAttrib); } /** * 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(); if ($count == 0) { $text .= "".LAN_MAILOUT_253.''; } else { $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); } /** * Clean up mailout DB * Dump array of results to admin log * * @return boolean TRUE if no errors, FALSE if errors */ public function dbTidy() { $noError = TRUE; $results = array(); $this->checkDB(2); // Make sure DB object created // First thing, delete temporary records from both tables if (($res = $this->db2->db_Delete('mail_content', '`mail_content_status` = '.MAIL_STATUS_TEMP)) === FALSE) { $results[] = 'Error '.$this->db2->mySQLlastErrNum.':'.$this->db2->mySQLlastErrText.' deleting temporary records from mail_content'; $noError = FALSE; } else { if ($res) $results[] = str_replace(array('--COUNT--', '--TABLE--'), array($res, 'mail_content'), LAN_MAILOUT_227); } if (($res = $this->db2->db_Delete('mail_recipients', '`mail_status` = '.MAIL_STATUS_TEMP)) === FALSE) { $results[] = 'Error '.$this->db2->mySQLlastErrNum.':'.$this->db2->mySQLlastErrText.' deleting temporary records from mail_recipients'; $noError = FALSE; } else { if ($res) $results[] = str_replace(array('--COUNT--', '--TABLE--'), array($res, 'mail_recipients'), LAN_MAILOUT_227); } // Now look for 'orphaned' recipient records if (($res = $this->db2->db_Select_gen("DELETE `#mail_recipients` FROM `#mail_recipients` LEFT JOIN `#mail_content` ON `#mail_recipients`.`mail_detail_id` = `#mail_content`.`mail_source_id` WHERE `#mail_content`.`mail_source_id` IS NULL")) === FALSE) { $results[] = 'Error '.$this->db2->mySQLlastErrNum.':'.$this->db2->mySQLlastErrText.' deleting orphaned records from mail_recipients'; $noError = FALSE; } elseif ($res) { if ($res) $results[] = str_replace('--COUNT--', $res, LAN_MAILOUT_226); } // Scan content table for anomalies, out of time records if (($res = $this->db2->db_Select_gen("SELECT * FROM `#mail_content` WHERE (`mail_content_status` >".MAIL_STATUS_FAILED.") AND (`mail_content_status` <=".MAIL_STATUS_MAX_ACTIVE.") AND ((`mail_togo_count`=0) OR ( (`mail_last_date` != 0) AND (`mail_last_date` < ".time().")))")) === FALSE) { $results[] = 'Error '.$this->db2->mySQLlastErrNum.':'.$this->db2->mySQLlastErrText.' checking bad status in mail_content'; $noError = FALSE; } else { $items = array(); // Store record number of any content record that needs to be changed while ($row = $this->db2->db_Fetch(MYSQL_ASSOC)) { $items[] = $row['mail_source_id']; if ($row['mail_source_id']) { if (FALSE == $this->cancelEmail($row['mail_source_id'])) { $results[] = 'Error cancelling email ref: '.$row['mail_source_id']; } else { $results[] = 'Email cancelled: '.$row['mail_source_id']; } } } if (count($items)) $results[] = str_replace(array('--COUNT--', '--RECORDS--'), array(count($items), implode(', ', $items)), LAN_MAILOUT_228); } //Finally - check for inconsistent recipient and content status records - basically verify counts if (($res = $this->db2->db_Select_gen("SELECT COUNT(mr.`mail_status`) AS mr_count, mr.`mail_status`, mc.`mail_source_id`, mc.`mail_togo_count`, mc.`mail_sent_count`, mc.`mail_fail_count`, mc.`mail_bounce_count`, mc.`mail_source_id` FROM `#mail_recipients` AS mr LEFT JOIN `#mail_content` AS mc ON mr.`mail_detail_id` = mc.`mail_source_id` WHERE mc.`mail_content_status` <= ".MAIL_STATUS_MAX_ACTIVE." GROUP BY mr.`mail_status`, mc.`mail_source_id` ORDER BY mc.`mail_source_id` ")) === FALSE) { $results[] = 'Error '.$this->db2->mySQLlastErrNum.':'.$this->db2->mySQLlastErrText.' assembling email counts'; $noError = FALSE; } else { $lastMail = 0; // May get several rows per mail $notLast = TRUE; // This forces one more loop, so we can clean up for last record read $changeCount = 0; $saveRow = array(); while (($row = $this->db2->db_Fetch(MYSQL_ASSOC)) || $notLast) { if (($lastMail > 0 && $row === FALSE) || ($lastMail != $row['mail_source_id'])) { // Change of mail ID here - handle any accumulated info if ($lastMail > 0) { // Need to verify counts for mail just read $changes = array(); foreach ($counters as $k => $v) { if ($saveRow[$k] != $v) { $changes[$k] = $v; // Assume the counters have got it right } } if (count($changes)) { // *************** Update mail record here ********************* $this->checkDB(1); $this->db->db_Update('mail_content', array('data' => $changes, 'WHERE' => '`mail_source_id` = '.$lastMail, '_FIELDS' => $this->dbTypes['mail_content'])); $line = "Count update for {$saveRow['mail_source_id']} - {$saveRow['mail_togo_count']}, {$saveRow['mail_sent_count']}, {$saveRow['mail_fail_count']}, {$saveRow['mail_bounce_count']} => "; $line .= implode (', ', $counters); $results[] = $line; $changeCount++; //echo $line.'
    '; } } // Now reset for current mail $lastMail = $row['mail_source_id']; $counters = array('mail_togo_count' => 0, 'mail_sent_count' => 0, 'mail_fail_count' => 0, 'mail_bounce_count' => 0); $saveRow = $row; } if ($row === FALSE) $notLast = FALSE; // We get one record for each mail_status value for a given email - use them to update counts if ($notLast) { switch ($row['mail_status']) { case MAIL_STATUS_SENT : // Mail sent. Email handler happy, but may have bounced (or may be yet to bounce) $counters['mail_sent_count'] += $row['mr_count']; break; case MAIL_STATUS_BOUNCED : $counters['mail_sent_count'] += $row['mr_count']; // It was sent, so increment that counter $counters['mail_bounce_count'] += $row['mr_count']; //...but bounced, so extra status break; case MAIL_STATUS_CANCELLED : // Cancelled email - treat as a failure case MAIL_STATUS_FAILED : $counters['mail_fail_count'] += $row['mr_count']; // Never sent at all break; case MAIL_STATUS_PARTIAL : // Shouldn't get this on individual emails - ignore if we do break; default : if (($row['mail_status'] >= MAIL_STATUS_PENDING) && ($row['mail_status'] <= MAIL_STATUS_MAX_ACTIVE)) { $counters['mail_togo_count'] += $row['mr_count']; // Still in the queue } } } } if ($changeCount) $results[] = str_replace('--COUNT--', $changeCount, LAN_MAILOUT_237); } $this->e107->admin_log->log_event('MAIL_05', implode('[!br!]', $results), E_LOG_INFORMATIVE, ''); return $noError; } } ?>