/** * Deletes all items with the specified ids for the specified user. * The items will only be deleted if all rows in groupware_email_items_flags * for the corresponding item have been set to is_deleted=1. Otherwise, * only the is_deleted field for the specified user will be set to 1. * If that is the case and the item gets entirely deleted, the method will * use the accounts-model to check whether there are any accounts flagged * as "is_deleted = 1" and also remove this accounts if no more items * are exiting in the data storage. * * @param array $itemIds A numeric array with all id's of the items that are * about to be deleted * @param integer $userId The id of the user for which the items get deleted. * * @return integer The number of total rows deleted */ public function deleteItemsForUser(array $itemIds, $userId) { $userId = (int) $userId; if ($userId <= 0) { return 0; } $clearedItemIds = array(); $cc = 0; for ($i = 0, $len = count($itemIds); $i < $len; $i++) { $id = (int) $itemIds[$i]; if ($id > 0) { $clearedItemIds[] = $id; $cc++; } } if ($cc == 0) { return 0; } $referenceModel = new Conjoon_Modules_Groupware_Email_Item_Model_References(); // delete all references for the items for the specified user $referenceModel->delete('user_id = ' . $userId . ' AND reference_items_id IN (' . implode(',', $clearedItemIds) . ')'); $flagModel = new Conjoon_Modules_Groupware_Email_Item_Model_Flag(); $flagModel->flagItemsAsDeleted($clearedItemIds, $userId); $deleteValues = $flagModel->areItemsFlaggedAsDeleted($clearedItemIds); // if the second argument to array_filter is ommited, array_filter gets // all keys which values does not equal to false $itemsToDelete = array_filter($deleteValues); $idString = implode(',', array_keys($itemsToDelete)); $deleted = $this->delete('id IN (' . $idString . ')'); if ($deleted > 0) { $referencesModel = new Conjoon_Modules_Groupware_Email_Item_Model_References(); $inboxModel = new Conjoon_Modules_Groupware_Email_Item_Model_Inbox(); $outboxModel = new Conjoon_Modules_Groupware_Email_Item_Model_Outbox(); $attachmentModel = new Conjoon_Modules_Groupware_Email_Attachment_Model_Attachment(); /** * @see Conjoon_Modules_Groupware_Email_Account_Model_Account */ require_once 'Conjoon/Modules/Groupware/Email/Account/Model/Account.php'; $accountModel = new Conjoon_Modules_Groupware_Email_Account_Model_Account(); $referencesModel->delete('is_pending=1 AND user_id = ' . $userId . ' AND groupware_email_items_id IN (' . $idString . ')'); $flagModel->delete('user_id = ' . $userId . ' AND groupware_email_items_id IN (' . $idString . ')'); $attachmentModel->delete('groupware_email_items_id IN (' . $idString . ')'); $inboxModel->delete('groupware_email_items_id IN (' . $idString . ')'); $outboxModel->delete('groupware_email_items_id IN (' . $idString . ')'); $accountModel->removeAsDeletedFlaggedAccounts($userId); } return $deleted; }
/** * Returns the email items based on the passed POST-parameters to the client. * Possible POST parameters are: * * start - the index in the datastore from where to read the first record * limit - the number of records to return * dir - the sort direction, either ASC or DESC * sort - the field to sort. Fields are based upon the properties of the * Conjoon_Modules_Groupware_Email_ItemDto-class and have to be substituted * to their appropriate representatives in the underlying datamodel. * groupwareEmailFoldersId - the id of the folder, for which the items should be loaded. * if this parameter is missing, all emails from all accounts * will be fetched * minDate - this argument is optional - if passed, all emails with a fetched_timestamp * equal to or greater than minDate will be fetched * * * The assigned view variables are: * * items - an array with objects of Conjoon_Modules_Groupware_Email_ItemDto * totalCount - the total count of records available for the requested folder * for this user, or the total count of latest emails for the * user since minDate * version - the version property for Ext.ux.grid.BufferedStore * pendingItems - if a folder id other than 0 was supplied, the number of * pending items will be read out and assigned to this view-variable * */ public function getEmailItemsAction() { require_once 'Conjoon/Modules/Groupware/Email/Item/Filter/Request.php'; require_once 'Conjoon/Util/Array.php'; require_once 'Conjoon/Keys.php'; $auth = Zend_Registry::get(Conjoon_Keys::REGISTRY_AUTH_OBJECT); $userId = $auth->getIdentity()->getId(); $CONTEXT_REQUEST_LATEST = Conjoon_Modules_Groupware_Email_Item_Filter_Request::CONTEXT_REQUEST_LATEST; $CONTEXT_REQUEST = Conjoon_Modules_Groupware_Email_Item_Filter_Request::CONTEXT_REQUEST; if (isset($_POST['minDate']) && !isset($_POST['groupwareEmailFoldersId'])) { $context = $CONTEXT_REQUEST_LATEST; } else { $context = $CONTEXT_REQUEST; } $itemRequestFilter = new Conjoon_Modules_Groupware_Email_Item_Filter_Request($_POST, $context); try { $filteredData = $itemRequestFilter->getProcessedData(); } catch (Zend_Filter_Exception $e) { $this->view->success = true; $this->view->error = null; $this->view->items = array(); $this->view->version = 1; $this->view->totalCount = 0; return; } $sortInfo = array('sort' => $filteredData['sort'], 'dir' => $filteredData['dir'], 'limit' => $filteredData['limit'], 'start' => $filteredData['start']); require_once 'Conjoon/BeanContext/Decorator.php'; require_once 'Conjoon/Modules/Groupware/Email/Item/Filter/ItemResponse.php'; $itemResponseFilter = new Conjoon_Modules_Groupware_Email_Item_Filter_ItemResponse(array(), Conjoon_Filter_Input::CONTEXT_RESPONSE); $pendingItems = -1; if ($context == $CONTEXT_REQUEST) { // check if folder is remote folder /** * @see Conjoon_Text_Parser_Mail_MailboxFolderPathJsonParser */ require_once 'Conjoon/Text/Parser/Mail/MailboxFolderPathJsonParser.php'; $parser = new Conjoon_Text_Parser_Mail_MailboxFolderPathJsonParser(); $pathInfo = $parser->parse($filteredData['path']); /** * @see Conjoon_Modules_Groupware_Email_Folder_Facade */ require_once 'Conjoon/Modules/Groupware/Email/Folder/Facade.php'; $facade = Conjoon_Modules_Groupware_Email_Folder_Facade::getInstance(); if ($facade->isRemoteFolder((int) $pathInfo['rootId'])) { /** * @see Conjoon_Modules_Groupware_Email_Item_ItemListRequestFacade */ require_once 'Conjoon/Modules/Groupware/Email/Item/ItemListRequestFacade.php'; $listFacade = Conjoon_Modules_Groupware_Email_Item_ItemListRequestFacade::getInstance(); $itemData = $listFacade->getEmailItemList($pathInfo, $userId, $sortInfo, true); $this->view->success = true; $this->view->error = null; $this->view->items = $itemData['items']; $this->view->version = 1; $this->view->totalCount = $itemData['totalCount']; $this->view->pendingItems = $itemData['pendingItems']; return; } // get the number of emails currently available for this folder // and this user require_once 'Conjoon/Modules/Groupware/Email/Item/Model/Item.php'; require_once 'Conjoon/Modules/Groupware/Email/Folder/Model/Folder.php'; $folderModel = new Conjoon_Modules_Groupware_Email_Folder_Model_Folder(); $itemModel = new Conjoon_Modules_Groupware_Email_Item_Model_Item(); $totalCount = $folderModel->getItemCountForFolderAndUser($filteredData['groupwareEmailFoldersId'], $userId); if ($totalCount == 0) { $this->view->success = true; $this->view->error = null; $this->view->items = array(); $this->view->version = 1; $this->view->totalCount = 0; $this->view->pendingItems = 0; return; } $decoratedModel = new Conjoon_BeanContext_Decorator($itemModel, $itemResponseFilter); $rows = $decoratedModel->getEmailItemsForAsDto($userId, $filteredData['groupwareEmailFoldersId'], $sortInfo); $pendingItems = $folderModel->getPendingCountForFolderAndUser($filteredData['groupwareEmailFoldersId'], $userId); } else { if ($context == $CONTEXT_REQUEST_LATEST) { require_once 'Conjoon/BeanContext/Decorator.php'; require_once 'Conjoon/Modules/Groupware/Email/Item/Filter/ItemResponse.php'; require_once 'Conjoon/Modules/Groupware/Email/Item/Model/Inbox.php'; $itemInboxModel = new Conjoon_Modules_Groupware_Email_Item_Model_Inbox(); $totalCount = $itemInboxModel->getLatestItemCount($userId, $filteredData['minDate']); if ($totalCount == 0) { $this->view->success = true; $this->view->error = null; $this->view->items = array(); $this->view->version = 1; $this->view->totalCount = 0; return; } $decoratedModel = new Conjoon_BeanContext_Decorator($itemInboxModel, $itemResponseFilter); $rows = $decoratedModel->getLatestEmailItemsForAsDto($userId, $filteredData['minDate'], $sortInfo); } } $this->view->success = true; $this->view->error = null; $this->view->items = $rows; $this->view->pendingItems = $pendingItems; $this->view->version = 1; $this->view->totalCount = $totalCount; }
/** * Returns an assoc array with the data of an draft. The returned array * has all properties as according to Conjoon_Modules_Groupware_Email_Draft. * * @param integer $itemId * @param integer $userId * @param string $context The context used to fetch the draft. Important * when dealign with contexts "reply", "reply_all" and "forward". * - context "forward": fields "references" and "in_reply_to" will be set * to an empty string * - context "reply", "reply_all": "in_reply_to" will be set to the message-id * of the email, references will be concatenated with the message-id * * @return array */ public function getDraft($itemId, $userId, $context = '') { $itemId = (int) $itemId; if ($itemId <= 0) { return array(); } $itemModel = new Conjoon_Modules_Groupware_Email_Item_Model_Item(); $row = $itemModel->fetchRow($itemModel->select()->from($itemModel)->where('id = ?', $itemId)); if (!$row) { return array(); } $draft = array('id' => $row->id, 'date' => $row->date, 'subject' => $row->subject, 'from' => $row->from, 'reply_to' => $row->reply_to, 'to' => $row->to, 'cc' => $row->cc, 'bcc' => $row->bcc, 'in_reply_to' => $row->in_reply_to, 'references' => $row->references, 'content_text_plain' => $row->content_text_plain, 'content_text_html' => $row->content_text_html, 'groupware_email_folders_id' => $row->groupware_email_folders_id, 'attachments' => array()); // clear memory unset($row); // set in_reply_to, references according to the context switch ($context) { case Conjoon_Modules_Groupware_Email_Keys::REFERENCE_TYPE_REPLY: case Conjoon_Modules_Groupware_Email_Keys::REFERENCE_TYPE_REPLY_ALL: $inboxModel = new Conjoon_Modules_Groupware_Email_Item_Model_Inbox(); $messageId = $inboxModel->getMessageIdForItem($draft['id']); if ($messageId != "") { $draft['in_reply_to'] = $messageId; $draft['references'] = $draft['references'] != '' ? $draft['references'] . ' ' . $messageId : $messageId; } else { $draft['in_reply_to'] = ''; $draft['references'] = ''; } break; case Conjoon_Modules_Groupware_Email_Keys::REFERENCE_TYPE_FORWARD: $draft['in_reply_to'] = ''; $draft['references'] = ''; case '': case Conjoon_Modules_Groupware_Email_Keys::REFERENCE_TYPE_EDIT: /** * @see Conjoon_Modules_Groupware_Email_Attachment_Model_Attachment */ require_once 'Conjoon/Modules/Groupware/Email/Attachment/Model/Attachment.php'; $attachmentModel = new Conjoon_Modules_Groupware_Email_Attachment_Model_Attachment(); $draft['attachments'] = $attachmentModel->getAttachmentsForItem($draft['id'])->toArray(); break; } // check if the item is available in outbox and get the id of it under which it was // created. Otherwise, get the standard account out of the accounts-table $outboxModel = new Conjoon_Modules_Groupware_Email_Item_Model_Outbox(); $accIdRow = $outboxModel->fetchRow($outboxModel->select()->from($outboxModel, array('groupware_email_accounts_id'))->where('groupware_email_items_id = ? ', $draft['id'])); $accountModel = new Conjoon_Modules_Groupware_Email_Account_Model_Account(); if (!$accIdRow) { $accId = $accountModel->getStandardAccountIdForUser($userId); } else { $accId = $accIdRow->groupware_email_accounts_id; // check if the account still exists $account = $accountModel->getAccount($accId, $userId); if (empty($account)) { $accId = $accountModel->getStandardAccountIdForUser($userId); if ($accId == 0) { return array(); } } } $draft['groupware_email_accounts_id'] = $accId; return $draft; }
/** * @param int $userId The id of the user to process the email-accounts for. * @param int $accountId The id of the account to fetch the emails for * * @return Array An associative array with the keys of the fetched and saved * emails in the array 'fetched', and error-messages in the key 'errors'. */ private function _fetchEmails($userId, Conjoon_Modules_Groupware_Email_Account $account) { $fetchedEmailIds = array(); $fetchedEmailErrors = array(); $userId = (int) $userId; if ($userId <= 0) { return $fetchedEmailIds; } $transports = array(Conjoon_Modules_Groupware_Email_Account::PROTOCOL_POP3 => "Conjoon_Mail_Storage_Pop3", Conjoon_Modules_Groupware_Email_Account::PROTOCOL_IMAP => "Conjoon_Mail_Storage_Imap"); self::_setIconvEncoding(self::ICONV_UTF_8); $accountId = $account->getId(); $transport = $transports[$account->getProtocol()]; $isPop3 = $account->getProtocol() == Conjoon_Modules_Groupware_Email_Account::PROTOCOL_POP3; $isCopyLeftOnServer = $account->isCopyLeftOnServer(); $cconf = array('host' => $account->getServerInbox(), 'port' => $account->getPortInbox(), 'user' => $account->getUsernameInbox(), 'password' => $account->getPasswordInbox()); $ssl = $account->getInboxConnectionType(); if ($ssl == 'SSL' || $ssl == 'TLS') { $cconf['ssl'] = $ssl; } $mail = new $transport($cconf); $hasUniqueId = $mail->hasUniqueId; $mailCount = count($mail); if ($hasUniqueId) { $uidl = $mail->getUniqueId(); $this->_cacheUidl($uidl, $accountId, $this->_computeChunkSize($mailCount)); // this is to prevent undefined indexes when the count of uidl // differs from the number of emails fetched. This is a very rare error // that occures now and then - see http://wiki.conjoon.org/ticket/189 // it's assumed its related to connection aborts during communication // with the mail server if (count($uidl) != $mailCount) { return array('fetched' => $fetchedEmailIds, 'errors' => array('Could not retrieve messages - number of items in unique id list ' . 'differs from total number of emails on the server: ' . 'Number of unique ids: ' . count($uidl) . '; number of messages: ' . $mailCount . '; ' . 'This is possibly related to a connection abort while attempting to fetch ' . 'messages from a server. Please try again.')); } } $messagesToRemove = array(); for ($oo = 1; $oo < $mailCount + 1; $oo++) { $messageNum = $oo; $this->_attachmentCounter = 1; $emailItem = array(); $rawHeader = ""; $rawBody = ""; // check if the account supports UIDL, and skip the message // if it is already available in the db if ($hasUniqueId) { if ($this->_isUidPresent($accountId, $uidl[$oo]) === true) { if (!$isCopyLeftOnServer && $isPop3) { $messagesToRemove[] = $messageNum; } continue; } else { $emailItem['uid'] = $uidl[$oo]; } } // check here if we can process the message, taking memory limit // of php ini into account if (!$this->_maxMemory) { $this->_maxMemory = Conjoon_Util_Format::convertToBytes(ini_get('memory_limit')); } $s = $mail->getSize($messageNum); if ($s == 0) { $fetchedEmailErrors[] = 'Could not save message No. ' . $messageNum . ' - message size seems to be 0 bytes'; continue; } if ($this->_maxMemory / $s <= 17) { $fetchedEmailErrors[] = 'Could not save message No. ' . $messageNum . ' - message could exceed available memory size (' . $this->_maxMemory . ' bytes, message size ' . $s . ').'; continue; } self::_splitMessage($mail->getRawMessage($messageNum), $rawHeader, $rawBody); $message = new Conjoon_Mail_Message(array('headers' => $rawHeader, 'noToplines' => true, 'content' => $rawBody)); $messageId = ""; try { $messageId = $message->messageId; } catch (Zend_Mail_Exception $e) { // ignore } $emailItem['messageId'] = $messageId; $mail->noop(); // check here if we can remove the mail from the server // check first if UIDL is supported. if not, look up the // message if (!$hasUniqueId) { $id = $this->_isMessageIdPresent($messageId, $accountId, $rawHeader, $rawBody); $mail->noop(); if ($id === true) { if (!$isCopyLeftOnServer && $isPop3) { $messagesToRemove[] = $messageNum; } continue; } } else { if (!$isCopyLeftOnServer && $isPop3) { $messagesToRemove[] = $messageNum; } } $mail->noop(); $emailItem['attachments'] = array(); $emailItem['userId'] = $userId; try { $emailItem['from'] = $message->from; } catch (Zend_Mail_Exception $e) { // may be changed to localized header values by anti vir programs try { $emailItem['from'] = $message->von; } catch (Zend_Mail_Exception $e) { $emailItem['from'] = "-"; } } if (!isset($emailItem['from'])) { throw new Zend_Mail_Exception("No header with the name \"from\" found. Please check if you have an anti virus program runnning in the background. Some are known to change the header values to localized derivates."); } $emailItem['subject'] = ""; // very few emails will come in without a subject. try { $emailItem['subject'] = $message->subject; } catch (Zend_Mail_Exception $e) { try { // may be changed to localized header values by anti vir programs $emailItem['subject'] = $message->betreff; } catch (Zend_Mail_exception $e) { // ignore } } catch (Zend_Mail_exception $e) { // ignore } $emailItem['date'] = ""; // date field will be given presedence try { $emailItem['date'] = $message->date; } catch (Zend_Mail_Exception $e) { // ignore } // if date not found, look up deliveryDate if (!$emailItem['date']) { try { $emailItem['date'] = $message->deliveryDate; } catch (Zend_Mail_Exception $e) { // ignore } if (!$emailItem['date']) { try { // may be changed to localized header values by anti vir programs $emailItem['date'] = $message->datum; } catch (Zend_Mail_Exception $e) { // ignore } // and one further down to fall back to actual // date if none was found if (!$emailItem['date']) { /** * @see Zend_Date */ require_once 'Zend/Date.php'; $zd = new Zend_Date(); $emailItem['date'] = $zd->get(Zend_Date::RFC_2822); } } } try { $emailItem['to'] = $message->to; } catch (Zend_Mail_Exception $e) { // "to" might not be used, instead "cc" will be probably available // then $emailItem['to'] = ""; } if (!$emailItem['to']) { try { // may be changed to localized header values by anti vir programs $emailItem['to'] = $message->an; } catch (Zend_Mail_Exception $e) { // ignore } } try { $emailItem['cc'] = $message->cc; } catch (Zend_Mail_Exception $e) { $emailItem['cc'] = ''; } try { $emailItem['references'] = $message->references; } catch (Zend_Mail_Exception $e) { $emailItem['references'] = ''; } try { $emailItem['replyTo'] = $message->replyTo; } catch (Zend_Mail_Exception $e) { $emailItem['replyTo'] = ''; } try { $emailItem['inReplyTo'] = $message->inReplyTo; } catch (Zend_Mail_Exception $e) { $emailItem['inReplyTo'] = ''; } $encodingInformation = $this->_getEncodingInformation($message); $contentType = $encodingInformation['contentType']; $mail->noop(); try { switch ($contentType) { case 'text/plain': $emailItem['contentTextPlain'] = $this->_decode($message->getContent(), $encodingInformation); break; case 'text/html': $emailItem['contentTextHtml'] = $this->_decode($message->getContent(), $encodingInformation); break; case 'multipart/mixed': $this->_parseMultipartMixed($message, $emailItem); break; case 'multipart/alternative': $this->_parseMultipartAlternative($message, $emailItem); break; case 'multipart/related': $this->_parseMultipartRelated($message, $emailItem); break; case 'multipart/signed': $this->_parseMultipartSigned($message, $emailItem); break; case 'multipart/report': $this->_parseMultipartReport($message, $emailItem); break; default: $emailItem['contentTextPlain'] = $this->_decode($message->getContent(), $encodingInformation); break; } } catch (Exception $e) { $fetchedEmailErrors[] = "Could not save message No. " . $messageNum . " with the subject \"" . $emailItem['subject'] . "\". " . "An unexpected error occurred: \"" . $e->getMessage() . "\""; $mail->noop(); continue; } $mail->noop(); if (!isset($emailItem['contentTextPlain'])) { $emailItem['contentTextPlain'] = ''; } if (!isset($emailItem['contentTextHtml'])) { $emailItem['contentTextHtml'] = ''; } $this->_assignJunkStatus($userId, $emailItem); $this->_assignFolderId($userId, $accountId, $emailItem); $emailItem['rawHeader'] =& $rawHeader; $emailItem['rawBody'] =& $rawBody; $mail->noop(); if (!$emailItem['messageId']) { $emailItem['hash'] = Conjoon_Modules_Groupware_Email_Item_Model_Inbox::computeMessageHash($rawHeader, $rawBody); } $mail->noop(); $saved = $this->_saveEmail($emailItem, $userId); $mail->noop(); if (is_int($saved) > 0) { $fetchedEmailIds[] = $saved; } else { $fetchedEmailErrors[] = "Could not save Email Message with the " . " subject \"" . $emailItem['subject'] . "\"" . ", date \"" . $emailItem['date'] . "\"" . ": " . $saved; continue; } $mail->noop(); if (!$isCopyLeftOnServer && $isPop3) { $messagesToRemove[] = $messageNum; } } $messagesToRemove = array_unique($messagesToRemove); foreach ($messagesToRemove as $id) { $mail->removeMessage($id); } self::_setIconvEncoding(self::ICONV_OLD); return array('fetched' => $fetchedEmailIds, 'errors' => $fetchedEmailErrors); }