Location: PHPKode > projects > phlyMail Lite > phlymail/backend/email.fetcher.php
<?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;
}
?>
Return current item: phlyMail Lite