<?php
/**
* Fetch emails in background
* Needs the global / email specific setting for the MySQL database used
* @author Matthias Sommerfeld, phlyLabs Berlin
* @copyright 2001-2010 phlyLabs Berlin, http://phlylabs.de
* @version 4.1.8 2010-10-04
* @todo Implement handling of CatchAll here so we still have a single script the customer must run
*/
define('LF', "\n");
define('CRLF', "\r\n");
chdir('../');
define('VECHO', true);
define('_IN_PHM_', true);
set_magic_quotes_runtime(0);
set_time_limit(0);
$_PM_ = parse_ini_file('choices.ini.php', true);
error_reporting((isset($_PM_['core']['debugging_level']) && 'disabled' != $_PM_['core']['debugging_level']) ? E_ALL : 0);
// Global Choices, overloading core settings
if (file_exists($_PM_['path']['conf'].'/global.choices.ini.php')) {
$_PM_ = fetcher_merge_PM($_PM_, parse_ini_file($_PM_['path']['conf'].'/global.choices.ini.php', true));
}
$_PM_['core']['file_umask'] = octdec($_PM_['core']['file_umask']);
$_PM_['core']['dir_umask'] = octdec($_PM_['core']['dir_umask']);
@set_include_path(get_include_path().PATH_SEPARATOR.dirname(__FILE__).PATH_SEPARATOR.$_PM_['path']['lib']);
$smsactive = false;
$base_path = $_PM_['path']['storage'].'/$1';
$mail_path = 'email';
$inbox_name = 'inbox';
$junk_name = 'junk';
$temp_name = '.tmp';
$opt_name = '.opt';
$spamassassin = $_PM_['antijunk']['cmd_check'];
$spamcheck_maxsize = '51200';
$AlertSMS = array();
$AlertEmail = array();
require_once($_PM_['path']['lib'].'/pop3.inc.php');
require_once($_PM_['path']['lib'].'/imap.inc.php');
require_once($_PM_['path']['lib'].'/phm_streaming_mailparser.php');
require_once($_PM_['path']['lib'].'/functions.php');
require_once($_PM_['path']['lib'].'/basemethods.php');
require_once($_PM_['path']['lib'].'/uctc.php');
require_once($_PM_['path']['lib'].'/phm_streaming_sendmail.php');
require_once($_PM_['path']['lib'].'/phm_streaming_smtp.php');
require_once($_PM_['path']['lib'].'/idna_convert.class.php');
require_once($_PM_['path']['driver'].'/'.$_PM_['core']['database'].'/driver.php');
require_once($_PM_['path']['handler'].'/email/fs.php');
// Load SMS driver
if (isset($_PM_['core']['sms_feature_active']) && $_PM_['core']['sms_feature_active']) {
$usegwpath = $_PM_['path']['msggw'].'/'.$_PM_['core']['sms_use_gw'];
$gwcredentials = $_PM_['path']['conf'].'/msggw.'.$_PM_['core']['sms_use_gw'].'.ini.php';
require_once($usegwpath.'/phm_shortmessage.php');
$GW = new phm_shortmessage($usegwpath, $gwcredentials);
$smsactive = true;
}
// Preparations for external alerts
// Reading in all available messages files to get the relevant date formats
$d = opendir($_PM_['path']['message']);
while ($file = readdir($d)) {
if ('.' == $file) continue;
if ('..' == $file) continue;
if (!preg_match('/\.php$/i', trim($file))) continue;
$lang = preg_replace('/\.php$/i', '', trim($file));
require_once($_PM_['path']['message'].'/'.$file);
$dateformat[$lang] = $WP_msg['dateformat'];
// Reading in the templates for that language, if not there, try using the English one
if (file_exists('backend/pop3fetcher.alertemail.'.$lang.'.tpl')) {
$mailtpl[$lang] = file_get_contents('backend/pop3fetcher.alertemail.'.$lang.'.tpl');
} elseif (file_exists('backend/pop3fetcher.alertemail.en.tpl')) {
$mailtpl[$lang] = file_get_contents('backend/pop3fetcher.alertemail.en.tpl');
}
if ($smsactive && file_exists('backend/pop3fetcher.alertsms.'.$lang.'.tpl')) {
$smstpl[$lang] = file_get_contents('backend/pop3fetcher.alertsms.'.$lang.'.tpl');
} elseif ($smsactive && file_exists('backend/pop3fetcher.alertsms.en.tpl')) {
$smstpl[$lang] = file_get_contents('backend/pop3fetcher.alertsms.en.tpl');
}
}
if (isset($_PM_['core']['provider_name']) && $_PM_['core']['provider_name'] != '') $subject = $_PM_['core']['provider_name'];
$DB = new driver($_PM_['path']['conf'].'/driver.'.$_PM_['core']['database'].'.ini.php'
,(isset($_PM_['core']['accountpass_security']) && $_PM_['core']['accountpass_security'] == 'cleartext' ? false : true)
);
// Read all active users
foreach ($DB->get_usridx(null, 'active') as $uid => $name) {
$path = str_replace('$1', $uid, $base_path);
$FS = new email_storage($uid);
// Quotas: Check the space left and how many messages this user might store
$quota_size_storage = $DB->quota_get($uid, 'email', 'size_storage');
if (false !== $quota_size_storage) {
$quota_spaceleft = $FS->quota_getmailsize(false);
$quota_spaceleft = $quota_size_storage - $quota_spaceleft;
} else {
$quota_spaceleft = false;
}
$quota_number_mails = $DB->quota_get($uid, 'email', 'number_mails');
if (false !== $quota_number_mails) {
$quota_mailsleft = $FS->quota_getmailnum(false);
$quota_mailsleft = $quota_number_mails - $quota_mailsleft;
} else {
$quota_mailsleft = false;
}
// No more mails allowed to save
if ((false !== $quota_mailsleft && $quota_mailsleft < 1)
|| (false !== $quota_spaceleft && $quota_spaceleft < 1)) {
$quota_reached = true;
} else {
$quota_reached = false;
}
// End Quotas
// Index all profiles of the user
foreach ($DB->get_accidx($uid, null, true) as $pid => $account) {
$accdata = $DB->get_accdata($uid, null, $account['accid']);
// Quota exceeded, no longer check POP3 accounts for new mails during this period
if ($accdata['acctype'] == 'pop3' && $quota_reached) continue;
// Only active accounts with a check_every_n_minutes setting
if ($accdata['be_checkevery'] == 0) continue;
// Recheck time not reached yet
if (($accdata['logintime'] + $accdata['be_checkevery']*60) > time()) continue;
$login = $DB->get_popconnect($uid, null, $account['accid']);
if ($accdata['acctype'] == 'pop3') {
$CONN = new pop3($login['popserver'], $login['popport'], 0, ($login['popsec'] == 'auto'));
if (true !== $CONN->check_connected()) { // Connection failed
unset($CONN);
continue;
}
$status = $CONN->login($login['popuser'], $login['poppass'], ($login['popnoapop'] * -1));
if (!$status['login']) { // Login failed
$CONN->close();
unset($CONN);
continue;
}
$accdata['cachetype'] = 'full';
// Appropriate settings for this account: Check for mails deleted locally which now get killed on the POP3 server, too.
if ($accdata['leaveonserver'] && $accdata['localkillserver']) {
$localkills = $FS->uidlcache_getdeleted($pid);
if (!empty($localkills)) $CONN->delete_by_uidl($localkills);
}
} elseif ($accdata['acctype'] == 'imap') {
$CONN = new imap($login['popserver'], $login['popport'], 0, !$login['popnoapop']);
if (true !== $CONN->check_connected()) { // Connection failed
unset($CONN);
continue;
}
$status = $CONN->login($login['popuser'], $login['poppass'], 'INBOX', true);
if (!$status['login']) { // Login failed
$CONN->close();
unset($CONN);
continue;
}
$accdata['leaveonserver'] = 1;
/* Will be popped in later
if (isset($accdata['cachetype'])) {
$this->imap_cached_headers = ($accdata['cachetype'] == 'struct' || $accdata['cachetype'] == 'full');
$this->imap_cached_mail = ($accdata['cachetype'] == 'full');
} else {
$this->imap_cached_headers = $this->imap_cached_mail = false;
}*/
$accdata['cachetype'] = 'struct';
}
$DB->set_poplogintime($uid, $account['accid']);
$dbcache = $dbsizes = $attlist = $maillist = array();
foreach ($CONN->get_list() as $num => $flags) {
$maillist[$num] = $flags['uidl'];
$attlist[$num] = $flags;
}
if (empty($maillist)) {
if ($accdata['acctype'] == 'imap') {
list ($maillist, $deletelist) = $FS->uidlcache_match($pid, $maillist);
if (!empty($deletelist)) {
foreach ($deletelist as $idx => $ouidl) $FS->IDX->mail_delete($uid, $idx, false);
}
} elseif ($accdata['leaveonserver']) {
$FS->uidlcache_remove($pid);
}
$CONN->close();
unset($CONN);
continue;
}
if ($accdata['acctype'] == 'imap') {
$fileto = $FS->get_folder_id_from_path($pid.':INBOX');
$dbuidls = $FS->get_folder_uidllist($fileto, false, false, array('ouidl', 'hsize', 'read', 'forwarded', 'answered', 'bounced', 'colour'));
foreach ($dbuidls as $k => $v) {
$dbsizes[$v['ouidl']] = array
('size' => $v['hsize'], 'idx' => $k, 'rd' => $v['read'], 'wg' => $v['forwarded']
,'aw' => $v['answered'], 'bn' => $v['bounced'], 'cl' => $v['colour']
);
$dbcache[$k] = $v['ouidl'];
}
list ($maillist, $deletelist) = $FS->uidlcache_match(false, $maillist, $dbcache);
if (!empty($deletelist)) {
foreach ($deletelist as $idx => $ouidl) $FS->IDX->mail_delete($uid, $idx, false);
}
} else {
list ($maillist, $deletelist) = $FS->uidlcache_match($pid, $maillist);
}
$counter = 0;
foreach ($maillist as $num => $uidl) {
// These variables might get populated by the filtering mechanisms
$deferred_dele = $deferred_copy = $deferred_move = $deferred_junk = $deferred_status = $deferred_color = false;
// Prevent doublette downloads of mails
if ($accdata['leaveonserver']) {
list ($true) = $FS->uidlcache_checkitem($pid, $uidl);
if ($true) continue;
}
if ($accdata['acctype'] == 'imap') {
$fileto = $FS->get_folder_id_from_path($pid.':INBOX');
} else {
$fileto = $inbox_name;
}
$mailfile = uniqid(time().'.', true);
$mail_size = $attlist[$num]['size'];
$header['status'] = ($attlist[$num]['seen']) ? 1 : 0;
$header['answered'] = $attlist[$num]['answered'] ? 1 : 0;
$header['forwarded'] = isset($attlist[$num]['forwarded']) && $attlist[$num]['forwarded'] ? 1 : 0;
$header['bounced'] = isset($attlist[$num]['bounced']) && $attlist[$num]['bounced'] ? 1 : 0;
if ($_PM_['antijunk']['use_feature'] && $accdata['checkspam'] && $mail_size < $spamcheck_maxsize) {
$success = $CONN->retrieve_to_file($num, $path.'/'.$mail_path.'/'.$temp_name.'/'.$mailfile.'.in');
if (!$success) {
vecho($CONN->get_last_error());
continue;
}
$spamcomd = str_replace('$1', $path.'/'.$mail_path.'/'.$temp_name.'/'.$mailfile.'.in', $spamassassin);
$spamcomd = str_replace('$2', $path.'/'.$mail_path.'/'.$temp_name.'/'.$mailfile.'.out', $spamcomd);
exec($spamcomd, $void, $deferred_junk);
// Make sure, SA could be called and produced a tagged mail
if (file_exists($path.'/'.$mail_path.'/'.$temp_name.'/'.$mailfile.'.out')
&& is_readable($path.'/'.$mail_path.'/'.$temp_name.'/'.$mailfile.'.out')) {
// Read the mail structure
$mh = fopen($path.'/'.$mail_path.'/'.$temp_name.'/'.$mailfile.'.out', 'r');
list ($header, $struct) = mailparser::parse($mh);
unset($struct['last_line']);
$header['struct'] = serialize($struct);
$mail_size = filesize($path.'/'.$mail_path.'/'.$temp_name.'/'.$mailfile.'.out');
$header['folder_path'] = $fileto;
rename
($path.'/'.$mail_path.'/'.$temp_name.'/'.$mailfile.'.out'
,$path.'/'.$mail_path.'/'.(($accdata['cachetype'] != 'full') ? $temp_name : $fileto).'/'.$mailfile
);
unlink($path.'/'.$mail_path.'/'.$temp_name.'/'.$mailfile.'.in');
} else {
// Read the mail structure
$mh = fopen($path.'/'.$mail_path.'/'.$temp_name.'/'.$mailfile.'.in', 'r');
list ($header, $struct) = mailparser::parse($mh);
unset($struct['last_line']);
$header['struct'] = serialize($struct);
$mail_size = filesize($path.'/'.$mail_path.'/'.$temp_name.'/'.$mailfile.'.in');
$header['folder_path'] = $fileto;
rename
($path.'/'.$mail_path.'/'.$temp_name.'/'.$mailfile.'.in'
,$path.'/'.$mail_path.'/'.($accdata['cachetype'] != 'full' ? $temp_name : $fileto).'/'.$mailfile
);
}
$old_umask = umask(0);
chmod($path.'/'.$mail_path.'/'.($accdata['cachetype'] != 'full' ? $temp_name : $fileto).'/'.$mailfile, $_PM_['core']['file_umask']);
umask($old_umask);
} else {
$success = $CONN->retrieve_to_file($num, $path.'/'.$mail_path.'/'.($accdata['cachetype'] != 'full' ? $temp_name : $fileto).'/'.$mailfile);
if (!$success) {
vecho($CONN->get_last_error());
continue;
}
$mail_size = filesize($path.'/'.$mail_path.'/'.(($accdata['cachetype'] != 'full') ? $temp_name : $fileto).'/'.$mailfile);
$mh = fopen($path.'/'.$mail_path.'/'.(($accdata['cachetype'] != 'full') ? $temp_name : $fileto).'/'.$mailfile, 'r');
list ($header, $struct) = mailparser::parse($mh);
unset($struct['last_line']);
$header['struct'] = serialize($struct);
}
if ($header['spam_status']) $deferred_junk = true;
// Aplly filters on the mail, but only, if it is not already tagged as SPAM
if (!$deferred_junk) {
foreach ($FS->filters_getlist() as $filter) {
// Inactive?
if (!$filter['active']) continue;
// Get filter information, run method to check against the rules
$filter = $FS->filters_getfilter($filter['id']);
$hit = mailparser::apply_filter($header['complete'], $filter['match'], $filter['rules']);
// Rules did not hit
if (!$hit) continue;
//
// Obey the actions defined for the filter
//
// Delete the mail
if (isset($filter['delete']) && $filter['delete']) {
$deferred_dele = true;
break;
}
// Mark as junk
if ($_PM_['antijunk']['use_feature'] && isset($filter['mark_junk']) && $filter['mark_junk']) {
$deferred_junk = true;
}
// Switch read status
if (isset($filter['mark_read']) && $filter['mark_read']) {
$deferred_status = ('read' == $filter['markread_status']) ? 1 : 0;
}
// Switch priority
if (isset($filter['set_prio']) && $filter['set_prio']) {
$header['priority'] = $filter['new_prio'];
}
// Set a colour mark
if (isset($filter['set_colour']) && $filter['set_colour']) {
$deferred_color = $filter['new_colour'];
}
// Move somewhere else
if (isset($filter['move']) && $filter['move']) {
// Prevent moving the mail to a non-existent folder
$is_there = $FS->get_folder_info($filter['move_to']);
if (is_array($is_there) && $is_there['foldername'] !== false) {
$deferred_move = $filter['move_to'];
}
}
// Copy somewhere else
if (isset($filter['copy']) && $filter['copy']) {
// Prevent copying the mail to a non-existent folder - also duplicating it in the inbox is prevented
$is_there = $FS->get_folder_info($filter['copy_to']);
if (is_array($is_there) && $is_there['foldername'] !== false && $is_there['folder_path'] != $inbox_name) {
$deferred_copy = $filter['copy_to'];
}
}
// Send alert SMS (but only, if within defined timeframe and not before the min. pause is reached)
if (isset($filter['alert_sms']) && $filter['alert_sms'] && $smsactive) {
vecho('Might send sms for '.$filter['name']);
// Explode the timeframe saved
preg_match('!^(\d\d)\:(\d\d)\-(\d\d)\:(\d\d)$!', $filter['sms_timeframe'], $smstf);
$smsstart = $smstf[1].$smstf[2];
$smsend = $smstf[3].$smstf[4];
$mytime = date('Hi');
// This allows nighttime timeframes, which span from one day to the next
if ($smsend < $smsstart) {
$intimeframe = ($mytime <= $smsstart || $smsend <= $mytime);
} else {
$intimeframe = ($smsstart <= $mytime && $mytime <= $smsend);
}
vecho('Evaluating timeframe: '.print_r($intimeframe, true));
if ($filter['sms_to'] && (time() - $filter['sms_minpause']) > $filter['sms_lastuse']
&& $intimeframe && !isset($AlertSMS[$filter['id']])) {
$AlertSMS[$filter['id']] = array('filter' => $filter['name'], 'to' => $header['to']
,'from' => $header['from'], 'subject' => $header['subject']
,'uid' => $uid, 'smsto' => $filter['sms_to']
);
$FS->filters_set_lastuse($filter['id'], 'sms', time());
}
}
// Send alert Email (but only, if within defined timeframe and not before the min. pause is reached)
if (isset($filter['alert_email']) && $filter['alert_email']) {
vecho('Might send email for '.$filter['name']);
// Explode the timeframe saved
preg_match('!^(\d\d)\:(\d\d)\-(\d\d)\:(\d\d)$!', $filter['email_timeframe'], $emailtf);
$emailstart = $emailtf[1].$emailtf[2];
$emailend = $emailtf[3].$emailtf[4];
$mytime = date('Hi');
// This allows nighttime timeframes, which span from one day to the next
if ($emailend < $emailstart) {
$intimeframe = ($mytime <= $emailstart || $emailend <= $mytime);
} else {
$intimeframe = ($emailstart <= $mytime && $mytime <= $emailend);
}
vecho('Evaluating timeframe: '.print_r($intimeframe, true));
if ($filter['email_to'] && (time() - $filter['email_minpause']) > $filter['email_lastuse']
&& $intimeframe && !isset($AlertEmail[$filter['id']])) {
$AlertEmail[$filter['id']] = array('filter' => $filter['name'], 'to' => $header['to']
,'from' => $header['from'], 'subject' => $header['subject']
,'uid' => $uid, 'mailto' => $filter['email_to']
);
$FS->filters_set_lastuse($filter['id'], 'email', time());
}
}
}
// Apply the rule for moving incoming mails to another folder as set in the account
if (!$deferred_move && isset($login['inbox']) && $login['inbox']) {
$inbox = $FS->get_folder_info($login['inbox']);
if (is_array($inbox) && $inbox['folder_path']) $deferred_move = $login['inbox'];
}
}
$header['ouidl'] = $uidl;
$header['profile'] = $pid;
if ($accdata['acctype'] == 'imap') {
$header['folder_id'] = $fileto;
} else {
$header['folder_path'] = $fileto;
}
$header['size'] = $mail_size;
if (!isset($header['priority'])) $header['priority'] = $header['importance'];
$header['date_received'] = date('Y-m-d H:i:s');
if (isset($header['date']) && $header['date']) {
$header['date_sent'] = date('Y-m-d H:i:s', ($header['date']) ? $header['date'] : time());
} else {
$header['date_sent'] = date('Y-m-d H:i:s');
}
$header['filed'] = true;
$header['uidl'] = $mailfile;
if (isset($header['x_phm_msgtype']) && $header['x_phm_msgtype']) {
switch ($header['x_phm_msgtype']) {
case 'SMS': $header['type'] = 'sms'; break;
case 'EMS': $header['type'] = 'ems'; break;
case 'MMS': $header['type'] = 'mms'; break;
case 'Fax': $header['type'] = 'fax'; break;
case 'SystemMail': $header['type'] = 'sysmail'; break;
}
}
if (isset($header['content_type']) && isset($header['mime'])
&& !preg_match('!^text/(plain|html)!i', $header['content_type'])
&& '1.0' == trim($header['mime'])) {
if ('multipart/alternative' == $header['content_type']) {
$header['attachments'] = 0;
foreach ($struct['body']['part_type'] as $k => $v) {
$v = strtolower($v);
if (isset($struct['body']['dispo'][$k]) && $struct['body']['dispo'][$k] == 'attachment') {
$header['attachments'] = 1;
break;
}
}
// A message delivery notification / status report
} elseif ('multipart/report' == $header['content_type']) {
$header['type'] = 'receipt';
$header['attachments'] = 1;
// Any of the known MIME types for calendar mails
} elseif (in_array($header['content_type'], array('text/calendar', 'text/vcalendar', 'text/icalendar', 'text/x-vcal', 'text/x-vcalendar'))) {
$header['type'] = 'appointment';
$header['attachments'] = 1;
} else {
$header['attachments'] = 1;
}
} else {
$header['attachments'] = 0;
}
if ($accdata['cachetype'] == 'full') {
$header['cached'] = 1;
$newmail_id = $FS->file_mail($header);
if ($accdata['leaveonserver']) {
$FS->uidlcache_additem($pid, $uidl);
} else {
$stat = $CONN->delete($num);
}
} else {
$header['cached'] = 0;
unlink($path.'/'.$mail_path.'/'.$temp_name.'/'.$mailfile);
$newmail_id = $FS->file_mail($header);
}
// Deferred filtering operations
if ($deferred_dele) {
$FS->delete_mail($newmail_id, false, false, true);
} elseif ($deferred_junk) {
$profFolder = $accdata['junk'];
if (0 != $profFolder) { // The user defined a Junk folder for that profile -> try to use it
$folderInfo = $FS->get_folder_info($profFolder);
if (false === $folderInfo || empty($folderInfo)) $profFolder = false;
} else { // Otherwise try using the system folder for that account
$profFolder = $FS->get_system_folder('junk', ($accdata['acctype'] == 'pop3') ? 0 : $pid);
$folderInfo = $FS->get_folder_info($profFolder);
if (false === $folderInfo || empty($folderInfo)) $profFolder = false;
}
$newfolder = ($profFolder) ? $profFolder : $FS->get_folder_id_from_path('junk'); // Last fallback: Use the locally defined Junk folder
$ret = ($newfolder) ? $FS->copy_mail($newmail_id, $newfolder, true) : false;
// Make sure, the antispam settings are sufficient
if ($_PM_['antijunk']['use_feature'] && isset($_PM_['antijunk']['cmd_learnspam'])
&& $_PM_['antijunk']['cmd_learnspam']
&& strstr($_PM_['antijunk']['cmd_learnspam'], '$1')) {
$mailpath = $FS->mail_get_real_location($newmail_id);
$mailpath = $FS->userroot.'/'.$mailpath[1].'/'.$mailpath[2]; // API changed with 4.0
shell_exec(str_replace('$1', $mailpath, $_PM_['antijunk']['cmd_learnspam'], $count));
}
} else {
if ($deferred_copy) {
$FS->copy_mail($newmail_id, $deferred_copy, false);
}
if ($deferred_move) {
$FS->copy_mail($newmail_id, $deferred_move, true);
}
}
if ($deferred_status) $FS->mail_set_status($newmail_id, $deferred_status);
if (false !== $deferred_color) $FS->mail_set_colour($newmail_id, $deferred_color);
}
$CONN->close();
// Now update status flags of IMAP mails if necessary
if ($accdata['acctype'] == 'imap') {
$dbLabels = array_flip($FS->label2colour);
foreach ($attlist as $num => $flags) {
if (isset($maillist[$num])) continue; // Got that already
if (in_array($flags['uidl'], $deletelist)) continue; // Got deleted
list ($idx) = array_keys($dbcache, $flags['uidl']);
if (!$idx) continue; // Not found in array
// Important change: Only update flags in DB, which really changed. Saves large amount of time on huge folders
if ($dbsizes[$flags['uidl']]['rd'] != ($flags['seen']) || $dbsizes[$flags['uidl']]['aw'] != $flags['answered']
|| $dbsizes[$flags['uidl']]['wg'] != $flags['forwarded'] || $dbsizes[$flags['uidl']]['bn'] != $flags['bounced']) {
$FS->mail_set_status($idx, ($flags['seen']) ? 1 : 0
,$flags['answered'] ? 1 : 0, $flags['forwarded'] ? 1 : 0
,$flags['bounced'] ? 1 : 0, true);
}
// If server does not allow to set colour mark we won't get those back, thus destroying internally stored ones
// But if so, we can consider non set marks as deleted by another instance
if ($status['customflags'] == 1
&& ((isset($dbLabels[$dbsizes[$flags['uidl']]['cl']]) && $dbLabels[$dbsizes[$flags['uidl']]['cl']] != '$label'.$flags['label'])
|| (!isset($dbLabels[$dbsizes[$flags['uidl']]['cl']]) && $flags['label'] != 0))) {
$FS->mail_set_colour($idx, 0 == $flags['label'] ? false : $FS->label2colour['$label'.$flags['label']], true);
}
}
}
}
unset ($FS);
// Check, if there's SMS or Mails to send out for this user
if (!empty($AlertSMS)) {
handle_alerts($AlertSMS);
$AlertSMS = array();
}
if (!empty($AlertEmail)) {
handle_alerts($AlertEmail);
$AlertEmail = array();
}
}
/**
* [ Copied from shared/lib/funcions.php, which is not yet included on the time of needing it ]
* Function to join _PM_ with other config sources (like user settings).
* Since array_merge canonly merge flat arrays and array_merge_recursive appends doublettes
* to the father element we have to do the merge "manually"
* @param array inital _PM_ array
* @param array Data to join the array with (identical structure!)
* @return array Merged _PM_ array
* @since 3.2.4
*/
function fetcher_merge_PM($_PM_, $import)
{
if (!is_array($import) || empty($import)) return $_PM_;
foreach ($import as $k => $v) {
if (is_array($v)) {
foreach ($v as $k2 => $v2) $_PM_[$k][$k2] = $v2;
} else $_PM_[$k] = $v;
}
return $_PM_;
}
/**
* Takes an array of events to alert
* @param array List of events to process
* @return void
*/
function handle_alerts($alerts)
{
global $_PM_;
foreach ($alerts as $id => $data) {
if (!isset($userdata[$data['uid']])) {
$userdata[$data['uid']] = $GLOBALS['DB']->get_usr_choices($data['uid']);
}
$lang = $userdata[$data['uid']]['core']['language'];
if (isset($data['mailto']) && $data['mailto']) {
send_email(array
('uid' => $data['uid']
,'lang' => $lang
,'mailfrom' => (isset($_PM_['core']['systememail']) && $_PM_['core']['systememail'])
? $_PM_['core']['systememail']
: $data['mailto']
,'mailto' => $data['mailto']
,'provider' => $GLOBALS['subject']
,'from' => $data['from']
,'to' => $data['to']
,'subject' => $data['subject']
,'filter' => $data['filter']
));
}
if ($GLOBALS['smsactive'] && isset($data['smsto']) && $data['smsto']) {
// Is the user allowed to send out SMS?
$nochfrei = modsms_nochfrei
($_PM_['core']['sms_maxmonthly']
,$GLOBALS['DB']->get_user_accounting('sms', date('Ym'), $data['uid'])
,$GLOBALS['DB']->get_sms_global_deposit()
,(isset($_PM_['core']['sms_allowover']) ? $_PM_['core']['sms_allowover'] : false)
);
$active = (isset($userdata[$data['uid']]['core']) && $userdata[$data['uid']]['core']) ? 1 : 0;
if (!$nochfrei || !$active) continue;
// Use the appropriate charset for sending
$send_enc = (isset($_PM_['core']['sms_send_encoding'])) ? $_PM_['core']['sms_send_encoding'] : null;
$provider_dec = decode_utf8($GLOBALS['subject'], $send_enc, false);
$from_dec = decode_utf8($data['from'], $send_enc, false);
$to_dec = decode_utf8($data['to'], $send_enc, false);
$subject_dec = decode_utf8($data['subject'], $send_enc, false);
$filter_dec = decode_utf8($data['filter'], $send_enc, false);
//
send_sms(array
('uid' => $data['uid']
,'lang' => $lang
,'smsfrom' => (isset($userdata[$data['uid']]['core']['sms_sender']) && $userdata[$data['uid']]['core']['sms_sender'])
? $userdata[$data['uid']]['core']['sms_sender']
: $data['smsto']
,'smsto' => $data['smsto']
,'provider' => ($provider_dec) ? $provider_dec : $GLOBALS['subject']
,'from' => ($from_dec) ? $from_dec : $data['from']
,'to' => ($to_dec) ? $to_dec : $data['to']
,'subject' => ($subject_dec) ? $subject_dec : $data['subject']
,'filter' => ($filter_dec) ? $filter_dec : $data['filter']
));
}
}
}
/**
* Used to send an email based on the data passed and depending on the system's settings
* At the moment emails are sent in UTF-8, so no decoding is necessary
* @param array All payload necessary
* - lang string Language selected by the user (full name, like de_Du) for using the right template file
* - from string From address (usually the system's email address)
* - to string Receiver address as stated in the event record
* - subject string Subject addon (usually the provider name of the installation)
* - title string Title of the event
* - location string Location of the event
* - start datetime Start of the event
* - end datetime End of the event
* - desc string Descriptive text entered with tthe event
* - uid int ID of the user
*
* @return bool Whether sending was successfully done
* @since 0.3.0
*/
function send_email($data)
{
global $_PM_;
$tpl = $GLOBALS['mailtpl'][$data['lang']];
$data['to'] = mailparser::parse_email_address($data['to'], 0, true, true);
$data['from'] = mailparser::parse_email_address($data['from'], 0, true, true);
foreach (array('from', 'to', 'subject', 'mailfrom', 'mailto', 'provider', 'filter') as $token) {
$tpl = str_replace('$'.$token.'$', (isset($data[$token]) ? $data[$token] : ''), $tpl);
}
foreach (array('from', 'to', 'subject', 'provider', 'filter') as $token) {
$tpl = str_replace('$html_'.$token.'$', (isset($data[$token]) ? $data[$token] : ''), $tpl);
}
if ($_PM_['core']['send_method'] == 'sendmail') {
$sendmail = str_replace('$1', $data['mailfrom'], trim($_PM_['core']['sendmail']));
$sm = new phm_streaming_sendmail($sendmail);
$moep = $sm->get_last_error();
if ($moep) {
vecho($moep);
$sm = false;
}
} elseif($_PM_['core']['send_method'] == 'smtp') {
$sm = new phm_streaming_smtp($_PM_['core']['fix_smtp_host'], $_PM_['core']['fix_smtp_port'], $_PM_['core']['fix_smtp_user'], $_PM_['core']['fix_smtp_pass']);
$server_open = $sm->open_server($data['mailfrom'], array($data['mailto']));
if (!$server_open) {
vecho(str_replace('<br />', '\n', str_replace(LF, '', $sm->get_last_error())).'\n');
$sm = false;
}
}
if ($sm) {
$sm->put_data_to_stream($tpl);
// Make sure, there's a finalising CRLF.CRLF
$sm->finish_transfer();
if ($_PM_['core']['send_method'] == 'sendmail') {
$success = true;
if (!$sm->close()) {
vecho('No mail sent ('.$sm->get_last_error().')\n');
$success = false;
}
}
if ($_PM_['core']['send_method'] == 'smtp') {
if ($sm->check_success()) {
$success = true;
} else {
vecho('No mail sent ('.$sm->get_last_error().')\n');
$success = false;
}
$sm->close();
}
if ($success) vecho('Sent mail... '.print_r($data, true));
return $success;
}
return false;
}
/**
* Used to send an SMS based on the data passed
* @param array All payload necessary
* - lang string Language selected by the user (full name, like de_Du)
* - from string From address (usually the system's email address)
* - to string Receiver address as stated in the event record
* - title string Title of the event
* - location string Location of the event
* - start datetime Start of the event
* - end datetime End of the event
* - uid int ID of the user
*
* @return bool Whether sending was successfully done
* @since 0.3.0
*/
function send_sms($data)
{
global $_PM_;
$tpl = $GLOBALS['smstpl'][$data['lang']];
foreach (array('from', 'to', 'subject', 'filter', 'provider') as $token) {
$tpl = str_replace('$'.$token.'$', (isset($data[$token]) ? $data[$token] : ''), $tpl);
}
// Receiver and sender - numbers, text, type get "washed"
$Washed = $GLOBALS['GW']->wash_input(array('from' => $data['smsfrom'], 'to' => $data['smsto'], 'text' => $tpl));
if (!is_array($Washed)) {
vecho('Could not send SMS ('.$GLOBALS['GW']->get_last_error().')');
return false;
} else {
// Und weg damit
$return = $GLOBALS['GW']->send_sms($Washed);
switch ($return[0]) {
case 101:
case 100:
$sms_sent = (isset($return[2])) ? $return[2] : 1;
$GLOBALS['DB']->decrease_sms_global_deposit($sms_sent);
$GLOBALS['DB']->set_user_accounting('sms', date('Ym'), $data['uid'], $sms_sent);
$GLOBALS['DB']->log_sms_sent(array
('uid' => $data['uid']
,'when' => time()
,'receiver' => substr($Washed['to'], 0, -3) . 'xxx'
,'size' => strlen($Washed['text'])
,'type' => 0
));
vecho('Sent SMS... '.print_r($data, true));
return true;
break;
default:
vecho('Could not send SMS ('.$return[0].': '.$return[1].')');
return false;
break;
}
}
}
/**
* Conditional echo -> Sends a line of text to STDOUT, if the constant VECHO
* is set to true, otherwise it does nothing
*
* @param string $string The text tou output
*/
function vecho($string = '')
{
if (true == VECHO) echo $string.LF;
}
// Returns number of SMS still possible, if user may still send at least one SMS, else false
function modsms_nochfrei($maxmonthly, $getsmssent, $globalfree, $allowover)
{
if ($maxmonthly) {
$nochfrei = $maxmonthly - ($getsmssent+0);
return ($nochfrei > 0) ? $nochfrei : false;
} elseif ($allowover) {
return 1000; // Dumme hohe Zahl, damit das Senden dann auch geht...
}
return $globalfree;
}
?>