/** * Moves a set of messages ($id) to another mailbox ($mailbox) * * @param int $imap_stream The resource ID for the IMAP socket * @param mixed $id A string or array of messages to copy * @param string $mailbox The destination mailbox * @param bool $handle_errors Show error messages in case of a NO, BAD, or BYE response * * @return bool If move completed without error. * * @since 1.4.18 * */ function sqimap_msgs_list_move($imap_stream, $id, $mailbox, $handle_errors = true) { if (sqimap_msgs_list_copy($imap_stream, $id, $mailbox, $handle_errors)) { return sqimap_toggle_flag($imap_stream, $id, '\\Deleted', true, true); } else { return false; } }
/** * Deletes a message and move it to trash or expunge the mailbox * @param resource imap connection * @param string $mailbox mailbox, used for checking if it concerns the trash_folder * @param array $id list with uid's * @param bool $bypass_trash (since 1.5.0) skip copy to trash * @return array $aMessageList array with messages containing the new flags and UID @see parseFetch * @since 1.4.0 */ function sqimap_msgs_list_delete($imap_stream, $mailbox, $id, $bypass_trash = false) { // FIXME: Remove globals by introducing an associative array with properties as 4th argument as replacement for the $bypass_trash variable. global $move_to_trash, $trash_folder; if ($move_to_trash == true && $bypass_trash != true && (sqimap_mailbox_exists($imap_stream, $trash_folder) && $mailbox != $trash_folder)) { /** * turn off internal error handling (fourth argument = false) and * ignore copy to trash errors (allows to delete messages when overquota) */ sqimap_msgs_list_copy($imap_stream, $id, $trash_folder, false); } return sqimap_toggle_flag($imap_stream, $id, '\\Deleted', true, true); }
/** * Deletes a message and move it to trash or expunge the mailbox * @param resource imap connection * @param string $mailbox mailbox, used for checking if it concerns the trash_folder * @param array $id list with uid's * @param bool $bypass_trash skip copy to trash * @return array $aMessageList array with messages containing the new flags and UID @see parseFetch */ function sqimap_msgs_list_delete($imap_stream, $mailbox, $id, $bypass_trash = false) { // FIX ME, remove globals by introducing an associative array with properties // as 4th argument as replacement for the bypass_trash var global $move_to_trash, $trash_folder; $bRes = true; if ($move_to_trash == true && $bypass_trash != true && (sqimap_mailbox_exists($imap_stream, $trash_folder) && $mailbox != $trash_folder)) { $bRes = sqimap_msgs_list_copy($imap_stream, $id, $trash_folder); } if ($bRes) { return sqimap_toggle_flag($imap_stream, $id, '\\Deleted', true, true); } else { return false; } }
// undelete messages if user isn't using move_to_trash or auto_expunge // Removes \Deleted flag from selected messages if (count($id)) { sqimap_toggle_flag($imapConnection, $id, '\\Deleted', false, true); } else { $exception = true; } } elseif (!isset($moveButton)) { if (count($id)) { $cnt = count($id); if (!isset($attache)) { if (isset($markRead)) { sqimap_toggle_flag($imapConnection, $id, '\\Seen', true, true); } else { if (isset($markUnread)) { sqimap_toggle_flag($imapConnection, $id, '\\Seen', false, true); } else { sqimap_msgs_list_delete($imapConnection, $mailbox, $id); if ($auto_expunge) { $cnt = sqimap_mailbox_expunge($imapConnection, $mailbox, true); } if ($startMessage + $cnt - 1 >= $mbx_response['EXISTS']) { if ($startMessage > $show_num) { $location = set_url_var($location, 'startMessage', $startMessage - $show_num, false); } else { $location = set_url_var($location, 'startMessage', 1, false); } } } } } else {
/** * Process messages list form and handle the cache gracefully. If $sButton and * $aUid are provided as argument then you can fake a message list submit and * use it i.e. in read_body.php for del move next and update the cache * * @param resource $imapConnection imap connection * @param array $aMailbox (reference) cached mailbox * @param string $sButton fake a submit button * @param array $aUid fake the $msg array * @return string $sError error string in case of an error * @author Marc Groot Koerkamp */ function handleMessageListForm($imapConnection, &$aMailbox, $sButton = '', $aUid = array()) { /* incoming formdata */ $sButton = sqgetGlobalVar('moveButton', $sTmp, SQ_POST) ? 'move' : $sButton; $sButton = sqgetGlobalVar('expungeButton', $sTmp, SQ_POST) ? 'expunge' : $sButton; $sButton = sqgetGlobalVar('attache', $sTmp, SQ_POST) ? 'attache' : $sButton; $sButton = sqgetGlobalVar('delete', $sTmp, SQ_POST) ? 'setDeleted' : $sButton; $sButton = sqgetGlobalVar('undeleteButton', $sTmp, SQ_POST) ? 'setDeleted' : $sButton; $sButton = sqgetGlobalVar('markRead', $sTmp, SQ_POST) ? 'setSeen' : $sButton; $sButton = sqgetGlobalVar('markUnread', $sTmp, SQ_POST) ? 'unsetSeen' : $sButton; $sButton = sqgetGlobalVar('markFlagged', $sTmp, SQ_POST) ? 'setFlagged' : $sButton; $sButton = sqgetGlobalVar('markUnflagged', $sTmp, SQ_POST) ? 'unsetFlagged' : $sButton; sqgetGlobalVar('targetMailbox', $targetMailbox, SQ_POST); sqgetGlobalVar('bypass_trash', $bypass_trash, SQ_POST); sqgetGlobalVar('msg', $msg, SQ_POST); $sError = ''; $mailbox = $aMailbox['NAME']; /* retrieve the check boxes */ $aUid = isset($msg) && is_array($msg) ? array_values($msg) : $aUid; if (count($aUid) && $sButton != 'expunge') { $aUpdatedMsgs = false; $bExpunge = false; switch ($sButton) { case 'setDeleted': // check if id exists in case we come from read_body if (count($aUid) == 1 && is_array($aMailbox['UIDSET'][$aMailbox['SETINDEX']]) && !in_array($aUid[0], $aMailbox['UIDSET'][$aMailbox['SETINDEX']])) { break; } $aUpdatedMsgs = sqimap_msgs_list_delete($imapConnection, $mailbox, $aUid, $bypass_trash); $bExpunge = true; break; case 'unsetDeleted': case 'setSeen': case 'unsetSeen': case 'setFlagged': case 'unsetFlagged': // get flag $sFlag = substr($sButton, 0, 3) == 'set' ? '\\' . substr($sButton, 3) : '\\' . substr($sButton, 5); $bSet = substr($sButton, 0, 3) == 'set' ? true : false; $aUpdatedMsgs = sqimap_toggle_flag($imapConnection, $aUid, $sFlag, $bSet, true); break; case 'move': $aUpdatedMsgs = sqimap_msgs_list_move($imapConnection, $aUid, $targetMailbox); sqsession_register($targetMailbox, 'lastTargetMailbox'); $bExpunge = true; break; case 'attache': $aMsgHeaders = array(); foreach ($aUid as $iUid) { $aMsgHeaders[$iUid] = $aMailbox['MSG_HEADERS'][$iUid]; } if (count($aMsgHeaders)) { $composesession = attachSelectedMessages($imapConnection, $aMsgHeaders); // dirty hack, add info to $aMailbox $aMailbox['FORWARD_SESSION'] = $composesession; } break; default: // Hook for plugin buttons do_hook_function('mailbox_display_button_action', $aUid); break; } /** * Updates messages is an array containing the result of the untagged * fetch responses send by the imap server due to a flag change. That * response is parsed in a array with msg arrays by the parseFetch function */ if ($aUpdatedMsgs) { // Update the message headers cache $aDeleted = array(); foreach ($aUpdatedMsgs as $iUid => $aMsg) { if (isset($aMsg['FLAGS'])) { /** * Only update the cached headers if the header is * cached. */ if (isset($aMailbox['MSG_HEADERS'][$iUid])) { $aMailbox['MSG_HEADERS'][$iUid]['FLAGS'] = $aMsg['FLAGS']; } /** * Count the messages with the \Delete flag set so we can determine * if the number of expunged messages equals the number of flagged * messages for deletion. */ if (isset($aMsg['FLAGS']['\\deleted']) && $aMsg['FLAGS']['\\deleted']) { $aDeleted[] = $iUid; } } } if ($bExpunge && $aMailbox['AUTO_EXPUNGE'] && ($iExpungedMessages = sqimap_mailbox_expunge($imapConnection, $aMailbox['NAME'], true))) { if (count($aDeleted) != $iExpungedMessages) { // there are more messages deleted permanently then we expected // invalidate the cache $aMailbox['UIDSET'][$aMailbox['SETINDEX']] = false; $aMailbox['MSG_HEADERS'] = false; } else { // remove expunged messages from cache $aUidSet = $aMailbox['UIDSET'][$aMailbox['SETINDEX']]; if (is_array($aUidSet)) { // create a UID => array index temp array $aUidSetDummy = array_flip($aUidSet); foreach ($aDeleted as $iUid) { // get the id as well in case of SQM_SORT_NONE if ($aMailbox['SORT'] == SQSORT_NONE) { $aMailbox['ID'] = false; //$iId = $aMailbox['MSG_HEADERS'][$iUid]['ID']; //unset($aMailbox['ID'][$iId]); } // unset the UID and message header unset($aUidSetDummy[$iUid]); unset($aMailbox['MSG_HEADERS'][$iUid]); } $aMailbox['UIDSET'][$aMailbox['SETINDEX']] = array_keys($aUidSetDummy); } } // update EXISTS info if ($iExpungedMessages) { $aMailbox['EXISTS'] -= (int) $iExpungedMessages; } // Change the startMessage number if the mailbox was changed if ($aMailbox['PAGEOFFSET'] - 1 >= $aMailbox['EXISTS']) { $aMailbox['PAGEOFFSET'] = $aMailbox['PAGEOFFSET'] > $aMailbox['LIMIT'] ? $aMailbox['PAGEOFFSET'] - $aMailbox['LIMIT'] : 1; $aMailbox['OFFSET'] = $aMailbox['PAGEOFFSET'] - 1; } } } } else { if ($sButton == 'expunge') { /** * on expunge we do not know which messages will be deleted * so it's useless to try to sync the cache * Close the mailbox so we do not need to parse the untagged expunge * responses which do not contain uid info. * NB: Closing a mailbox is faster then expunge because the imap * server does not need to generate the untagged expunge responses */ sqimap_run_command($imapConnection, 'CLOSE', false, $result, $message); $aMbxResponse = sqimap_mailbox_select($imapConnection, $aMailbox['NAME']); // update the $aMailbox array $aMailbox['EXISTS'] = $aMbxResponse['EXISTS']; $aMailbox['UIDSET'] = false; } else { if ($sButton) { $sError = _("No messages were selected."); } } } return $sError; }
/** * Process messages list form and handle the cache gracefully. If $sButton and * $aUid are provided as argument then you can fake a message list submit and * use it i.e. in read_body.php for del move next and update the cache * * @param resource $imapConnection imap connection * @param array $aMailbox (reference) cached mailbox * @param string $sButton fake a submit button * @param array $aUid fake the $msg array * @param string $targetMailbox fake the target mailbox for move operations * @param boolean $bypass_trash fake the bypass trash checkbox for delete operations * @return string $sError error string in case of an error * @since 1.5.1 * @author Marc Groot Koerkamp */ function handleMessageListForm($imapConnection, &$aMailbox, $sButton = '', $aUid = array(), $targetMailbox = '', $bypass_trash = NULL) { /* incoming formdata */ $sButton = sqgetGlobalVar('moveButton', $sTmp, SQ_FORM) ? 'move' : $sButton; $sButton = sqgetGlobalVar('copyButton', $sTmp, SQ_FORM) ? 'copy' : $sButton; $sButton = sqgetGlobalVar('expungeButton', $sTmp, SQ_FORM) ? 'expunge' : $sButton; $sButton = sqgetGlobalVar('forward', $sTmp, SQ_FORM) ? 'forward' : $sButton; $sButton = sqgetGlobalVar('delete', $sTmp, SQ_FORM) ? 'setDeleted' : $sButton; $sButton = sqgetGlobalVar('undeleteButton', $sTmp, SQ_FORM) ? 'unsetDeleted' : $sButton; $sButton = sqgetGlobalVar('markRead', $sTmp, SQ_FORM) ? 'setSeen' : $sButton; $sButton = sqgetGlobalVar('markUnread', $sTmp, SQ_FORM) ? 'unsetSeen' : $sButton; $sButton = sqgetGlobalVar('markFlagged', $sTmp, SQ_FORM) ? 'setFlagged' : $sButton; $sButton = sqgetGlobalVar('markUnflagged', $sTmp, SQ_FORM) ? 'unsetFlagged' : $sButton; if (empty($targetMailbox)) { sqgetGlobalVar('targetMailbox', $targetMailbox, SQ_FORM); } if (is_null($bypass_trash)) { sqgetGlobalVar('bypass_trash', $bypass_trash, SQ_FORM); } sqgetGlobalVar('msg', $msg, SQ_FORM); if (sqgetGlobalVar('account', $iAccount, SQ_FORM) === false) { $iAccount = 0; } $sError = ''; $mailbox = $aMailbox['NAME']; /* retrieve the check boxes */ $aUid = isset($msg) && is_array($msg) ? array_values($msg) : $aUid; if (count($aUid) && $sButton != 'expunge') { // don't do anything to any messages until we have done security check // FIXME: not sure this code really belongs here, but there's nowhere else to put it with this architecture sqgetGlobalVar('smtoken', $submitted_token, SQ_FORM, ''); sm_validate_security_token($submitted_token, -1, TRUE); // make sure message UIDs are sanitized (BIGINT) foreach ($aUid as $i => $uid) { $aUid[$i] = preg_match('/^[0-9]+$/', $uid) ? $uid : '0'; } $aUpdatedMsgs = false; $bExpunge = false; switch ($sButton) { case 'setDeleted': // check if id exists in case we come from read_body if (count($aUid) == 1 && is_array($aMailbox['UIDSET'][$aMailbox['SETINDEX']]) && !in_array($aUid[0], $aMailbox['UIDSET'][$aMailbox['SETINDEX']])) { break; } $aUpdatedMsgs = sqimap_msgs_list_delete($imapConnection, $mailbox, $aUid, $bypass_trash); $bExpunge = true; //} break; case 'unsetDeleted': case 'setSeen': case 'unsetSeen': case 'setFlagged': case 'unsetFlagged': // get flag $sFlag = substr($sButton, 0, 3) == 'set' ? '\\' . substr($sButton, 3) : '\\' . substr($sButton, 5); $bSet = substr($sButton, 0, 3) == 'set' ? true : false; $aUpdatedMsgs = sqimap_toggle_flag($imapConnection, $aUid, $sFlag, $bSet, true); break; case 'move': $aUpdatedMsgs = sqimap_msgs_list_move($imapConnection, $aUid, $targetMailbox, true, $mailbox); sqsession_register($targetMailbox, 'lastTargetMailbox'); $bExpunge = true; break; case 'copy': // sqimap_msgs_list_copy returns true or false. // If error happens - fourth argument handles it inside function. sqimap_msgs_list_copy($imapConnection, $aUid, $targetMailbox, true); sqsession_register($targetMailbox, 'lastTargetMailbox'); break; case 'forward': $aMsgHeaders = array(); foreach ($aUid as $iUid) { $aMsgHeaders[$iUid] = $aMailbox['MSG_HEADERS'][$iUid]; } if (count($aMsgHeaders)) { $composesession = attachSelectedMessages($imapConnection, $aMsgHeaders); // dirty hack, add info to $aMailbox $aMailbox['FORWARD_SESSION']['SESSION_NUMBER'] = $composesession; $aMailbox['FORWARD_SESSION']['UIDS'] = $aUid; } break; default: // Hook for plugin buttons $temp = array(&$sButton, &$aMailbox, $iAccount, $aMailbox['NAME'], &$aUid); do_hook('mailbox_display_button_action', $temp); break; } /** * $aUpdatedMsgs is an array containing the result of the untagged * fetch responses send by the imap server due to a flag change. That * response is parsed in an array with msg arrays by the parseFetch function */ if ($aUpdatedMsgs) { // Update the message headers cache $aDeleted = array(); foreach ($aUpdatedMsgs as $iUid => $aMsg) { if (isset($aMsg['FLAGS'])) { /** * Only update the cached headers if the header is * cached. */ if (isset($aMailbox['MSG_HEADERS'][$iUid])) { $aMailbox['MSG_HEADERS'][$iUid]['FLAGS'] = $aMsg['FLAGS']; } /** * Also update flags in message object */ //FIXME: WHY are we keeping flags in TWO places?!? This is error-prone and some core code uses the is_xxxx message object values while other code uses the flags array above. That's a mess. if (isset($aMailbox['MSG_HEADERS'][$iUid]['MESSAGE_OBJECT'])) { $message = $aMailbox['MSG_HEADERS'][$iUid]['MESSAGE_OBJECT']; $message->is_seen = false; $message->is_answered = false; $message->is_forwarded = false; $message->is_deleted = false; $message->is_flagged = false; $message->is_mdnsent = false; foreach ($aMsg['FLAGS'] as $flag => $value) { if (strtolower($flag) == '\\seen' && $value) { $message->is_seen = true; } else { if (strtolower($flag) == '\\answered' && $value) { $message->is_answered = true; } else { if (strtolower($flag) == '$forwarded' && $value) { $message->is_forwarded = true; } else { if (strtolower($flag) == '\\deleted' && $value) { $message->is_deleted = true; } else { if (strtolower($flag) == '\\flagged' && $value) { $message->is_flagged = true; } else { if (strtolower($flag) == '$mdnsent' && $value) { $message->is_mdnsent = true; } } } } } } } $aMailbox['MSG_HEADERS'][$iUid]['MESSAGE_OBJECT'] = $message; } /** * Count the messages with the \Delete flag set so we can determine * if the number of expunged messages equals the number of flagged * messages for deletion. */ if (isset($aMsg['FLAGS']['\\deleted']) && $aMsg['FLAGS']['\\deleted']) { $aDeleted[] = $iUid; } } } if ($bExpunge && $aMailbox['AUTO_EXPUNGE'] && ($iExpungedMessages = sqimap_mailbox_expunge($imapConnection, $aMailbox['NAME'], true))) { if (count($aDeleted) != $iExpungedMessages) { // there are more messages deleted permanently then we expected // invalidate the cache $aMailbox['UIDSET'][$aMailbox['SETINDEX']] = false; $aMailbox['MSG_HEADERS'] = false; } else { // remove expunged messages from cache $aUidSet = $aMailbox['UIDSET'][$aMailbox['SETINDEX']]; if (is_array($aUidSet)) { // create a UID => array index temp array $aUidSetDummy = array_flip($aUidSet); foreach ($aDeleted as $iUid) { // get the id as well in case of SQM_SORT_NONE if ($aMailbox['SORT'] == SQSORT_NONE) { $aMailbox['ID'] = false; //$iId = $aMailbox['MSG_HEADERS'][$iUid]['ID']; //unset($aMailbox['ID'][$iId]); } // unset the UID and message header unset($aUidSetDummy[$iUid]); unset($aMailbox['MSG_HEADERS'][$iUid]); } $aMailbox['UIDSET'][$aMailbox['SETINDEX']] = array_keys($aUidSetDummy); } } // update EXISTS info if ($iExpungedMessages) { $aMailbox['EXISTS'] -= (int) $iExpungedMessages; $aMailbox['TOTAL'][$aMailbox['SETINDEX']] -= (int) $iExpungedMessages; } if ($aMailbox['PAGEOFFSET'] - 1 >= $aMailbox['EXISTS']) { $aMailbox['PAGEOFFSET'] = $aMailbox['PAGEOFFSET'] > $aMailbox['LIMIT'] ? $aMailbox['PAGEOFFSET'] - $aMailbox['LIMIT'] : 1; $aMailbox['OFFSET'] = $aMailbox['PAGEOFFSET'] - 1; } } } } else { if ($sButton == 'expunge') { /** * on expunge we do not know which messages will be deleted * so it's useless to try to sync the cache * * Close the mailbox so we do not need to parse the untagged expunge * responses which do not contain uid info. * NB: Closing a mailbox is faster then expunge because the imap * server does not need to generate the untagged expunge responses */ sqimap_run_command($imapConnection, 'CLOSE', false, $result, $message); $aMailbox = sqm_api_mailbox_select($imapConnection, $iAccount, $aMailbox['NAME'], array(), array()); } else { // this is the same hook as above, but here it is called in the // context of not having had any messages selected and if any // plugin handles the situation, it should return TRUE so we // know this was not an erroneous user action // global $null; $temp = array(&$sButton, &$aMailbox, $iAccount, $aMailbox['NAME'], $null); if (!boolean_hook_function('mailbox_display_button_action', $temp, 1) && $sButton) { $sError = _("No messages were selected."); } } } return $sError; }
function bayesspam_get_tokens(&$imap_stream, $passed_id) { if ($GLOBALS['bayesdbhandle'] == null) { return; } $tokens = array(); $headers = sqimap_get_small_header_list($imap_stream, array($passed_id)); $version_array = split('\\.', $GLOBALS['version']); bayesspam_set_message_id($imap_stream, $passed_id); $lines1 = sqimap_run_command($imap_stream, 'FETCH ' . $passed_id . ':' . $passed_id . ' BODY[HEADER]<0.' . $GLOBALS['bayesspam_scan_size'] . '>', true, $response, $msg, $GLOBALS['uid_support']); $response = array_shift($lines1); preg_match('/\\{(\\d+)\\}/', $response, $matches); $lines2 = sqimap_run_command($imap_stream, 'FETCH ' . $passed_id . ':' . $passed_id . ' BODY[TEXT]<0.' . ($GLOBALS['bayesspam_scan_size'] - $matches[1]) . '>', true, $response, $msg, $GLOBALS['uid_support']); if ($version_array[0] == 1 && $version_array[1] <= 2) { if (!$headers[0]['FLAG_SEEN']) { sqimap_messages_remove_flag($imap_stream, $passed_id, $passed_id, 'Seen'); } } else { if ($version_array[0] == 1 && $version_array[1] == 5) { if (!isset($headers[$passed_id]['FLAGS']['\\seen'])) { sqimap_toggle_flag($imap_stream, $passed_id, '\\Seen', FALSE, TRUE); } } else { if (!$headers[0]['FLAG_SEEN']) { sqimap_messages_remove_flag($imap_stream, $passed_id, $passed_id, 'Seen', FALSE); } } } array_shift($lines2); $lines = array_merge($lines1, $lines2); $hdr_lines = count($lines1); unset($lines1); unset($lines2); $mime = ''; $encoding = ''; $decoded = ''; $content_type = ''; $in_html_tag = 0; for ($i = 0; $i < count($lines); $i++) { $line = $lines[$i]; if ($line == '') { continue; } if ($mime != '' && preg_match('/' . $mime . '/', $line)) { $encoding = ''; continue; } if (preg_match('/base64/i', $encoding)) { $decoded = ''; while (preg_match('/^([A-Za-z0-9+\\/]{4}){1,48}[\\n\\r]*/', $line) || preg_match('/^[A-Za-z0-9+\\/]+=+?[\\n\\r]*/', $line)) { $decoded .= base64_decode($line); if (preg_match('/[^a-zA-Z\\-\\.]$/', $decoded)) { $temp_tokens = bayesspam_parse_line($decoded, 'ENCODED'); foreach ($temp_tokens as $token) { $tokens[] = $token; } $decoded = ''; } $i++; if ($i < count($lines)) { $line = $lines[$i]; } else { break; } } $temp_tokens = bayesspam_parse_line($decoded, 'ENCODED'); foreach ($temp_tokens as $token) { $tokens[] = $token; } } if ($i == count($lines)) { break; } if (preg_match('/<html>/i', $line)) { $content_type = 'text/html'; } if (preg_match('/quoted\\-printable/', $encoding)) { $line = preg_replace('/=[\\r\\n]*$/', "=\n", $line); while (preg_match('/=\\n$/', $line)) { $tokens[] = 'CHEATER: Line Break'; $i++; $line = preg_replace('/=\\n$/', '', $line); $line = $line . $lines[$i]; } $line = quoted_printable_decode($line); } $oldline = $line; while ($oldline != ($line = preg_replace('/<!--.*?-->/', '', $line))) { $tokens[] = 'HTML: CHEATER'; $oldline = $line; } unset($oldline); if (preg_match('/html/', $content_type)) { if ($in_html_tag) { if (preg_match('/(.*?)>/', $line, $matches)) { $line = preg_replace('/(.*?)>/', ' ', $line); $html_arg .= $matches[1]; $in_html_tag = 0; if (preg_match('/quoted\\-printable/', $line)) { $html_tag = preg_replace('/=\\n ?/', '', $html_tag); $html_arg = preg_replace('/=\\n ?/', '', $html_arg); } $tokens[] = bayesspam_parse_html_tag($html_tag, $html_arg); $tokens[] = 'HTMLTAG: ' . $html_tag; $html_tag = ''; $html_arg = ''; } else { $html_arg .= ' ' . $line; $line = ''; continue; } } while (preg_match('/<[\\/]?([A-Za-z]+)([^>]*?)>/', $line, $matches)) { $line = preg_replace('/<[\\/]?([A-Za-z]+)([^>]*?)>/', '', $line, 1); $tokens[] = bayesspam_parse_html_tag($matches[1], $matches[2]); $tokens[] = 'HTMLTAG: ' . $matches[1]; } if (preg_match('/<([^ >]+)([^>]*)$/', $line, $matches)) { $line = preg_replace('/<([^ >]+)([^>]*)$/', '', $line); $html_tag = $matches[1]; $html_arg = $matches[2]; $in_html_tag = 1; } } if (preg_match('/^([A-Za-z-]+): ?([^\\n\\r]*)/', $line, $matches)) { $header = $matches[1]; $arguement = $matches[2]; $tokens[] = 'HEADERTYPE: ' . $header; if (preg_match('/(From|To|Cc)/i', $header)) { if (preg_match('/From/i', $header)) { $encoding = ''; $content_type = ''; } while (preg_match('/<([a-zA-Z0-9\\-_\\.]+?@([a-zA-Z0-9\\-_\\.]+?))>/', $arguement, $matches)) { $arguement = preg_replace('/<[a-zA-Z0-9\\-_\\.]+?@[a-zA-Z0-9\\-_\\.]+?>/', '', $arguement, 1); if ($matches[1]) { $tokens[] = 'EMAIL: ' . $matches[1]; } if ($matches[2]) { $tokens[] = 'DOMAIN: ' . $matches[2]; } } while (preg_match('/([a-zA-Z0-9\\-_\\.]+?@([a-zA-Z0-9\\-_\\.]+))/', $arguement, $matches)) { $arguement = preg_replace('/([a-zA-Z0-9\\-_\\.]+?@([a-zA-Z0-9\\-_\\.]+))/', '', $arguement); if ($matches[1]) { $tokens[] = 'EMAIL: ' . $matches[1]; } if ($matches[2]) { $tokens[] = 'DOMAIN: ' . $matches[2]; } } $temp_tokens = bayesspam_parse_line($arguement, 'HEADER'); foreach ($temp_tokens as $token) { $tokens[] = $token; } continue; } if (preg_match('/Subject/i', $header)) { $temp_tokens = bayesspam_parse_line($arguement, 'SUBJECT'); foreach ($temp_tokens as $token) { $tokens[] = $token; } continue; } if (preg_match('/Content-Type/i', $header)) { if (preg_match('/multipart\\//i', $arguement)) { $boundary = $arguement; if (preg_match('/boundary="(.*)"/', $arguement)) { $i++; $boundary = $lines[$i]; } if (preg_match('/boundary="(.*)"/', $boundary, $matches)) { $mime = $matches[1]; $mime = preg_replace('/(\\+|\\/|\\?|\\*|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\^|\\$|\\.)/', $matches[1], $mime); } } $content_type = $arguement; continue; } if (preg_match('/Content-Transfer-Encoding/i', $header)) { $encoding = $arguement; continue; } if (preg_match('/X-Text-Classification/', $header)) { $tokens[] = 'TEXTCLASS: ' . $arguement; continue; } if (preg_match('/(Thread-Index|X-UIDL|Message-ID|X-Text-Classification|X-Mime-Key)/i', $header)) { continue; } $temp_tokens = bayesspam_parse_line($arguement, 'HEADER'); foreach ($temp_tokens as $token) { $tokens[] = $token; } } else { if ($i < $hdr_lines) { $temp_tokens = bayesspam_parse_line($arguement, 'HEADER'); } else { $temp_tokens = bayesspam_parse_line($arguement, 'BODY'); } foreach ($temp_tokens as $token) { $tokens[] = $token; } } } return $tokens; }
/** * temporary function to make use of the deliver class. * In the future the responsible backend should be automaticly loaded * and conf.pl should show a list of available backends. * The message also should be constructed by the message class. * * @param object $composeMessage The message being sent. Please note * that it is passed by reference and * will be returned modified, with additional * headers, such as Message-ID, Date, In-Reply-To, * References, and so forth. * * @return boolean FALSE if delivery failed, or some non-FALSE value * upon success. * */ function deliverMessage(&$composeMessage, $draft = false) { global $send_to, $send_to_cc, $send_to_bcc, $mailprio, $subject, $body, $username, $identity, $idents, $data_dir, $request_mdn, $request_dr, $default_charset, $useSendmail, $domain, $action, $default_move_to_sent, $move_to_sent, $imapServerAddress, $imapPort, $imap_stream_options, $sent_folder, $key; $rfc822_header = $composeMessage->rfc822_header; $abook = addressbook_init(false, true); $rfc822_header->to = $rfc822_header->parseAddress($send_to, true, array(), '', $domain, array(&$abook, 'lookup')); $rfc822_header->cc = $rfc822_header->parseAddress($send_to_cc, true, array(), '', $domain, array(&$abook, 'lookup')); $rfc822_header->bcc = $rfc822_header->parseAddress($send_to_bcc, true, array(), '', $domain, array(&$abook, 'lookup')); $rfc822_header->priority = $mailprio; $rfc822_header->subject = $subject; $special_encoding = ''; if (strtolower($default_charset) == 'iso-2022-jp') { if (mb_detect_encoding($body) == 'ASCII') { $special_encoding = '8bit'; } else { $body = mb_convert_encoding($body, 'JIS'); $special_encoding = '7bit'; } } $composeMessage->setBody($body); $reply_to = ''; $reply_to = $idents[$identity]['reply_to']; if ($reply_to && strpos($reply_to, '@') === FALSE) { $reply_to .= '@' . $domain; } $from_addr = build_from_header($identity); $rfc822_header->from = $rfc822_header->parseAddress($from_addr, true); if ($reply_to) { $rfc822_header->reply_to = $rfc822_header->parseAddress($reply_to, true); } /* Receipt: On Read */ if (isset($request_mdn) && $request_mdn) { $rfc822_header->dnt = $rfc822_header->parseAddress($from_addr, true); } elseif (isset($rfc822_header->dnt)) { unset($rfc822_header->dnt); } /* Receipt: On Delivery */ if (!empty($request_dr)) { //FIXME: it would be better to fiddle with headers inside of the message object or possibly when delivering the message to its destination; is this possible? $rfc822_header->more_headers['Return-Receipt-To'] = $from_addr; } elseif (isset($rfc822_header->more_headers['Return-Receipt-To'])) { unset($rfc822_header->more_headers['Return-Receipt-To']); } /* multipart messages */ if (count($composeMessage->entities)) { $message_body = new Message(); $message_body->body_part = $composeMessage->body_part; $composeMessage->body_part = ''; $mime_header = new MessageHeader(); $mime_header->type0 = 'text'; $mime_header->type1 = 'plain'; if ($special_encoding) { $mime_header->encoding = $special_encoding; } else { $mime_header->encoding = '8bit'; } if ($default_charset) { $mime_header->parameters['charset'] = $default_charset; } $message_body->mime_header = $mime_header; array_unshift($composeMessage->entities, $message_body); $content_type = new ContentType('multipart/mixed'); } else { $content_type = new ContentType('text/plain'); if ($special_encoding) { $rfc822_header->encoding = $special_encoding; } else { $rfc822_header->encoding = '8bit'; } if ($default_charset) { $content_type->properties['charset'] = $default_charset; } } $rfc822_header->content_type = $content_type; $composeMessage->rfc822_header = $rfc822_header; if ($action == 'reply' || $action == 'reply_all') { global $passed_id, $passed_ent_id; $reply_id = $passed_id; $reply_ent_id = $passed_ent_id; } else { $reply_id = ''; $reply_ent_id = ''; } /* Here you can modify the message structure just before we hand it over to deliver; plugin authors note that $composeMessage is sent and modified by reference since 1.5.2 */ do_hook('compose_send', $composeMessage); if (!$useSendmail && !$draft) { require_once SM_PATH . 'class/deliver/Deliver_SMTP.class.php'; $deliver = new Deliver_SMTP(); global $smtpServerAddress, $smtpPort, $smtp_stream_options, $pop_before_smtp, $pop_before_smtp_host; $authPop = isset($pop_before_smtp) && $pop_before_smtp ? true : false; if (empty($pop_before_smtp_host)) { $pop_before_smtp_host = $smtpServerAddress; } get_smtp_user($user, $pass); $stream = $deliver->initStream($composeMessage, $domain, 0, $smtpServerAddress, $smtpPort, $user, $pass, $authPop, $pop_before_smtp_host, $smtp_stream_options); } elseif (!$draft) { require_once SM_PATH . 'class/deliver/Deliver_SendMail.class.php'; global $sendmail_path, $sendmail_args; // Check for outdated configuration if (!isset($sendmail_args)) { if ($sendmail_path == '/var/qmail/bin/qmail-inject') { $sendmail_args = ''; } else { $sendmail_args = '-i -t'; } } $deliver = new Deliver_SendMail(array('sendmail_args' => $sendmail_args)); $stream = $deliver->initStream($composeMessage, $sendmail_path); } elseif ($draft) { global $draft_folder; $imap_stream = sqimap_login($username, false, $imapServerAddress, $imapPort, 0, $imap_stream_options); if (sqimap_mailbox_exists($imap_stream, $draft_folder)) { require_once SM_PATH . 'class/deliver/Deliver_IMAP.class.php'; $imap_deliver = new Deliver_IMAP(); $success = $imap_deliver->mail($composeMessage, $imap_stream, $reply_id, $reply_ent_id, $imap_stream, $draft_folder); sqimap_logout($imap_stream); unset($imap_deliver); $composeMessage->purgeAttachments(); return $success; } else { $msg = '<br />' . sprintf(_("Error: Draft folder %s does not exist."), sm_encode_html_special_chars($draft_folder)); plain_error_message($msg); return false; } } $success = false; if ($stream) { $deliver->mail($composeMessage, $stream, $reply_id, $reply_ent_id); $success = $deliver->finalizeStream($stream); } if (!$success) { // $deliver->dlv_server_msg is not always server's reply $msg = _("Message not sent.") . "<br />\n" . (isset($deliver->dlv_msg) ? $deliver->dlv_msg : ''); if (!empty($deliver->dlv_server_msg)) { // add 'server replied' part only when it is not empty. // Delivery error can be generated by delivery class itself $msg .= '<br />' . _("Server replied:") . ' ' . (isset($deliver->dlv_ret_nr) ? $deliver->dlv_ret_nr . ' ' : '') . nl2br(sm_encode_html_special_chars($deliver->dlv_server_msg)); } plain_error_message($msg); } else { unset($deliver); $imap_stream = sqimap_login($username, false, $imapServerAddress, $imapPort, 0, $imap_stream_options); // mark as replied or forwarded if applicable // global $what, $iAccount, $startMessage, $passed_id, $fwduid, $mailbox; if ($action == 'reply' || $action == 'reply_all' || $action == 'forward' || $action == 'forward_as_attachment') { require SM_PATH . 'functions/mailbox_display.php'; $aMailbox = sqm_api_mailbox_select($imap_stream, $iAccount, $mailbox, array('setindex' => $what, 'offset' => $startMessage), array()); switch ($action) { case 'reply': case 'reply_all': // check if we are allowed to set the \\Answered flag if (in_array('\\answered', $aMailbox['PERMANENTFLAGS'], true)) { $aUpdatedMsgs = sqimap_toggle_flag($imap_stream, array($passed_id), '\\Answered', true, false); if (isset($aUpdatedMsgs[$passed_id]['FLAGS'])) { /** * Only update the cached headers if the header is * cached. */ if (isset($aMailbox['MSG_HEADERS'][$passed_id])) { $aMailbox['MSG_HEADERS'][$passed_id]['FLAGS'] = $aMsg['FLAGS']; } } } break; case 'forward': case 'forward_as_attachment': // check if we are allowed to set the $Forwarded flag (RFC 4550 paragraph 2.8) if (in_array('$forwarded', $aMailbox['PERMANENTFLAGS'], true) || in_array('\\*', $aMailbox['PERMANENTFLAGS'])) { // when forwarding as an attachment from the message // list, passed_id is not used, need to get UID(s) // from the query string // if (empty($passed_id) && !empty($fwduid)) { $ids = explode('_', $fwduid); } else { $ids = array($passed_id); } $aUpdatedMsgs = sqimap_toggle_flag($imap_stream, $ids, '$Forwarded', true, false); foreach ($ids as $id) { if (isset($aUpdatedMsgs[$id]['FLAGS'])) { if (isset($aMailbox['MSG_HEADERS'][$id])) { $aMailbox['MSG_HEADERS'][$id]['FLAGS'] = $aMsg['FLAGS']; } } } } break; } /** * Write mailbox with updated seen flag information back to cache. */ if (isset($aUpdatedMsgs[$passed_id])) { $mailbox_cache[$iAccount . '_' . $aMailbox['NAME']] = $aMailbox; sqsession_register($mailbox_cache, 'mailbox_cache'); } } // move to sent folder // $move_to_sent = getPref($data_dir, $username, 'move_to_sent'); if (isset($default_move_to_sent) && $default_move_to_sent != 0) { $svr_allow_sent = true; } else { $svr_allow_sent = false; } if (isset($sent_folder) && ($sent_folder != '' || $sent_folder != 'none') && sqimap_mailbox_exists($imap_stream, $sent_folder)) { $fld_sent = true; } else { $fld_sent = false; } if (isset($move_to_sent) && $move_to_sent != 0 || !isset($move_to_sent)) { $lcl_allow_sent = true; } else { $lcl_allow_sent = false; } if ($fld_sent && $svr_allow_sent && !$lcl_allow_sent || $fld_sent && $lcl_allow_sent) { if ($action == 'reply' || $action == 'reply_all') { $save_reply_with_orig = getPref($data_dir, $username, 'save_reply_with_orig'); if ($save_reply_with_orig) { $sent_folder = $mailbox; } } require_once SM_PATH . 'class/deliver/Deliver_IMAP.class.php'; $imap_deliver = new Deliver_IMAP(); $imap_deliver->mail($composeMessage, $imap_stream, $reply_id, $reply_ent_id, $imap_stream, $sent_folder); unset($imap_deliver); } // final cleanup // $composeMessage->purgeAttachments(); sqimap_logout($imap_stream); } return $success; }
/** * Recursively walk the tree of mailboxes in the given folder and delete all folders and messages * * @param int index the place in the tree to start, usually 0 * @param stream imap_stream the IMAP connection to send commands to * @param array tree the tree to walk * @param mailbox the name of the root folder to empty * @return void */ function walkTreeInPreOrderEmptyFolder($index, $imap_stream, $tree, $mailbox) { if ($tree[$index]['doIHaveChildren']) { for ($j = 0; $j < count($tree[$index]['subNodes']); $j++) { walkTreeInPreOrderEmptyTrash($tree[$index]['subNodes'][$j], $imap_stream, $tree); } if ($tree[$index]['value'] != $mailbox) { sqimap_mailbox_delete($imap_stream, $tree[$index]['value']); } else { $mbx_response = sqimap_mailbox_select($imap_stream, $mailbox); if ($mbx_response['EXISTS'] > 0) { sqimap_toggle_flag($imap_stream, '1:*', '\\Deleted', true, true); // CLOSE === EXPUNGE and UNSELECT sqimap_run_command($imap_stream, 'CLOSE', false, $response, $message); } } } else { if ($tree[$index]['value'] != $mailbox) { sqimap_mailbox_delete($imap_stream, $tree[$index]['value']); } else { $mbx_response = sqimap_mailbox_select($imap_stream, $mailbox); if ($mbx_response['EXISTS'] > 0) { sqimap_toggle_flag($imap_stream, '1:*', '\\Deleted', true, true); // CLOSE === EXPUNGE and UNSELECT sqimap_run_command($imap_stream, 'CLOSE', false, $response, $message); } } } }
$read = sqimap_run_command($imapConnection, "FETCH {$passed_id} BODY[1.HEADER]", true, $response, $msg, TRUE); $rfc822_header = new Rfc822Header(); $rfc822_header->parseHeader($read); $message->rfc822_header = $rfc822_header; } else { $passed_ent_id = 0; } } $header = $message->header; // gmail does not mark messages as read when retrieving the message body // even though RFC 3501, section 6.4.5 (FETCH Command) says: // "The \Seen flag is implicitly set; if this causes the flags to change, // they SHOULD be included as part of the FETCH responses." // if ($imap_server_type == 'gmail') { sqimap_toggle_flag($imapConnection, $passed_id, '\\Seen', true, true); } /****************************************/ /* Block for handling incoming url vars */ /****************************************/ if (isset($sendreceipt)) { if (!$message->is_mdnsent) { $supportMDN = ServerMDNSupport($aMailbox["PERMANENTFLAGS"]); if (SendMDN($mailbox, $passed_id, $message, $imapConnection) > 0 && $supportMDN) { ToggleMDNflag(true, $imapConnection, $mailbox, $passed_id); $message->is_mdnsent = true; $aMailbox['MSG_HEADERS'][$passed_id]['MESSAGE_OBJECT'] = $message; } } } /***********************************************/