/** * validateLogin, verify that the login credentials are correct. * * @param string $login the login field * @param string $password the password * * @return array * index 0 -> false if login failed, index of the administrator if successful * index 1 -> error message when login fails * * eg * return array(5,'OK'); // -> login successful for admin 5 * return array(0,'Incorrect login details'); // login failed */ public function validateLogin($login, $password) { $query = sprintf('select password, disabled, id from %s where loginname = "%s"', $GLOBALS['tables']['admin'], sql_escape($login)); $req = Sql_Query($query); $admindata = Sql_Fetch_Assoc($req); $encryptedPass = hash(ENCRYPTION_ALGO, $password); $passwordDB = $admindata['password']; #Password encryption verification. if (strlen($passwordDB) < $GLOBALS['hash_length']) { // Passwords are encrypted but the actual is not. #Encrypt the actual DB password before performing the validation below. $encryptedPassDB = hash(ENCRYPTION_ALGO, $passwordDB); $query = sprintf('update %s set password = "******" where loginname = "%s"', $GLOBALS['tables']['admin'], $encryptedPassDB, sql_escape($login)); $passwordDB = $encryptedPassDB; $req = Sql_Query($query); } if ($admindata['disabled']) { return array(0, s('your account has been disabled')); } elseif (!empty($passwordDB) && $encryptedPass == $passwordDB) { return array($admindata['id'], 'OK'); } else { if (!empty($GLOBALS['admin_auth_module'])) { Error(s('Admin authentication has changed, please update your admin module'), 'https://resources.phplist.com/documentation/errors/adminauthchange'); return; } return array(0, s('incorrect password')); } if (!empty($GLOBALS['admin_auth_module'])) { Error(s('Admin authentication has changed, please update your admin module'), 'https://resources.phplist.com/documentation/errors/adminauthchange'); return; } return array(0, s('Login failed')); }
/** * Create the html to show the number of list members in up to three totals. * Confirmed - subscriber is confirmed and not blacklisted * Not confirmed - subscriber is not confirmed and not blacklisted * Blacklisted - subscriber is blacklisted. * * @param int $listId the list id, or 0 for all subscribers * @return string */ function listMemberCounts($listId) { global $tables; if ($listId) { $join = "JOIN {$tables['listuser']} lu ON u.id = lu.userid\n WHERE lu.listid = {$listId}"; } else { $join = ''; } $req = Sql_Query("SELECT\n SUM(1) AS total,\n SUM(IF(u.confirmed = 1 && u.blacklisted = 0, 1, 0)) AS confirmed,\n SUM(IF(u.confirmed = 0 && u.blacklisted = 0, 1, 0)) AS notconfirmed,\n SUM(IF(u.blacklisted = 1, 1, 0)) AS blacklisted\n FROM {$tables['user']} u\n {$join}"); $counts = Sql_Fetch_Assoc($req); $membersDisplay = sprintf('<span class="memberCount" title="%s">%s</span>' . ' (' . '<span class="unconfirmedCount" title="%s">%s</span>, ' . ' ' . '<span class="blacklistedCount" title="%s">%s</span>' . ')', s('Confirmed members'), number_format($counts['confirmed']), s('Unconfirmed members'), number_format($counts['notconfirmed']), s('Blacklisted members'), number_format($counts['blacklisted'])); return $membersDisplay; }
function Retreive_And_Unserialize() { $retrieve_serialized_query = sprintf("select value from %s", $this->AttributeChangerData['attribute_changer_tablename']); $retrieve_s_return = Sql_Query($retrieve_serialized_query); if (!$retrieve_s_return) { print "ERROR NO STORED SESSION"; die; } $returned_result = Sql_Fetch_Assoc($retrieve_s_return); if (!isset($returned_result['value'])) { print "ERROR Improperly stored value data"; die; } //print_r($returned_result); $serialized_session = $returned_result['value']; //print($serialized_session); $this->Current_Session = unserialize(base64_decode($serialized_session)); }
function Get_Attribute_List() { $AttributeChangerPlugin = $GLOBALS['AttributeChangerPlugin']; $AttributeChangerData = $AttributeChangerPlugin->AttributeChangerData; $case_array = $AttributeChangerData['case_array']; $query = sprintf('select * from %s', $AttributeChangerData['tables']['attribute']); $attribute_data_return = Sql_Query($query); if ($attribute_data_return) { $new_attribute_list = array(); while ($attribute_data = Sql_Fetch_Assoc($attribute_data_return)) { if (!isset($attribute_data['id']) || !isset($attribute_data['name']) || !isset($attribute_data['type'])) { //not known format, cannot use } else { if (isset($new_attribute_list[$attribute_data['id']])) { //cannot have duplicates, but really wont continue; } //use the attribute list to get type and value information $new_attribute_list[$attribute_data['id']] = $attribute_data; //must check tables for values if ($case_array[$attribute_data['type']] == "case_2" || $case_array[$attribute_data['type']] == "case_3") { if (!isset($attribute_data['tablename'])) { //this wouldnt make sense unset($new_attribute_list[$attribute_data['id']]); } else { $new_attribute_list[$attribute_data['id']]['allowed_value_ids'] = $this->Get_Attribute_Value_Id_List($attribute_data['id']); if ($new_attribute_list[$attribute_data['id']]['allowed_value_ids'] === null) { //was an error, something missing, no values is just empty array, must still match, so unset unset($new_attribute_list[$attribute_data['id']]); } } } else { //is other input type, do not set values array } } } //print_r($new_attribute_list); return $new_attribute_list; } else { //no rows :S //PRINT AN ERROR I GUESS LOL return null; } }
$_SESSION['action_result'] = s('Category assignments saved'); Redirect('list'); } else { Info(s('Categories saved'), true); } } $req = Sql_Query(sprintf('select * from %s %s', $tables['list'], $subselect)); if (!Sql_Affected_Rows()) { Info(s('All lists have already been assigned a category') . '<br/>' . PageLinkButton('list', s('Back')), true); } print '<div class="fright">' . PageLinkButton('catlists&show=all', s('Re-edit all lists')) . '</div>'; print '<div class="fright">' . PageLinkButton('configure&id=list_categories&ret=catlists', $I18N->get('Configure Categories')) . '</div>'; $ls = new WebblerListing(s('Categorise lists')); $aListCategories = listCategories(); if (count($aListCategories)) { while ($row = Sql_Fetch_Assoc($req)) { $ls->addELement($row['id']); $ls->addColumn($row['id'], $GLOBALS['I18N']->get('Name'), stripslashes($row['name'])); $catselect = '<select name="category[' . $row['id'] . ']">'; $catselect .= '<option value="">-- ' . s('choose category') . '</option>'; $catselect .= '<option value="">-- ' . s('none') . '</option>'; foreach ($aListCategories as $category) { $category = trim($category); $catselect .= sprintf('<option value="%s" %s>%s</option>', $category, $category == $row['category'] ? 'selected="selected"' : '', $category); } $catselect .= '</select>'; $ls->addColumn($row['id'], s('Category'), $catselect); } } $ls->addButton(s('save'), 'javascript:document.categoryedit.submit();'); print $ls->display();
function sendEmail($messageid, $email, $hash, $htmlpref = 0, $rssitems = array(), $forwardedby = array()) { $getspeedstats = VERBOSE && !empty($GLOBALS['getspeedstats']) && isset($GLOBALS['processqueue_timer']); $sqlCountStart = $GLOBALS["pagestats"]["number_of_queries"]; $isTestMail = isset($_GET['page']) && $_GET['page'] == 'send'; ## for testing concurrency, put in a delay to check if multiple send processes cause duplicates #usleep(rand(0,10) * 1000000); global $strThisLink, $strUnsubscribe, $PoweredByImage, $PoweredByText, $cached, $website, $counters; if ($email == "") { return 0; } if ($getspeedstats) { output('sendEmail start ' . $GLOBALS['processqueue_timer']->interval(1)); } #0013076: different content when forwarding 'to a friend' if (FORWARD_ALTERNATIVE_CONTENT) { $forwardContent = sizeof($forwardedby) > 0; } else { $forwardContent = 0; } if (empty($cached[$messageid])) { if (!precacheMessage($messageid, $forwardContent)) { unset($cached[$messageid]); logEvent('Error loading message ' . $messageid . ' in cache'); return 0; } } else { # dbg("Using cached {$cached[$messageid]["fromemail"]}"); if (VERBOSE) { output('Using cached message'); } } if (VERBOSE) { output(s('Sending message %d with subject %s to %s', $messageid, $cached[$messageid]["subject"], $email)); } ## at this stage we don't know whether the content is HTML or text, it's just content $content = $cached[$messageid]['content']; if (VERBOSE && $getspeedstats) { output('Load user start'); } $userdata = array(); $user_att_values = array(); #0011857: forward to friend, retain attributes if ($hash == 'forwarded' && defined('KEEPFORWARDERATTRIBUTES') && KEEPFORWARDERATTRIBUTES) { $user_att_values = getUserAttributeValues($forwardedby['email']); } elseif ($hash != 'forwarded') { $user_att_values = getUserAttributeValues($email); } if (!is_array($user_att_values)) { $user_att_values = array(); } foreach ($user_att_values as $key => $val) { $newkey = cleanAttributeName($key); ## in the help, we only list attributes with "strlen < 20" unset($user_att_values[$key]); if (strlen($key) < 20) { $user_att_values[$newkey] = $val; } } # print '<pre>';var_dump($user_att_values);print '</pre>';exit; $query = sprintf('select * from %s where email = ?', $GLOBALS["tables"]["user"]); $rs = Sql_Query_Params($query, array($email)); $userdata = Sql_Fetch_Assoc($rs); if (empty($userdata['id'])) { $userdata = array(); } #var_dump($userdata); if (stripos($content, "[LISTS]") !== false) { $listsarr = array(); $req = Sql_Query(sprintf('select list.name from %s as list,%s as listuser where list.id = listuser.listid and listuser.userid = %d', $GLOBALS["tables"]["list"], $GLOBALS["tables"]["listuser"], $userdata["id"])); while ($row = Sql_Fetch_Row($req)) { array_push($listsarr, $row[0]); } if (!empty($listsarr)) { $html['lists'] = join('<br/>', $listsarr); $text['lists'] = join("\n", $listsarr); } else { $html['lists'] = $GLOBALS['strNoListsFound']; $text['lists'] = $GLOBALS['strNoListsFound']; } unset($listsarr); } if (VERBOSE && $getspeedstats) { output('Load user end'); } if ($cached[$messageid]['userspecific_url']) { if (VERBOSE && $getspeedstats) { output('fetch personal URL start'); } ## Fetch external content, only if the URL has placeholders if ($GLOBALS["can_fetchUrl"] && preg_match("/\\[URL:([^\\s]+)\\]/i", $content, $regs)) { while (isset($regs[1]) && strlen($regs[1])) { $url = $regs[1]; if (!preg_match('/^http/i', $url)) { $url = 'http://' . $url; } $remote_content = fetchUrl($url, $userdata); # @@ don't use this # $remote_content = includeStyles($remote_content); if ($remote_content) { ## @TODO, work out a nice way to do this: ##17197 ## collecting different remote URLS only works if they do not have html and body tags. ## but if we strip them here, that might affect specially crafted ones, eg <body class="xx"> if (0) { $remote_content = preg_replace('/<html[^>]*>/', '', $remote_content); $remote_content = preg_replace('/<body[^>]*>/', '', $remote_content); $remote_content = preg_replace('/<\\/html[^>]*>/', '', $remote_content); $remote_content = preg_replace('/<\\/body[^>]*>/', '', $remote_content); } $content = str_replace($regs[0], '<!--' . $url . '-->' . $remote_content, $content); $cached[$messageid]["htmlformatted"] = strip_tags($content) != $content; } else { logEvent("Error fetching URL: {$regs['1']} to send to {$email}"); return 0; } preg_match("/\\[URL:([^\\s]+)\\]/i", $content, $regs); } } if (VERBOSE && $getspeedstats) { output('fetch personal URL end'); } } if (VERBOSE && $getspeedstats) { output('define placeholders start'); } $url = getConfig("unsubscribeurl"); ## https://mantis.phplist.com/view.php?id=16680 -> the "sep" should be & for the text links $sep = strpos($url, '?') === false ? '?' : '&'; $html["unsubscribe"] = sprintf('<a href="%s%suid=%s">%s</a>', $url, htmlspecialchars($sep), $hash, $strUnsubscribe); $text["unsubscribe"] = sprintf('%s%suid=%s', $url, $sep, $hash); $text["jumpoff"] = sprintf('%s%suid=%s&jo=1', $url, $sep, $hash); $html["unsubscribeurl"] = sprintf('%s%suid=%s', $url, htmlspecialchars($sep), $hash); $text["unsubscribeurl"] = sprintf('%s%suid=%s', $url, $sep, $hash); $text["jumpoffurl"] = sprintf('%s%suid=%s&jo=1', $url, $sep, $hash); #0013076: Blacklisting posibility for unknown users $url = getConfig("blacklisturl"); $sep = strpos($url, '?') === false ? '?' : '&'; $html["blacklist"] = sprintf('<a href="%s%semail=%s">%s</a>', $url, htmlspecialchars($sep), $email, $strUnsubscribe); $text["blacklist"] = sprintf('%s%semail=%s', $url, $sep, $email); $html["blacklisturl"] = sprintf('%s%semail=%s', $url, htmlspecialchars($sep), $email); $text["blacklisturl"] = sprintf('%s%semail=%s', $url, $sep, $email); #0013076: Problem found during testing: message part must be parsed correctly as well. if (sizeof($forwardedby) && isset($forwardedby['email'])) { $html["unsubscribe"] = $html["blacklist"]; $text["unsubscribe"] = $text["blacklist"]; $html["forwardedby"] = $forwardedby["email"]; $text["forwardedby"] = $forwardedby["email"]; } $url = getConfig("subscribeurl"); $sep = strpos($url, '?') === false ? '?' : '&'; $html["subscribe"] = sprintf('<a href="%s">%s</a>', $url, $strThisLink); $text["subscribe"] = sprintf('%s', $url); $html["subscribeurl"] = sprintf('%s', $url); $text["subscribeurl"] = sprintf('%s', $url); $url = getConfig("forwardurl"); $sep = strpos($url, '?') === false ? '?' : '&'; $html["forward"] = sprintf('<a href="%s%suid=%s&mid=%d">%s</a>', $url, htmlspecialchars($sep), $hash, $messageid, $strThisLink); $text["forward"] = sprintf('%s%suid=%s&mid=%d', $url, $sep, $hash, $messageid); $html["forwardurl"] = sprintf('%s%suid=%s&mid=%d', $url, htmlspecialchars($sep), $hash, $messageid); $text["forwardurl"] = $text["forward"]; $html["messageid"] = sprintf('%d', $messageid); $text["messageid"] = sprintf('%d', $messageid); $url = getConfig("forwardurl"); # make sure there are no newlines, otherwise they get turned into <br/>s $html["forwardform"] = sprintf('<form method="get" action="%s" name="forwardform" class="forwardform"><input type="hidden" name="uid" value="%s" /><input type="hidden" name="mid" value="%d" /><input type="hidden" name="p" value="forward" /><input type=text name="email" value="" class="forwardinput" /><input name="Send" type="submit" value="%s" class="forwardsubmit"/></form>', $url, $hash, $messageid, $GLOBALS['strForward']); $text["signature"] = "\n\n-- powered by phpList, www.phplist.com --\n\n"; $url = getConfig("preferencesurl"); $sep = strpos($url, '?') === false ? '?' : '&'; $html["preferences"] = sprintf('<a href="%s%suid=%s">%s</a>', $url, htmlspecialchars($sep), $hash, $strThisLink); $text["preferences"] = sprintf('%s%suid=%s', $url, $sep, $hash); $html["preferencesurl"] = sprintf('%s%suid=%s', $url, htmlspecialchars($sep), $hash); $text["preferencesurl"] = sprintf('%s%suid=%s', $url, $sep, $hash); $url = getConfig("confirmationurl"); $sep = strpos($url, '?') === false ? '?' : '&'; $html["confirmationurl"] = sprintf('%s%suid=%s', $url, htmlspecialchars($sep), $hash); $text["confirmationurl"] = sprintf('%s%suid=%s', $url, $sep, $hash); #historical, not sure it's still used $html["userid"] = $hash; $text["userid"] = $hash; $html['website'] = $GLOBALS['website']; # Your website's address, e.g. www.yourdomain.com $text['website'] = $GLOBALS['website']; $html['domain'] = $GLOBALS['domain']; # Your domain, e.g. yourdomain.com $text['domain'] = $GLOBALS['domain']; if ($hash != 'forwarded') { $text['footer'] = $cached[$messageid]["textfooter"]; $html['footer'] = $cached[$messageid]["htmlfooter"]; } else { #0013076: different content when forwarding 'to a friend' if (FORWARD_ALTERNATIVE_CONTENT) { $text['footer'] = stripslashes($messagedata["forwardfooter"]); } else { $text['footer'] = getConfig('forwardfooter'); } $html['footer'] = $text['footer']; } /* We request you retain the signature below in your emails including the links. This not only gives respect to the large amount of time given freely by the developers but also helps build interest, traffic and use of phpList, which is beneficial to it's future development. You can configure how the credits are added to your pages and emails in your config file. Michiel Dethmers, phpList Ltd 2003 - 2013 */ if (!EMAILTEXTCREDITS) { $html["signature"] = $PoweredByImage; #'<div align="center" id="signature"><a href="http://www.phplist.com"><img src="powerphplist.png" width=88 height=31 title="Powered by PHPlist" alt="Powered by PHPlist" border="0" /></a></div>'; # oops, accidentally became spyware, never intended that, so take it out again :-) $html["signature"] = preg_replace('/src=".*power-phplist.png"/', 'src="powerphplist.png"', $html["signature"]); } else { $html["signature"] = $PoweredByText; } # $content = $cached[$messageid]["htmlcontent"]; if (VERBOSE && $getspeedstats) { output('define placeholders end'); } ## Fill text and html versions depending on given versions. if (VERBOSE && $getspeedstats) { output('parse text to html or html to text start'); } if ($cached[$messageid]["htmlformatted"]) { if (empty($cached[$messageid]["textcontent"])) { $textcontent = HTML2Text($content); } else { $textcontent = $cached[$messageid]["textcontent"]; } $htmlcontent = $content; } else { if (empty($cached[$messageid]["textcontent"])) { $textcontent = $content; } else { $textcontent = $cached[$messageid]["textcontent"]; } $htmlcontent = parseText($content); } if (VERBOSE && $getspeedstats) { output('parse text to html or html to text end'); } $defaultstyle = getConfig("html_email_style"); $adddefaultstyle = 0; if (VERBOSE && $getspeedstats) { output('merge into template start'); } if ($cached[$messageid]["template"]) { # template used $htmlmessage = str_replace("[CONTENT]", $htmlcontent, $cached[$messageid]["template"]); } else { # no template used $htmlmessage = $htmlcontent; $adddefaultstyle = 1; } $textmessage = $textcontent; if (VERBOSE && $getspeedstats) { output('merge into template end'); } ## Parse placeholders if (VERBOSE && $getspeedstats) { output('parse placeholders start'); } /* var_dump($html); var_dump($userdata); var_dump($user_att_values); exit; */ # print htmlspecialchars($htmlmessage);exit; ### @@@TODO don't use forward and forward form in a forwarded message as it'll fail if (strpos($htmlmessage, "[FOOTER]") !== false) { $htmlmessage = str_ireplace("[FOOTER]", $html["footer"], $htmlmessage); } elseif ($html["footer"]) { $htmlmessage = addHTMLFooter($htmlmessage, '<br />' . $html["footer"]); } if (strpos($htmlmessage, "[SIGNATURE]") !== false) { $htmlmessage = str_ireplace("[SIGNATURE]", $html["signature"], $htmlmessage); } else { # BUGFIX 0015303, 2/2 // $htmlmessage .= '<br />'.$html["signature"]; $htmlmessage = addHTMLFooter($htmlmessage, ' ' . $html["signature"]); } # END BUGFIX 0015303, 2/2 if (strpos($textmessage, "[FOOTER]")) { $textmessage = str_ireplace("[FOOTER]", $text["footer"], $textmessage); } else { $textmessage .= "\n\n" . $text["footer"]; } if (strpos($textmessage, '[SIGNATURE]')) { $textmessage = str_ireplace("[SIGNATURE]", $text["signature"], $textmessage); } else { $textmessage .= "\n" . $text["signature"]; } ### addition to handle [FORWARDURL:Message ID:Link Text] (link text optional) while (preg_match('/\\[FORWARD:([^\\]]+)\\]/Uxm', $htmlmessage, $regs)) { $newforward = $regs[1]; $matchtext = $regs[0]; if (strpos($newforward, ':')) { ## using FORWARDURL:messageid:linktext list($forwardmessage, $forwardtext) = explode(':', $newforward); } else { $forwardmessage = sprintf('%d', $newforward); $forwardtext = 'this link'; } if (!empty($forwardmessage)) { $url = getConfig("forwardurl"); $sep = strpos($url, '?') === false ? '?' : '&'; $forwardurl = sprintf('%s%suid=%s&mid=%d', $url, $sep, $hash, $forwardmessage); $htmlmessage = str_replace($matchtext, '<a href="' . htmlspecialchars($forwardurl) . '">' . $forwardtext . '</a>', $htmlmessage); } else { ## make sure to remove the match, otherwise, it'll be an eternal loop $htmlmessage = str_replace($matchtext, '', $htmlmessage); } } ## the text message has to be parsed seperately, because the line might wrap if the text for the link is long, so the match text is different while (preg_match('/\\[FORWARD:([^\\]]+)\\]/Uxm', $textmessage, $regs)) { $newforward = $regs[1]; $matchtext = $regs[0]; if (strpos($newforward, ':')) { ## using FORWARDURL:messageid:linktext list($forwardmessage, $forwardtext) = explode(':', $newforward); } else { $forwardmessage = sprintf('%d', $newforward); $forwardtext = 'this link'; } if (!empty($forwardmessage)) { $url = getConfig("forwardurl"); $sep = strpos($url, '?') === false ? '?' : '&'; $forwardurl = sprintf('%s%suid=%s&mid=%d', $url, $sep, $hash, $forwardmessage); $textmessage = str_replace($matchtext, $forwardtext . ' ' . $forwardurl, $textmessage); } else { ## make sure to remove the match, otherwise, it'll be an eternal loop $textmessage = str_replace($matchtext, '', $textmessage); } } # $req = Sql_Query(sprintf('select filename,data from %s where template = %d', # $GLOBALS["tables"]["templateimage"],$cached[$messageid]["templateid"])); if (ALWAYS_ADD_USERTRACK) { if (stripos($htmlmessage, '</body>')) { $htmlmessage = str_replace('</body>', '<img src="' . $GLOBALS['public_scheme'] . '://' . $website . $GLOBALS["pageroot"] . '/ut.php?u=' . $hash . '&m=' . $messageid . '" width="1" height="1" border="0" /></body>', $htmlmessage); } else { $htmlmessage .= '<img src="' . $GLOBALS['public_scheme'] . '://' . $website . $GLOBALS["pageroot"] . '/ut.php?u=' . $hash . '&m=' . $messageid . '" width="1" height="1" border="0" />'; } } else { ## can't use str_replace or str_ireplace, because those replace all, and we only want to replace one $htmlmessage = preg_replace('/\\[USERTRACK\\]/i', '<img src="' . $GLOBALS['public_scheme'] . '://' . $website . $GLOBALS["pageroot"] . '/ut.php?u=' . $hash . '&m=' . $messageid . '" width="1" height="1" border="0" />', $htmlmessage, 1); } # make sure to only include usertrack once, otherwise the stats would go silly $htmlmessage = str_ireplace('[USERTRACK]', '', $htmlmessage); $html['subject'] = $cached[$messageid]["subject"]; $text['subject'] = $cached[$messageid]["subject"]; $htmlmessage = parsePlaceHolders($htmlmessage, $html); $textmessage = parsePlaceHolders($textmessage, $text); if (VERBOSE && $getspeedstats) { output('parse placeholders end'); } if (VERBOSE && $getspeedstats) { output('parse userdata start'); } $htmlmessage = parsePlaceHolders($htmlmessage, $userdata); $textmessage = parsePlaceHolders($textmessage, $userdata); //CUT 2 $destinationemail = ''; if (is_array($user_att_values)) { // CUT 3 $htmlmessage = parsePlaceHolders($htmlmessage, $user_att_values); $textmessage = parsePlaceHolders($textmessage, $user_att_values); } if (VERBOSE && $getspeedstats) { output('parse userdata end'); } if (!$destinationemail) { $destinationemail = $email; } # this should move into a plugin if (strpos($destinationemail, '@') === false && isset($GLOBALS["expand_unqualifiedemail"])) { $destinationemail .= $GLOBALS["expand_unqualifiedemail"]; } if (VERBOSE && $getspeedstats) { output('pass to plugins for destination email start'); } foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { # print "Checking Destination for ".$plugin->name."<br/>"; $destinationemail = $plugin->setFinalDestinationEmail($messageid, $user_att_values, $destinationemail); } if (VERBOSE && $getspeedstats) { output('pass to plugins for destination email end'); } foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { $textmessage = $plugin->parseOutgoingTextMessage($messageid, $textmessage, $destinationemail, $userdata); $htmlmessage = $plugin->parseOutgoingHTMLMessage($messageid, $htmlmessage, $destinationemail, $userdata); } ## click tracking # for now we won't click track forwards, as they are not necessarily users, so everything would fail if (VERBOSE && $getspeedstats) { output('click track start'); } if (CLICKTRACK && $hash != 'forwarded' && !empty($userdata['id'])) { $urlbase = ''; # let's leave this for now /* if (preg_match('/<base href="(.*)"([^>]*)>/Umis',$htmlmessage,$regs)) { $urlbase = $regs[1]; } else { $urlbase = ''; } # print "URLBASE: $urlbase<br/>"; */ # convert html message # preg_match_all('/<a href="?([^> "]*)"?([^>]*)>(.*)<\/a>/Umis',$htmlmessage,$links); preg_match_all('/<a (.*)href=["\'](.*)["\']([^>]*)>(.*)<\\/a>/Umis', $htmlmessage, $links); # to process the Yahoo webpage with base href and link like <a href=link> we'd need this one # preg_match_all('/<a href=([^> ]*)([^>]*)>(.*)<\/a>/Umis',$htmlmessage,$links); $clicktrack_root = sprintf('%s://%s/lt.php', $GLOBALS["public_scheme"], $website . $GLOBALS["pageroot"]); for ($i = 0; $i < count($links[2]); $i++) { $link = cleanUrl($links[2][$i]); $link = str_replace('"', '', $link); if (preg_match('/\\.$/', $link)) { $link = substr($link, 0, -1); } $linkid = 0; $linktext = $links[4][$i]; ## if the link is text containing a "protocol" eg http:// then do not track it, otherwise ## it will look like Phishing ## it's ok when the link is an image $linktext = strip_tags($linktext); $looksLikePhishing = stripos($linktext, 'https://') !== false || stripos($linktext, 'http://') !== false; if (!$looksLikePhishing && (preg_match('/^http|ftp/', $link) || preg_match('/^http|ftp/', $urlbase)) && stripos($link, 'www.phplist.com') === false && !strpos($link, $clicktrack_root)) { # take off personal uids $url = cleanUrl($link, array('PHPSESSID', 'uid')); # $url = preg_replace('/&uid=[^\s&]+/','',$link); # if (!strpos('http:',$link)) { # $link = $urlbase . $link; # } $linkid = clickTrackLinkId($messageid, $userdata['id'], $url, $link); $masked = "H|{$linkid}|{$messageid}|" . $userdata['id'] ^ XORmask; $masked = base64_encode($masked); ## 15254- the encoding adds one or two extraneous = signs, take them off $masked = preg_replace('/=$/', '', $masked); $masked = preg_replace('/=$/', '', $masked); $masked = urlencode($masked); if (!CLICKTRACK_LINKMAP) { $newlink = sprintf('<a %shref="%s://%s/lt.php?id=%s" %s>%s</a>', $links[1][$i], $GLOBALS["public_scheme"], $website . $GLOBALS["pageroot"], $masked, $links[3][$i], $links[4][$i]); } else { $newlink = sprintf('<a %shref="%s://%s%s" %s>%s</a>', $links[1][$i], $GLOBALS["public_scheme"], $website . CLICKTRACK_LINKMAP, $masked, $links[3][$i], $links[4][$i]); } $htmlmessage = str_replace($links[0][$i], $newlink, $htmlmessage); } } # convert Text message # first find occurances of our top domain, to avoid replacing them later # hmm, this is no point, it's not just *our* topdomain, but any if (0) { preg_match_all('#(https?://' . $GLOBALS['website'] . '/?)\\s+#mis', $textmessage, $links); # preg_match_all('#(https?://[a-z0-9\./\#\?&:@=%\-]+)#ims',$textmessage,$links); # preg_match_all('!(https?:\/\/www\.[a-zA-Z0-9\.\/#~\?+=&%@-_]+)!mis',$textmessage,$links); for ($i = 0; $i < count($links[1]); $i++) { # not entirely sure why strtolower was used, but it seems to break things http://mantis.phplist.com/view.php?id=4406 # $link = strtolower(cleanUrl($links[1][$i])); $link = cleanUrl($links[1][$i]); if (preg_match('/\\.$/', $link)) { $link = substr($link, 0, -1); } $linkid = 0; if (preg_match('/^http|ftp/', $link) && stripos($link, 'www.phplist.com') === false && !strpos($link, $clicktrack_root)) { $url = cleanUrl($link, array('PHPSESSID', 'uid')); $req = Sql_Query(sprintf('insert ignore into %s (messageid,userid,url,forward) values(%d,%d,"%s","%s")', $GLOBALS['tables']['linktrack'], $messageid, $userdata['id'], $url, $link)); $req = Sql_Fetch_Row_Query(sprintf('select linkid from %s where messageid = %s and userid = %d and forward = "%s" ', $GLOBALS['tables']['linktrack'], $messageid, $userdata['id'], $link)); $linkid = $req[0]; $masked = "T|{$linkid}|{$messageid}|" . $userdata['id'] ^ XORmask; $masked = urlencode(base64_encode($masked)); $newlink = sprintf('%s://%s/lt.php?id=%s', $GLOBALS["public_scheme"], $website . $GLOBALS["pageroot"], $masked); $textmessage = str_replace($links[0][$i], '<' . $newlink . '>', $textmessage); } } } #now find the rest # @@@ needs to expand to find complete urls like: #http://user:password@www.web-site.com:1234/document.php?parameter=something&otherpar=somethingelse#anchor # or secure #https://user:password@www.website.com:2345/document.php?parameter=something%20&otherpar=somethingelse#anchor preg_match_all('#(https?://[^\\s\\>\\}\\,]+)#mis', $textmessage, $links); # preg_match_all('#(https?://[a-z0-9\./\#\?&:@=%\-]+)#ims',$textmessage,$links); # preg_match_all('!(https?:\/\/www\.[a-zA-Z0-9\.\/#~\?+=&%@-_]+)!mis',$textmessage,$links); ## sort the results in reverse order, so that they are replaced correctly rsort($links[1]); $newlinks = array(); for ($i = 0; $i < count($links[1]); $i++) { $link = cleanUrl($links[1][$i]); if (preg_match('/\\.$/', $link)) { $link = substr($link, 0, -1); } $linkid = 0; if (preg_match('/^http|ftp/', $link) && stripos($link, 'www.phplist.com') === false) { # && !strpos($link,$clicktrack_root)) { $url = cleanUrl($link, array('PHPSESSID', 'uid')); $linkid = clickTrackLinkId($messageid, $userdata['id'], $url, $link); $masked = "T|{$linkid}|{$messageid}|" . $userdata['id'] ^ XORmask; $masked = base64_encode($masked); ## 15254- the encoding adds one or two extraneous = signs, take them off $masked = preg_replace('/=$/', '', $masked); $masked = preg_replace('/=$/', '', $masked); $masked = urlencode($masked); if (!CLICKTRACK_LINKMAP) { $newlinks[$linkid] = sprintf('%s://%s/lt.php?id=%s', $GLOBALS["public_scheme"], $website . $GLOBALS["pageroot"], $masked); } else { $newlinks[$linkid] = sprintf('%s://%s%s', $GLOBALS["public_scheme"], $website . CLICKTRACK_LINKMAP, $masked); } # print $links[0][$i] .' -> '.$newlink.'<br/>'; $textmessage = str_replace($links[1][$i], '[%%%' . $linkid . '%%%]', $textmessage); } } foreach ($newlinks as $linkid => $newlink) { $textmessage = str_replace('[%%%' . $linkid . '%%%]', $newlink, $textmessage); } } if (VERBOSE && $getspeedstats) { output('click track end'); } ## if we're not tracking clicks, we should add Google tracking here ## otherwise, we can add it when redirecting on the click if (!CLICKTRACK && !empty($cached[$messageid]['google_track'])) { preg_match_all('/<a (.*)href=["\'](.*)["\']([^>]*)>(.*)<\\/a>/Umis', $htmlmessage, $links); for ($i = 0; $i < count($links[2]); $i++) { $link = cleanUrl($links[2][$i]); $link = str_replace('"', '', $link); ## http://www.google.com/support/analytics/bin/answer.py?hl=en&answer=55578 $trackingcode = 'utm_source=emailcampaign' . $messageid . '&utm_medium=phpList&utm_content=HTML&utm_campaign=' . urlencode($cached[$messageid]["subject"]); ## take off existing tracking code, if found if (strpos($link, 'utm_medium') !== false) { $link = preg_replace('/utm_(\\w+)\\=[^&]+&/U', '', $link); } ## 16894 make sure to keep the fragment value at the end of the URL if (strpos($link, '#')) { list($tmplink, $fragment) = explode('#', $link); $link = $tmplink; unset($tmplink); $fragment = '#' . $fragment; } else { $fragment = ''; } if (strpos($link, '?')) { $newurl = $link . '&' . $trackingcode . $fragment; } else { $newurl = $link . '?' . $trackingcode . $fragment; } # print $link. ' '.$newurl.' <br/>'; $newlink = sprintf('<a %shref="%s" %s>%s</a>', $links[1][$i], $newurl, $links[3][$i], $links[4][$i]); $htmlmessage = str_replace($links[0][$i], $newlink, $htmlmessage); } preg_match_all('#(https?://[^\\s\\>\\}\\,]+)#mis', $textmessage, $links); rsort($links[1]); $newlinks = array(); for ($i = 0; $i < count($links[1]); $i++) { $link = cleanUrl($links[1][$i]); if (preg_match('/\\.$/', $link)) { $link = substr($link, 0, -1); } if (preg_match('/^http|ftp/', $link) && stripos($link, 'www.phplist.com') !== 0) { # && !strpos($link,$clicktrack_root)) { $url = cleanUrl($link, array('PHPSESSID', 'uid')); $trackingcode = 'utm_source=emailcampaign' . $messageid . '&utm_medium=phpList&utm_content=text&utm_campaign=' . urlencode($cached[$messageid]["subject"]); ## take off existing tracking code, if found if (strpos($link, 'utm_medium') !== false) { $link = preg_replace('/utm_(\\w+)\\=[^&]+/', '', $link); } ## 16894 make sure to keep the fragment value at the end of the URL if (strpos($link, '#')) { list($tmplink, $fragment) = explode('#', $link); $link = $tmplink; unset($tmplink); $fragment = '#' . $fragment; } else { $fragment = ''; } if (strpos($link, '?')) { $newurl = $link . '&' . $trackingcode . $fragment; } else { $newurl = $link . '?' . $trackingcode . $fragment; } $newlinks[$i] = $newurl; $textmessage = str_replace($links[1][$i], '[%%%' . $i . '%%%]', $textmessage); } } foreach ($newlinks as $linkid => $newlink) { $textmessage = str_replace('[%%%' . $linkid . '%%%]', $newlink, $textmessage); } unset($newlinks); } # print htmlspecialchars($htmlmessage);exit; #0011996: forward to friend - personal message if (FORWARD_PERSONAL_NOTE_SIZE && $hash == 'forwarded' && !empty($forwardedby['personalNote'])) { $htmlmessage = nl2br($forwardedby['personalNote']) . '<br/>' . $htmlmessage; $textmessage = $forwardedby['personalNote'] . "\n" . $textmessage; } if (VERBOSE && $getspeedstats) { output('cleanup start'); } ## allow fallback to default value for the ones that do not have a value ## delimiter is %% to avoid interfering with markup preg_match_all('/\\[.*\\%\\%([^\\]]+)\\]/Ui', $htmlmessage, $matches); for ($i = 0; $i < count($matches[0]); $i++) { $htmlmessage = str_ireplace($matches[0][$i], $matches[1][$i], $htmlmessage); } preg_match_all('/\\[.*\\%\\%([^\\]]+)\\]/Ui', $textmessage, $matches); for ($i = 0; $i < count($matches[0]); $i++) { $textmessage = str_ireplace($matches[0][$i], $matches[1][$i], $textmessage); } ## remove any remaining placeholders ## 16671 - do not do this, as it'll remove conditional CSS and other stuff ## that we'd like to keep //$htmlmessage = preg_replace("/\[[A-Z\. ]+\]/i","",$htmlmessage); //$textmessage = preg_replace("/\[[A-Z\. ]+\]/i","",$textmessage); # print htmlspecialchars($htmlmessage);exit; # check that the HTML message as proper <head> </head> and <body> </body> tags # some readers fail when it doesn't if (!preg_match("#<body.*</body>#ims", $htmlmessage)) { $htmlmessage = '<body>' . $htmlmessage . '</body>'; } if (!preg_match("#<head.*</head>#ims", $htmlmessage)) { if (!$adddefaultstyle) { $defaultstyle = ""; } $htmlmessage = '<head> <meta content="text/html;charset=' . $cached[$messageid]["html_charset"] . '" http-equiv="Content-Type"> <title></title>' . $defaultstyle . '</head>' . $htmlmessage; } if (!preg_match("#<html.*</html>#ims", $htmlmessage)) { $htmlmessage = '<html>' . $htmlmessage . '</html>'; } ## remove trailing code after </html> $htmlmessage = preg_replace('#</html>.*#msi', '</html>', $htmlmessage); ## the editor sometimes places <p> and </p> around the URL $htmlmessage = str_ireplace('<p><!DOCTYPE', '<!DOCTYPE', $htmlmessage); $htmlmessage = str_ireplace('</html></p>', '</html>', $htmlmessage); if (VERBOSE && $getspeedstats) { output('cleanup end'); } # $htmlmessage = compressContent($htmlmessage); # print htmlspecialchars($htmlmessage);exit; if ($getspeedstats) { output('build Start ' . $GLOBALS['processqueue_timer']->interval(1)); } # build the email $mail = new PHPlistMailer($messageid, $destinationemail); if ($forwardedby) { $mail->add_timestamp(); } $mail->addCustomHeader("List-Help: <" . $text["preferences"] . ">"); $mail->addCustomHeader("List-Unsubscribe: <" . $text["jumpoffurl"] . ">"); $mail->addCustomHeader("List-Subscribe: <" . getConfig("subscribeurl") . ">"); $mail->addCustomHeader("List-Owner: <mailto:" . getConfig("admin_address") . ">"); list($dummy, $domaincheck) = explode('@', $destinationemail); $text_domains = explode("\n", trim(getConfig("alwayssendtextto"))); if (in_array($domaincheck, $text_domains)) { $htmlpref = 0; if (VERBOSE) { output($GLOBALS['I18N']->get('sendingtextonlyto') . " {$domaincheck}"); } } foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { # $textmessage = $plugin->parseOutgoingTextMessage($messageid,$textmessage,$destinationemail, $userdata); # $htmlmessage = $plugin->parseOutgoingHTMLMessage($messageid,$htmlmessage,$destinationemail, $userdata); $plugin_attachments = $plugin->getMessageAttachment($messageid, $mail->Body); if (!empty($plugin_attachments[0]['content'])) { foreach ($plugins_attachments as $plugin_attachment) { $mail->add_attachment($plugin_attachment['content'], basename($plugin_attachment["filename"]), $plugin_attachment["mimetype"]); } } } # so what do we actually send? switch ($cached[$messageid]["sendformat"]) { case "PDF": # send a PDF file to users who want html and text to everyone else foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { $plugin->processSuccesFailure($messageid, 'astext', $userdata); } if ($htmlpref) { if (!$isTestMail) { Sql_Query("update {$GLOBALS["tables"]["message"]} set aspdf = aspdf + 1 where id = {$messageid}"); } $pdffile = createPdf($textmessage); if (is_file($pdffile) && filesize($pdffile)) { $fp = fopen($pdffile, "r"); if ($fp) { $contents = fread($fp, filesize($pdffile)); fclose($fp); unlink($pdffile); $html = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title></title> </head> <body> <embed src="message.pdf" width="450" height="450" href="message.pdf"></embed> </body> </html>'; # $mail->add_html($html,$textmessage); # $mail->add_text($textmessage); $mail->add_attachment($contents, "message.pdf", "application/pdf"); } } if (!addAttachments($messageid, $mail, "HTML")) { return 0; } } else { if (!$isTestMail) { Sql_Query("update {$GLOBALS["tables"]["message"]} set astext = astext + 1 where id = {$messageid}"); } $mail->add_text($textmessage); if (!addAttachments($messageid, $mail, "text")) { return 0; } } break; case "text and PDF": foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { $plugin->processSuccesFailure($messageid, 'astext', $userdata); } # send a PDF file to users who want html and text to everyone else if ($htmlpref) { if (!$isTestMail) { Sql_Query("update {$GLOBALS["tables"]["message"]} set astextandpdf = astextandpdf + 1 where id = {$messageid}"); } $pdffile = createPdf($textmessage); if (is_file($pdffile) && filesize($pdffile)) { $fp = fopen($pdffile, "r"); if ($fp) { $contents = fread($fp, filesize($pdffile)); fclose($fp); unlink($pdffile); $html = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title></title> </head> <body> <embed src="message.pdf" width="450" height="450" href="message.pdf"></embed> </body> </html>'; # $mail->add_html($html,$textmessage); $mail->add_text($textmessage); $mail->add_attachment($contents, "message.pdf", "application/pdf"); } } if (!addAttachments($messageid, $mail, "HTML")) { return 0; } } else { if (!$isTestMail) { Sql_Query("update {$GLOBALS["tables"]["message"]} set astext = astext + 1 where id = {$messageid}"); } $mail->add_text($textmessage); if (!addAttachments($messageid, $mail, "text")) { return 0; } } break; case "text": # send as text foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { $plugin->processSuccesFailure($messageid, 'astext', $userdata); } if (!$isTestMail) { Sql_Query("update {$GLOBALS["tables"]["message"]} set astext = astext + 1 where id = {$messageid}"); } $mail->add_text($textmessage); if (!addAttachments($messageid, $mail, "text")) { return 0; } break; case "both": case "text and HTML": case "HTML": default: $handled_by_plugin = 0; if (!empty($GLOBALS['pluginsendformats'][$cached[$messageid]["sendformat"]])) { # possibly handled by plugin $pl = $GLOBALS['plugins'][$GLOBALS['pluginsendformats'][$cached[$messageid]["sendformat"]]]; if (is_object($pl) && method_exists($pl, 'parseFinalMessage')) { $handled_by_plugin = $pl->parseFinalMessage($cached[$messageid]["sendformat"], $htmlmessage, $textmessage, $mail, $messageid); } } if (!$handled_by_plugin) { # send one big file to users who want html and text to everyone else if ($htmlpref) { if (!$isTestMail) { Sql_Query("update {$GLOBALS["tables"]["message"]} set astextandhtml = astextandhtml + 1 where id = {$messageid}"); } foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { $plugin->processSuccesFailure($messageid, 'ashtml', $userdata); } # dbg("Adding HTML ".$cached[$messageid]["templateid"]); if (WORDWRAP_HTML) { ## wrap it: http://mantis.phplist.com/view.php?id=15528 ## some reports say, this fixes things and others say it breaks things https://mantis.phplist.com/view.php?id=15617 ## so for now, only switch on if requested. ## it probably has to do with the MTA used $htmlmessage = wordwrap($htmlmessage, WORDWRAP_HTML, "\r\n"); } $mail->add_html($htmlmessage, $textmessage, $cached[$messageid]["templateid"]); if (!addAttachments($messageid, $mail, "HTML")) { return 0; } } else { if (!$isTestMail) { Sql_Query("update {$GLOBALS["tables"]["message"]} set astext = astext + 1 where id = {$messageid}"); } foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { $plugin->processSuccesFailure($messageid, 'astext', $userdata); } $mail->add_text($textmessage); # $mail->setText($textmessage); # $mail->Encoding = TEXTEMAIL_ENCODING; if (!addAttachments($messageid, $mail, "text")) { return 0; } } } break; } # print htmlspecialchars($htmlmessage);exit; if (!TEST) { if ($hash != 'forwarded' || !sizeof($forwardedby)) { $fromname = $cached[$messageid]["fromname"]; $fromemail = $cached[$messageid]["fromemail"]; $subject = $cached[$messageid]["subject"]; } else { $fromname = ''; $fromemail = $forwardedby['email']; $subject = $GLOBALS['strFwd'] . ': ' . $cached[$messageid]["subject"]; } if (!empty($cached[$messageid]["replytoemail"])) { $mail->AddReplyTo($cached[$messageid]["replytoemail"], $cached[$messageid]["replytoname"]); } if ($getspeedstats) { output('build End ' . $GLOBALS['processqueue_timer']->interval(1)); } if ($getspeedstats) { output('send Start ' . $GLOBALS['processqueue_timer']->interval(1)); } if (!empty($GLOBALS['developer_email'])) { $destinationemail = $GLOBALS['developer_email']; } $sendOK = false; if (!$mail->compatSend("", $destinationemail, $fromname, $fromemail, $subject)) { foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { $plugin->processSendFailed($messageid, $userdata, $isTestMail); } output(sprintf(s('Error sending message %d (%d/%d) to %s (%s) '), $messageid, $counters['batch_count'], $counters['batch_total'], $email, $destinationemail), 0); } else { $sendOK = true; foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { $plugin->processSendSuccess($messageid, $userdata, $isTestMail); } } if ($getspeedstats) { output('send End ' . $GLOBALS['processqueue_timer']->interval(1)); } if (!empty($mail->mailsize)) { $sizename = $htmlpref ? 'htmlsize' : 'textsize'; if (empty($cached[$messageid][$sizename])) { Sql_Replace($GLOBALS['tables']['messagedata'], array('id' => $messageid, 'name' => $sizename, 'data' => $mail->mailsize), array('name', 'id')); $cached[$messageid][$sizename] = $mail->mailsize; if (isset($cached[$messageid]['htmlsize'])) { output(sprintf(s('Size of HTML email: %s ', formatBytes($cached[$messageid]['htmlsize']))), 0, 'progress'); } if (isset($cached[$messageid]['textsize'])) { output(sprintf(s('Size of Text email: %s ', formatBytes($cached[$messageid]['textsize']))), 0, 'progress'); } } } if (defined('MAX_MAILSIZE') && isset($cached[$messageid]['htmlsize']) && $cached[$messageid]['htmlsize'] > MAX_MAILSIZE) { logEvent(s('Message too large (%s is over %s), suspending', $cached[$messageid]['htmlsize'], MAX_MAILSIZE)); if ($isTestMail) { $_SESSION['action_result'] = s('Warning: the final message exceeds the sending limit, this campaign will fail sending. Reduce the size by removing attachments or images'); } else { Sql_Query(sprintf('update %s set status = "suspended" where id = %d', $GLOBALS['tables']['message'], $messageid)); logEvent(s('Campaign %d suspended. Message too large', $messageid)); foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { $plugin->processError(s('Campaign %d suspended, message too large', $messageid)); } } } $sqlCount = $GLOBALS["pagestats"]["number_of_queries"] - $sqlCountStart; if ($getspeedstats) { output('It took ' . $sqlCount . ' queries to send this message'); } return $sendOK; } return 0; }
return; } $counters['batch_total'] = $counters['num_per_batch']; $counters['failed_sent'] = 0; $counters['invalid'] = 0; $counters['sent'] = 0; if (0 && $reload) { processQueueOutput(s('Sent in last run') . ": {$lastsent}", 0, 'progress'); processQueueOutput(s('Skipped in last run') . ": {$lastskipped}", 0, 'progress'); } $script_stage = 1; # we are active $notsent = $unconfirmed = $cannotsend = 0; ## check for messages that need requeuing $req = Sql_Query(sprintf('select id from %s where requeueinterval > 0 and requeueuntil > now() and status = "sent"', $tables['message'])); while ($msg = Sql_Fetch_Assoc($req)) { Sql_query(sprintf('UPDATE %s SET status = "submitted", sendstart = null, embargo = embargo + INTERVAL (FLOOR(TIMESTAMPDIFF(MINUTE, embargo, GREATEST(embargo, NOW())) / requeueinterval) + 1) * requeueinterval MINUTE WHERE id = %d', $GLOBALS['tables']['message'], $msg['id'])); foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { $plugin->messageReQueued($msg['id']); } ## @@@ need to update message data as well } $messagelimit = ''; ## limit the number of campaigns to work on if (defined('MAX_PROCESS_MESSAGE')) { $messagelimit = sprintf(' limit %d ', MAX_PROCESS_MESSAGE);
function getPageLock($force = 0) { global $tables; $thispage = $GLOBALS['page']; if ($thispage == 'pageaction') { $thispage = $_GET['action']; } $thispage = preg_replace('/\\W/', '', $thispage); # cl_output('getting pagelock '.$thispage); # ob_end_flush(); if ($GLOBALS['commandline'] && $thispage == 'processqueue') { if (is_object($GLOBALS['MC'])) { ## multi-send requires a valid memcached setup $max = MAX_SENDPROCESSES; } else { $max = 1; } } else { $max = 1; } ## allow killing other processes if ($force) { Sql_query('delete from ' . $tables['sendprocess'] . ' where page = "' . sql_escape($thispage) . '"'); } $running_req = Sql_query(sprintf('select now() - modified as age,id from %s where page = "%s" and alive order by started desc', $tables['sendprocess'], sql_escape($thispage))); $count = Sql_Num_Rows($running_req); $running_res = Sql_Fetch_Assoc($running_req); $waited = 0; # while ($running_res['age'] && $count >= $max) { # a process is already running while ($count >= $max) { # don't check age, as it may be 0 # cl_output('running process: '.$running_res['age'].' '.$max); if ($running_res['age'] > 600) { # some sql queries can take quite a while #cl_output($running_res['id'].' is old '.$running_res['age']); # process has been inactive for too long, kill it Sql_query("update {$tables['sendprocess']} set alive = 0 where id = " . $running_res['id']); } elseif ((int) $count >= (int) $max) { # cl_output (sprintf($GLOBALS['I18N']->get('A process for this page is already running and it was still alive %s seconds ago'),$running_res['age'])); output(s('A process for this page is already running and it was still alive %d seconds ago', $running_res['age']), 0); sleep(1); # to log the messages in the correct order if ($GLOBALS['commandline']) { cl_output(s('A process for this page is already running and it was still alive %d seconds ago', $running_res['age']), 0); cl_output($GLOBALS['I18N']->get('Running commandline, quitting. We\'ll find out what to do in the next run.')); exit; } output($GLOBALS['I18N']->get('Sleeping for 20 seconds, aborting will quit'), 0); flush(); $abort = ignore_user_abort(0); sleep(20); } ++$waited; if ($waited > 10) { # we have waited 10 cycles, abort and quit script output($GLOBALS['I18N']->get('We have been waiting too long, I guess the other process is still going ok'), 0); return false; } $running_req = Sql_query('select now() - modified,id from ' . $tables['sendprocess'] . " where page = \"{$thispage}\" and alive order by started desc"); $count = Sql_Num_Rows($running_req); $running_res = Sql_Fetch_row($running_req); } if (!empty($GLOBALS['commandline'])) { $processIdentifier = SENDPROCESS_SERVERNAME . ':' . getmypid(); } else { $processIdentifier = $_SERVER['REMOTE_ADDR']; } $res = Sql_query('insert into ' . $tables['sendprocess'] . ' (started,page,alive,ipaddress) values(now(),"' . $thispage . '",1,"' . $processIdentifier . '")'); $send_process_id = Sql_Insert_Id(); $abort = ignore_user_abort(1); # cl_output('Got pagelock '.$send_process_id ); return $send_process_id; }
function getPageLock($force = 0) { global $tables; $thispage = $GLOBALS["page"]; if ($thispage == 'pageaction') { $thispage = $_GET['action']; } # cl_output('getting pagelock '.$thispage); # ob_end_flush(); if ($GLOBALS["commandline"] && $thispage == 'processqueue') { if (is_object($GLOBALS['MC'])) { ## multi-send requires a valid memcached setup $max = MAX_SENDPROCESSES; } else { $max = 1; } } else { $max = 1; } ## allow killing other processes if ($force) { Sql_Query_Params("delete from " . $tables['sendprocess'] . " where page = ?", array($thispage)); } $query = ' select current_timestamp - modified as age, id' . ' from ' . $tables['sendprocess'] . ' where page = ?' . ' and alive > 0' . ' order by age desc'; $running_req = Sql_Query_Params($query, array($thispage)); $running_res = Sql_Fetch_Assoc($running_req); $count = Sql_Num_Rows($running_req); if (VERBOSE) { cl_output($count . ' out of ' . $max . ' active processes'); } $waited = 0; # while ($running_res['age'] && $count >= $max) { # a process is already running while ($count >= $max) { # don't check age, as it may be 0 # cl_output('running process: '.$running_res['age'].' '.$max); if ($running_res['age'] > 600) { # some sql queries can take quite a while #cl_output($running_res['id'].' is old '.$running_res['age']); # process has been inactive for too long, kill it Sql_query("update {$tables["sendprocess"]} set alive = 0 where id = " . $running_res['id']); } elseif ((int) $count >= (int) $max) { # cl_output (sprintf($GLOBALS['I18N']->get('A process for this page is already running and it was still alive %s seconds ago'),$running_res['age'])); output(sprintf($GLOBALS['I18N']->get('A process for this page is already running and it was still alive %s seconds ago'), $running_res['age']), 0); sleep(1); # to log the messages in the correct order if ($GLOBALS["commandline"]) { cl_output($GLOBALS['I18N']->get('Running commandline, quitting. We\'ll find out what to do in the next run.')); exit; } output($GLOBALS['I18N']->get('Sleeping for 20 seconds, aborting will quit'), 0); flush(); $abort = ignore_user_abort(0); sleep(20); } $waited++; if ($waited > 10) { # we have waited 10 cycles, abort and quit script output($GLOBALS['I18N']->get('We have been waiting too long, I guess the other process is still going ok'), 0); return false; } $query = ' select current_timestamp - modified as age, id' . ' from ' . $tables['sendprocess'] . ' where page = ?' . ' and alive > 0' . ' order by age desc'; $running_req = Sql_Query_Params($query, array($thispage)); $running_res = Sql_Fetch_Assoc($running_req); $count = Sql_Num_Rows($running_req); } $query = ' insert into ' . $tables['sendprocess'] . ' (started, page, alive, ipaddress)' . ' values' . ' (current_timestamp, ?, 1, ?)'; if (!empty($GLOBALS['commandline'])) { $processIdentifier = SENDPROCESS_SERVERNAME . ':' . getmypid(); } else { $processIdentifier = $_SERVER['REMOTE_ADDR']; } $res = Sql_Query_Params($query, array($thispage, $processIdentifier)); $send_process_id = Sql_Insert_Id($tables['sendprocess'], 'id'); $abort = ignore_user_abort(1); # cl_output('Got pagelock '.$send_process_id ); return $send_process_id; }
case "mbox": $download_report = processMbox($bounce_mailbox); break; default: Error($GLOBALS['I18N']->get("bounce_protocol not supported")); return; } # now we have filled database with all available bounces ## reprocess the unidentified ones, as the bounce detection has improved, so it might catch more cl_output('reprocessing'); $reparsed = $count = 0; $reidentified = 0; $req = Sql_Query(sprintf('select * from %s where status = "unidentified bounce"', $tables['bounce'])); $total = Sql_Affected_Rows(); cl_output(s('%d bounces to reprocess', $total)); while ($bounce = Sql_Fetch_Assoc($req)) { $count++; if ($count % 25 == 0) { cl_progress(s('%d out of %d processed', $count, $total)); } $bounceBody = decodeBody($bounce['header'], $bounce['data']); $userid = findUserID($bounceBody); $messageid = findMessageId($bounceBody); if (!empty($userid) || !empty($messageid)) { $reparsed++; if (processBounceData($bounce['id'], $messageid, $userid)) { $reidentified++; } } } cl_output(s('%d out of %d processed', $count, $total));
. ' from ' . $tables['list'] . $subselect . ' order by listorder '.$limit; $result = Sql_query($query); */ } while ($row = Sql_fetch_array($result)) { ## we only consider confirmed and not blacklisted subscribers members of a list ## we assume "confirmed" to be 1 or 0, so that the sum gives the total confirmed ## could be incorrect, as 1000 is also "true" but will be ok (saves a few queries) ## same with blacklisted, but we're disregarding that for now, because blacklisted subscribers should not ## be on the list at all. ## @@TODO increase accuracy, without adding loads of queries. $query = ' select count(u.id) as total,' . ' sum(u.confirmed) as confirmed, ' . ' sum(u.blacklisted) as blacklisted ' . ' from ' . $tables['listuser'] . ' lu, ' . $tables['user'] . ' u where u.id = lu.userid and listid = ? '; $req = Sql_Query_Params($query, array($row["id"])); $membercount = Sql_Fetch_Assoc($req); $members = $membercount['confirmed']; $unconfirmedMembers = (int) ($membercount['total'] - $members); $desc = stripslashes($row['description']); if ($unconfirmedMembers > 0) { $membersDisplay = '<span class="memberCount">' . $members . '</span> <span class="unconfirmedCount">(' . $unconfirmedMembers . ')</span>'; } else { $membersDisplay = '<span class="memberCount">' . $members . '</span>'; } //## allow plugins to add columns // @@@ TODO review this //foreach ($GLOBALS['plugins'] as $plugin) { //$desc = $plugin->displayLists($row) . $desc; //} $element = '<!-- ' . $row['id'] . '-->' . stripslashes($row['name']); $ls->addElement($element);
$ls->addColumn($element, ' ', shortenTextDisplay($messagedata['subject'], 30)); $element = ucfirst(s('Date entered')); $ls->addElement($element); $ls->addColumn($element, ' ', $messagedata['entered']); $element = ucfirst(s('Date sent')); $ls->addElement($element); $ls->addColumn($element, ' ', $messagedata['sent']); $element = ucfirst(s('Sent as HTML')); $ls->addElement($element); $ls->addColumn($element, ' ', $messagedata['astextandhtml']); $element = ucfirst(s('Sent as text')); $ls->addElement($element); $ls->addColumn($element, ' ', $messagedata['astext']); $totalSent = 0; $sentQ = Sql_Query(sprintf('select status,count(userid) as num from %s where messageid = %d group by status', $tables['usermessage'], $id)); while ($row = Sql_Fetch_Assoc($sentQ)) { $element = ucfirst($row['status']); $ls->addElement($element); $ls->addColumn($element, ' ', $row['num']); if ($row['status'] == 'sent') { $totalSent = $row['num']; } } /* $element = ucfirst(s('Bounced')); $ls->addElement($element); $ls->addColumn($element,' ',$messagedata['bouncecount']); */ $bounced = Sql_Fetch_Row_Query(sprintf('select count(distinct user) from %s where message = %d', $tables['user_message_bounce'], $id)); $element = ucfirst(s('Bounced')); $ls->addElement($element);
function precacheMessage($messageid, $forwardContent = 0) { global $cached, $tables; $domain = getConfig('domain'); # $message = Sql_query("select * from {$GLOBALS["tables"]["message"]} where id = $messageid"); # $cached[$messageid] = array(); # $message = Sql_fetch_array($message); $message = loadMessageData($messageid); ## the reply to is actually not in use if (preg_match('/([^ ]+@[^ ]+)/', $message['replyto'], $regs)) { # if there is an email in the from, rewrite it as "name <email>" $message['replyto'] = str_replace($regs[0], '', $message['replyto']); $cached[$messageid]['replytoemail'] = $regs[0]; # if the email has < and > take them out here $cached[$messageid]['replytoemail'] = str_replace('<', '', $cached[$messageid]['replytoemail']); $cached[$messageid]['replytoemail'] = str_replace('>', '', $cached[$messageid]['replytoemail']); # make sure there are no quotes around the name $cached[$messageid]['replytoname'] = str_replace('"', '', ltrim(rtrim($message['replyto']))); } elseif (strpos($message['replyto'], ' ')) { # if there is a space, we need to add the email $cached[$messageid]['replytoname'] = $message['replyto']; $cached[$messageid]['replytoemail'] = "listmaster@{$domain}"; } else { if (!empty($message['replyto'])) { $cached[$messageid]['replytoemail'] = $message['replyto'] . "@{$domain}"; ## makes more sense not to add the domain to the word, but the help says it does ## so let's keep it for now $cached[$messageid]['replytoname'] = $message['replyto'] . "@{$domain}"; } } $cached[$messageid]['fromname'] = $message['fromname']; $cached[$messageid]['fromemail'] = $message['fromemail']; $cached[$messageid]['to'] = $message['tofield']; #0013076: different content when forwarding 'to a friend' $cached[$messageid]['subject'] = $forwardContent ? stripslashes($message['forwardsubject']) : $message['subject']; #0013076: different content when forwarding 'to a friend' $cached[$messageid]['content'] = $forwardContent ? stripslashes($message['forwardmessage']) : $message['message']; if (USE_MANUAL_TEXT_PART && !$forwardContent) { $cached[$messageid]['textcontent'] = $message['textmessage']; } else { $cached[$messageid]['textcontent'] = ''; } # var_dump($cached);exit; #0013076: different content when forwarding 'to a friend' $cached[$messageid]['footer'] = $forwardContent ? stripslashes($message['forwardfooter']) : $message['footer']; if (strip_tags($cached[$messageid]['footer']) != $cached[$messageid]['footer']) { $cached[$messageid]['textfooter'] = HTML2Text($cached[$messageid]['footer']); $cached[$messageid]['htmlfooter'] = $cached[$messageid]['footer']; } else { $cached[$messageid]['textfooter'] = $cached[$messageid]['footer']; $cached[$messageid]['htmlfooter'] = parseText($cached[$messageid]['footer']); } $cached[$messageid]['htmlformatted'] = strip_tags($cached[$messageid]['content']) != $cached[$messageid]['content']; $cached[$messageid]['sendformat'] = $message['sendformat']; if ($message['template']) { $req = Sql_Fetch_Row_Query("select template from {$GLOBALS['tables']['template']} where id = {$message['template']}"); $cached[$messageid]['template'] = stripslashes($req[0]); $cached[$messageid]['templateid'] = $message['template']; # dbg("TEMPLATE: ".$req[0]); } else { $cached[$messageid]['template'] = ''; $cached[$messageid]['templateid'] = 0; } ## @@ put this here, so it can become editable per email sent out at a later stage $cached[$messageid]['html_charset'] = 'UTF-8'; #getConfig("html_charset"); ## @@ need to check on validity of charset if (!$cached[$messageid]['html_charset']) { $cached[$messageid]['html_charset'] = 'UTF-8'; #'iso-8859-1'; } $cached[$messageid]['text_charset'] = 'UTF-8'; #getConfig("text_charset"); if (!$cached[$messageid]['text_charset']) { $cached[$messageid]['text_charset'] = 'UTF-8'; #'iso-8859-1'; } ## if we are sending a URL that contains user attributes, we cannot pre-parse the message here ## but that has quite some impact on speed. So check if that's the case and apply $cached[$messageid]['userspecific_url'] = preg_match('/\\[.+\\]/', $message['sendurl']); if (!$cached[$messageid]['userspecific_url']) { ## Fetch external content here, because URL does not contain placeholders if ($GLOBALS['can_fetchUrl'] && preg_match("/\\[URL:([^\\s]+)\\]/i", $cached[$messageid]['content'], $regs)) { $remote_content = fetchUrl($regs[1], array()); # $remote_content = fetchUrl($message['sendurl'],array()); # @@ don't use this # $remote_content = includeStyles($remote_content); if ($remote_content) { $cached[$messageid]['content'] = str_replace($regs[0], $remote_content, $cached[$messageid]['content']); # $cached[$messageid]['content'] = $remote_content; $cached[$messageid]['htmlformatted'] = strip_tags($remote_content) != $remote_content; ## 17086 - disregard any template settings when we have a valid remote URL $cached[$messageid]['template'] = null; $cached[$messageid]['templateid'] = null; } else { #print Error(s('unable to fetch web page for sending')); logEvent('Error fetching URL: ' . $message['sendurl'] . ' cannot proceed'); return false; } } if (VERBOSE && !empty($GLOBALS['getspeedstats'])) { output('fetch URL end'); } /* print $message['sendurl']; print $remote_content;exit; */ } // end if not userspecific url if ($cached[$messageid]['htmlformatted']) { # $cached[$messageid]["content"] = compressContent($cached[$messageid]["content"]); } $cached[$messageid]['google_track'] = $message['google_track']; /* else { print $message['sendurl']; exit; } */ foreach ($GLOBALS['plugins'] as $plugin) { $plugin->processPrecachedCampaign($messageid, $cached[$messageid]); } if (VERBOSE && !empty($GLOBALS['getspeedstats'])) { output('parse config start'); } /* * this is not a good idea, as it'll replace eg "unsubscribeurl" with a general one instead of personalised * if (is_array($GLOBALS["default_config"])) { foreach($GLOBALS["default_config"] as $key => $val) { if (is_array($val)) { $cached[$messageid]['content'] = str_ireplace("[$key]",getConfig($key),$cached[$messageid]['content']); $cached[$messageid]["textcontent"] = str_ireplace("[$key]",getConfig($key),$cached[$messageid]["textcontent"]); $cached[$messageid]["textfooter"] = str_ireplace("[$key]",getConfig($key),$cached[$messageid]['textfooter']); $cached[$messageid]["htmlfooter"] = str_ireplace("[$key]",getConfig($key),$cached[$messageid]['htmlfooter']); } } } */ if (VERBOSE && !empty($GLOBALS['getspeedstats'])) { output('parse config end'); } ## ##17233 not that many fields are actually useful, so don't blatantly use all # foreach($message as $key => $val) { foreach (array('subject', 'id', 'fromname', 'fromemail') as $key) { $val = $message[$key]; if (!is_array($val)) { $cached[$messageid]['content'] = str_ireplace("[{$key}]", $val, $cached[$messageid]['content']); $cached[$messageid]['textcontent'] = str_ireplace("[{$key}]", $val, $cached[$messageid]['textcontent']); $cached[$messageid]['textfooter'] = str_ireplace("[{$key}]", $val, $cached[$messageid]['textfooter']); $cached[$messageid]['htmlfooter'] = str_ireplace("[{$key}]", $val, $cached[$messageid]['htmlfooter']); } } /* * cache message owner and list owner attribute values */ $cached[$messageid]['adminattributes'] = array(); $result = Sql_Query("SELECT a.name, aa.value\n FROM {$tables['adminattribute']} a\n JOIN {$tables['admin_attribute']} aa ON a.id = aa.adminattributeid\n JOIN {$tables['message']} m ON aa.adminid = m.owner\n WHERE m.id = {$messageid}"); if ($result !== false) { while ($att = Sql_Fetch_Array($result)) { $cached[$messageid]['adminattributes']['OWNER.' . $att['name']] = $att['value']; } } $result = Sql_Query("SELECT DISTINCT l.owner\n FROM {$tables['list']} AS l\n JOIN {$tables['listmessage']} AS lm ON lm.listid = l.id\n WHERE lm.messageid = {$messageid}"); if ($result !== false && Sql_Num_Rows($result) == 1) { $row = Sql_Fetch_Assoc($result); $listOwner = $row['owner']; $att_req = Sql_Query("SELECT a.name, aa.value\n FROM {$tables['adminattribute']} a\n JOIN {$tables['admin_attribute']} aa ON a.id = aa.adminattributeid\n WHERE aa.adminid = {$listOwner}"); while ($att = Sql_Fetch_Array($att_req)) { $cached[$messageid]['adminattributes']['LISTOWNER.' . $att['name']] = $att['value']; } } $baseurl = $GLOBALS['website']; if (defined('UPLOADIMAGES_DIR') && UPLOADIMAGES_DIR) { ## escape subdirectories, otherwise this renders empty $dir = str_replace('/', '\\/', UPLOADIMAGES_DIR); $cached[$messageid]['content'] = preg_replace('/<img(.*)src="\\/' . $dir . '(.*)>/iU', '<img\\1src="' . $GLOBALS['public_scheme'] . '://' . $baseurl . '/' . UPLOADIMAGES_DIR . '\\2>', $cached[$messageid]['content']); } foreach (array('content', 'template', 'htmlfooter') as $element) { $cached[$messageid][$element] = parseLogoPlaceholders($cached[$messageid][$element]); } return 1; }
} else { print '<p>' . $GLOBALS['I18N']->get('None found') . '</p>'; } return; } $query = sprintf('select lu.userid, count(umb.bounce) as numbounces from %s lu join %s umb on lu.userid = umb.user where ' . ' lu.listid = %d group by lu.userid ', $GLOBALS['tables']['listuser'], $GLOBALS['tables']['user_message_bounce'], $listid); $req = Sql_Query($query); $total = Sql_Affected_Rows(); $limit = ''; $numpp = 150; $selectOtherlist = new buttonGroup(new Button(PageUrl2('listbounces'), $GLOBALS['I18N']->get('Select another list'))); $lists = Sql_Query(sprintf('select id,name from %s list %s order by listorder', $tables['list'], $isowner_where)); while ($list = Sql_Fetch_Assoc($lists)) { $selectOtherlist->addButton(new Button(PageUrl2('listbounces') . '&id=' . $list['id'], htmlspecialchars($list['name']))); } print $selectOtherlist->show(); if ($total) { print PageLinkButton('listbounces&type=dl&id=' . $listid, 'Download emails'); } print '<p>' . s('%d bounces to list %s', $total, listName($listid)) . '</p>'; $start = empty($_GET['start']) ? 0 : sprintf('%d', $_GET['start']); if ($total > $numpp && !$download) { # print Paging2('listbounces&id='.$listid,$total,$numpp,'Page'); # $listing = sprintf($GLOBALS['I18N']->get("Listing %s to %s"),$s,$s+$numpp); $limit = "limit {$start}," . $numpp; print simplePaging('listbounces&id=' . $listid, $start, $total, $numpp); $query .= $limit; $req = Sql_Query($query);
function loadImageCache($messagedata = array()) { $this->curid = $messagedata['id']; $this->cache[$this->curid] = array(); // Make sure that the cache defined // even if no images $msgtbl = $GLOBALS['tables']['inlineImagePlugin_msg']; $imgtbl = $GLOBALS['tables']['inlineImagePlugin_image']; $query = sprintf('select original, imagetag, cid, type, file_name, local_name from %s natural join %s where id = %d', $msgtbl, $imgtbl, $this->curid); $result = Sql_Query($query); $i = 0; while ($row = Sql_Fetch_Assoc($result)) { $this->cache[$this->curid][$i] = $row; $this->cache[$this->curid][$i]['contents'] = file_get_contents($row['local_name']); $i++; } }