/** * Set the temporary file * * @param \GO\Base\Fs\File $file * @throws Exception */ public function setTempFile(\GO\Base\Fs\File $file) { if (!$file->isTempFile()) { throw new \Exception("File {$file->name} is not a temporary file"); } $this->_tmp_file = $file->stripTempPath(); }
protected function actionProxy($params) { $feed = $params['feed']; if ($feed != '' && strpos($feed, 'http') === 0) { header('Content-Type: text/xml'); if (function_exists('curl_init')) { $httpclient = new \GO\Base\Util\HttpClient(); $xml = $httpclient->request($feed); } else { if (!\GO\Base\Fs\File::checkPathInput($feed)) { throw new \Exception("Invalid request"); } $xml = @file_get_contents($feed); } if ($xml) { //fix relative images preg_match('/(.*:\\/\\/[^\\/]+)\\//', $feed, $matches); $baseUrl = $matches[1]; $xml = str_replace('src="/', 'src="' . $baseUrl . '/', $xml); $xml = str_replace('src="/', 'src="' . $baseUrl . '/', $xml); $xml = str_replace('href="/', 'href="' . $baseUrl . '/', $xml); $xml = str_replace('href="/', 'href="' . $baseUrl . '/', $xml); $xml = str_replace('<content:encoded>', '<content>', $xml); $xml = str_replace('</content:encoded>', '</content>', $xml); $xml = str_replace('</dc:creator>', '</author>', $xml); echo str_replace('<dc:creator', '<author', $xml); } } }
/** * Moves a file from one location to another * * @param string $sourcePath The path to the file which should be moved * @param string $destinationPath The full destination path, so not just the destination parent node * @return int */ public function move($sourcePath, $destinationPath) { \GO::debug("ObjectTree::move({$sourcePath}, {$destinationPath})"); $moveable = $this->getNodeForPath($sourcePath); $destination = $this->getNodeForPath(dirname($destinationPath)); $targetServerPath = $destination->getServerPath() . '/' . \GO\Base\Fs\File::utf8Basename($destinationPath); $moveable->move($targetServerPath); }
public static function save(\GO\Base\Fs\File $file, array $config) { $configData = "<?php\n/**\n" . " * Group-Office configuration file.\n" . " * Visit https://www.group-office.com/wiki/Configuration_file for available values\n" . " */\n\n"; $configReflection = new ReflectionClass(GO::config()); $defaults = $configReflection->getDefaultProperties(); foreach ($config as $key => $value) { if (!isset($defaults[$key]) || $defaults[$key] !== $value) { $configData .= '$config["' . $key . '"]=' . var_export($value, true) . ';' . "\n"; } } //make sure directory exists $file->parent()->create(); //clear opcache in PHP 5.5 if (function_exists('opcache_invalidate')) { opcache_invalidate($file->path(), true); } return file_put_contents($file->path(), $configData); }
public function actionData($params) { $response = array('success' => true, 'data' => array()); try { $customCssFolder = new Folder(GO::config()->file_storage_path . 'customcss'); if (!$customCssFolder->exists()) { $customCssFolder->create(0755); } $cssFile = new File(GO::config()->file_storage_path . 'customcss/style.css'); $jsFile = new File(GO::config()->file_storage_path . 'customcss/javascript.js'); if (Http::isPostRequest()) { if (isset($_POST['css'])) { $cssFile->putContents($_POST['css']); } if (isset($_POST['javascript'])) { $jsFile->putContents($_POST['javascript']); } } if ($cssFile->exists()) { $response['data']['css'] = $cssFile->getContents(); } else { $response['data']['css'] = '/* * Put custom styles here that will be applied to Group-Office. You can use the select file button to upload your logo and insert the URL in to this stylesheet. */ /* this will override the logo at the top right */ #headerLeft{ background-image:url(/insert/url/here) !important; } /* this will override the logo at the login screen */ .go-app-logo { background-image:url(/insert/url/here) !important; }'; } if ($jsFile->exists()) { $response['data']['javascript'] = $jsFile->getContents(); } } catch (Exception $e) { $response['feedback'] = $e->getMessage(); $response['success'] = false; } echo $this->renderJson($response); }
/** * The code that needs to be called when the cron is running * * If $this->enableUserAndGroupSupport() returns TRUE then the run function * will be called for each $user. (The $user parameter will be given) * * If $this->enableUserAndGroupSupport() returns FALSE then the * $user parameter is null and the run function will be called only once. * * @param CronJob $cronJob * @param User $user [OPTIONAL] */ public function run(CronJob $cronJob, User $user = null) { GO::session()->runAsRoot(); $licenseFile = \GO::getLicenseFile(); $temporaryLicenseFile = new \GO\Base\Fs\File(GO::config()->file_storage_path . 'license/' . $licenseFile->name()); if ($temporaryLicenseFile->exists()) { if (!$temporaryLicenseFile->move($licenseFile)) { throw new \Exception("Could not move license file to Group-Office root!"); } else { if (!GO::scriptCanBeDecoded()) { GO\Base\Mail\AdminNotifier::sendMail("Group-Office license invalid", "You attempted to install a license but the license file you provided didn't work. Please contant Intermesh about this error."); } else { //add all users to the modules they have access too \GO\Professional\License::autoConfigureModulePermissions(); GO\Base\Mail\AdminNotifier::sendMail("Group-Office license installed successfully!", "Your license was installed and the new users were automatically added to the App permissions if necessary.\n\nThank you for using Group-Office!"); } } } }
protected function actionRedirect() { $tmpFile = \GO\Base\Fs\File::tempFile(); $tmpFile->putContents(\GO::user()->id); if (empty(\GO::config()->phpbb3_url)) { throw new \Exception('You must configure phpbb3_url in your config.php file'); } $url = \GO::config()->phpbb3_url . '?goauth=' . base64_encode($tmpFile->path()) . '&sid=' . md5(uniqid(time())); header('Location: ' . $url); exit; }
/** * Send the email to the users * * @param \GO\Base\Model\User $user * @param eventAndTaskPdf $pdf * @return Boolean */ private function _sendEmail(\GO\Base\Model\User $user, $pdf) { $filename = \GO\Base\Fs\File::stripInvalidChars($user->name) . '.pdf'; //Set the PDF filename $filename = str_replace(',', '', $filename); $mailSubject = \GO::t('cronEventAndTaskReportMailerSubject', 'calendar'); $body = \GO::t('cronEventAndTaskReportMailerContent', 'calendar'); $message = \GO\Base\Mail\Message::newInstance($mailSubject)->setFrom(\GO::config()->webmaster_email, \GO::config()->title)->addTo($user->email); $message->setHtmlAlternateBody(nl2br($body)); $message->attach(\Swift_Attachment::newInstance($pdf, $filename, 'application/pdf')); \GO::debug('CRON SEND MAIL TO: ' . $user->email); return \GO\Base\Mail\Mailer::newGoInstance()->send($message); }
/** * Export the contact model to a .csv, including the company. * * @param array $params */ public function export($params) { GO::$disableModelCache = true; GO::setMaxExecutionTime(420); // Load the data from the session. $findParams = \GO::session()->values['contact']['findParams']; $findParams->getCriteria()->recreateTemporaryTables(); $model = \GO::getModel(\GO::session()->values['contact']['model']); // Include the companies $findParams->joinRelation('company', 'LEFT'); // Let the export handle all found records without a limit $findParams->limit(0); // Create the statement $stmt = $model->find($findParams); // Create the csv file $csvFile = new \GO\Base\Fs\CsvFile(\GO\Base\Fs\File::stripInvalidChars('export.csv')); // Output the download headers \GO\Base\Util\Http::outputDownloadHeaders($csvFile, false); $csvWriter = new \GO\Base\Csv\Writer('php://output'); $headerPrinted = false; $attrs = array(); $compAttrs = array(); foreach ($stmt as $m) { $iterationStartUnix = time(); if (!$headerPrinted) { $attrs = $m->getAttributes(); $compAttrs = $m->company->getAttributes(); } $header = array(); $record = array(); foreach ($attrs as $attr => $val) { if (!$headerPrinted) { $header[$attr] = $m->getAttributeLabel($attr); } $record[$attr] = $m->{$attr}; } foreach ($compAttrs as $cattr => $cval) { if (!$headerPrinted) { $header[GO::t('company', 'addressbook') . $cattr] = GO::t('company', 'addressbook') . ':' . $m->company->getAttributeLabel($cattr); } $record[GO::t('company', 'addressbook') . $cattr] = $m->company->{$cattr}; } if (!$headerPrinted) { $csvWriter->putRecord($header); $headerPrinted = true; } $csvWriter->putRecord($record); } }
public function __construct($prefixString = '') { if (!\GO::modules()->isInstalled('files')) { throw new \Exception('The current action requires the files module to be activated for the current user.'); } // Make sure the current user's folder exists. $userFolderModel = \GO\Files\Model\Folder::model()->findHomeFolder(\GO::user()); if (empty($userFolderModel)) { $userFolder = new \GO\Base\Fs\Folder(\GO::config()->file_storage_path . 'users/' . \GO::user()->username); $userFolder->create(); $userFolderModel = new \GO\Files\Model\Folder(); $userFolderModel->findByPath('users/' . \GO::user()->username, true); } parent::__construct(\GO::config()->file_storage_path . $userFolderModel->path . '/' . $prefixString . \GO\Base\Util\Date::get_timestamp(time(), true) . '.log'); }
public function createTempFile() { if (!$this->hasTempFile()) { $tmpFile = new \GO\Base\Fs\File($this->getTempDir() . \GO\Base\Fs\File::stripInvalidChars($this->name)); // This fix for duplicate filenames in forwards caused screwed up attachment names! // A possible new fix should be made in ImapMessage->getAttachments() // // $file = new \GO\Base\Fs\File($this->name); // $tmpFile = new \GO\Base\Fs\File($this->getTempDir().uniqid(time()).'.'.$file->extension()); if (!$tmpFile->exists()) { $imap = $this->account->openImapConnection($this->mailbox); $imap->save_to_file($this->uid, $tmpFile->path(), $this->number, $this->encoding, true); } $this->setTempFile($tmpFile); } return $this->getTempFile(); }
protected function actionCreateFile($params) { $filename = \GO\Base\Fs\File::stripInvalidChars($params['filename']); if (empty($filename)) { throw new \Exception("Filename can not be empty"); } $template = \GO\Files\Model\Template::model()->findByPk($params['template_id']); $folder = \GO\Files\Model\Folder::model()->findByPk($params['folder_id']); $path = \GO::config()->file_storage_path . $folder->path . '/' . $filename; if (!empty($template->extension)) { $path .= '.' . $template->extension; } $fsFile = new \GO\Base\Fs\File($path); $fsFile->putContents($template->content); $fileModel = \GO\Files\Model\File::importFromFilesystem($fsFile); if (!$fileModel) { throw new Exception("Could not create file"); } return array('id' => $fileModel->id, 'success' => true); }
public function setParams($response, $view = false) { if (!$view) { $responses = array($response); } else { $responses = $response['results']; } $headers = true; foreach ($responses as $r) { $this->_view = $view; $this->_start_time = $r['start_time']; $this->_end_time = $r['end_time']; $this->_title = !empty($this->_view) ? \GO\Base\Fs\File::stripInvalidChars($this->_view->name) . ': ' . \GO\Base\Fs\File::stripInvalidChars($r['title']) : \GO\Base\Fs\File::stripInvalidChars($r['title']); $this->_days = ceil(($this->_end_time - $this->_start_time) / 86400); $this->_date_range_text = $this->_days > 1 ? date(\GO::user()->completeDateFormat, $this->_start_time) . ' - ' . date(\GO::user()->completeDateFormat, $this->_end_time) : date(\GO::user()->completeDateFormat, $this->_start_time); $this->_results = $r['results']; $this->_loadCurrentCalendar($r['calendar_id']); $this->_processEvents(!$view, $headers, $view ? $r['view_calendar_name'] : ''); $headers = false; } }
/** * Creates a new file in the directory * * data is a readable stream resource * * @param string $name Name of the file * @param resource $data Initial payload * @return void */ public function createFile($name, $data = null) { \GO::debug("FSD::createFile({$name})"); $folder = $this->_getFolder(); if (!$folder->checkPermissionLevel(\GO\Base\Model\Acl::WRITE_PERMISSION)) { throw new Sabre\DAV\Exception\Forbidden(); } $newFile = new \GO\Base\Fs\File($this->path . '/' . $name); if ($newFile->exists()) { throw new \Exception("File already exists!"); } $tmpFile = \GO\Base\Fs\File::tempFile(); $tmpFile->putContents($data); if (!\GO\Files\Model\File::checkQuota($tmpFile->size())) { $tmpFile->delete(); throw new Sabre\DAV\Exception\InsufficientStorage(); } // $newFile->putContents($data); $tmpFile->move($folder->fsFolder, $name); $folder->addFile($name); }
public function output() { $this->_sendHeaders(); $this->_setupExcel(); if ($this->header) { if ($this->humanHeaders) { $this->_write(array_values($this->getLabels())); } else { $this->_write(array_keys($this->getLabels())); } } while ($record = $this->store->nextRecord()) { $record = $this->prepareRecord($record); $this->_write($record); } // Hack to write contents of file to string $writer = PHPExcel_IOFactory::createWriter($this->phpExcel, 'Excel5'); //$tmpFilename = tempnam('./temp', 'tmp'); $file = \GO\Base\Fs\File::tempFile(); $writer->save($file->path()); $file->output(); $file->delete(); }
/** * * @param type $params * @return boolean * @throws Exception */ protected function actionImport($params) { if ($this->client->getAccessToken()) { $file = $this->service->files->get(\GO::session()->values['googledrive']['editing'][$params[id]]['gd_id']); $goFile = \GO\Files\Model\File::model()->findByPk(\GO::session()->values['googledrive']['editing'][$params[id]]['go_file_id']); $mimeType = $goFile->fsFile->mimeType(); //hack for strange gdocs mimetype if ($mimeType == 'application/vnd.oasis.opendocument.spreadsheet') { $mimeType = 'application/x-vnd.oasis.opendocument.spreadsheet'; } $downloadUrl = isset($file->exportLinks[$mimeType]) ? $file->exportLinks[$mimeType] : false; if ($downloadUrl) { $tmpFile = \GO\Base\Fs\File::tempFile($goFile->name); $request = new Google_HttpRequest($downloadUrl, 'GET', null, null); $httpRequest = Google_Client::$io->authenticatedRequest($request); if ($httpRequest->getResponseHttpCode() == 200) { $tmpFile->putContents($httpRequest->getResponseBody()); $goFile->replace($tmpFile); $this->service->files->delete(\GO::session()->values['googledrive']['editing'][$params[id]]['gd_id']); unset(\GO::session()->values['googledrive']['editing'][$params[id]]); $response['success'] = true; } else { throw new Exception("Got HTTP response code " . $httpRequest->getResponseHttpCode() . " from Google"); } } else { var_dump($file->exportLinks); throw new Exception("Document type " . $mimeType . " is not supported"); } $this->saveToken(); } else { throw new Exception("No access to Google!"); } if (!$response['success']) { throw new Exception("Failed to import file!"); } return $response; }
/** * Download a file * * @param string $url * @param \GO\Base\Fs\File $outputFile * @param array $params * @return boolean */ public function downloadFile($url, \GO\Base\Fs\File $outputFile, $params = array()) { $this->_lastDownloadUrl = $url; $this->_initRequest($url, $params); $fp = fopen($outputFile->path(), 'w'); curl_setopt($this->_curl, CURLOPT_FILE, $fp); curl_setopt($this->_curl, CURLOPT_HEADERFUNCTION, array($this, 'readHeader')); $response = curl_exec($this->_curl); fclose($fp); if ($outputFile->size()) { return true; } else { return false; } }
public static function handleUpload() { $tmpFolder = new \GO\Base\Fs\Folder(\GO::config()->tmpdir . 'uploadqueue'); //$tmpFolder->delete(); $tmpFolder->create(); // $files = \GO\Base\Fs\File::moveUploadedFiles($_FILES['attachments'], $tmpFolder); // \GO::session()->values['files']['uploadqueue'] = array(); // foreach ($files as $file) { // \GO::session()->values['files']['uploadqueue'][] = $file->path(); // } if (!isset(\GO::session()->values['files']['uploadqueue'])) { \GO::session()->values['files']['uploadqueue'] = array(); } $targetDir = $tmpFolder->path(); // Get parameters $chunk = isset($_POST["chunk"]) ? $_POST["chunk"] : 0; $chunks = isset($_POST["chunks"]) ? $_POST["chunks"] : 0; $fileName = isset($_POST["name"]) ? $_POST["name"] : ''; // Clean the fileName for security reasons $fileName = \GO\Base\Fs\File::stripInvalidChars($fileName); // Make sure the fileName is unique but only if chunking is disabled // if ($chunks < 2 && file_exists($targetDir . DIRECTORY_SEPARATOR . $fileName)) { // $ext = strrpos($fileName, '.'); // $fileName_a = substr($fileName, 0, $ext); // $fileName_b = substr($fileName, $ext); // // $count = 1; // while (file_exists($targetDir . DIRECTORY_SEPARATOR . $fileName_a . '_' . $count . $fileName_b)) // $count++; // // $fileName = $fileName_a . '_' . $count . $fileName_b; // } // Look for the content type header if (isset($_SERVER["HTTP_CONTENT_TYPE"])) { $contentType = $_SERVER["HTTP_CONTENT_TYPE"]; } if (isset($_SERVER["CONTENT_TYPE"])) { $contentType = $_SERVER["CONTENT_TYPE"]; } if (!in_array($targetDir . DIRECTORY_SEPARATOR . $fileName, \GO::session()->values['files']['uploadqueue'])) { \GO::session()->values['files']['uploadqueue'][] = $targetDir . DIRECTORY_SEPARATOR . $fileName; } $file = new \GO\Base\Fs\File($targetDir . DIRECTORY_SEPARATOR . $fileName); if ($file->exists() && $file->size() > \GO::config()->max_file_size) { throw new \Exception("File too large"); } // Handle non multipart uploads older WebKit versions didn't support multipart in HTML5 if (strpos($contentType, "multipart") !== false) { if (isset($_FILES['file']['tmp_name']) && is_uploaded_file($_FILES['file']['tmp_name'])) { // Open temp file $out = fopen($targetDir . DIRECTORY_SEPARATOR . $fileName, $chunk == 0 ? "wb" : "ab"); if ($out) { // Read binary input stream and append it to temp file $in = fopen($_FILES['file']['tmp_name'], "rb"); if ($in) { while ($buff = fread($in, 4096)) { fwrite($out, $buff); } } else { die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}'); } fclose($in); fclose($out); @unlink($_FILES['file']['tmp_name']); } else { die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}'); } } else { die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}'); } } else { // Open temp file $out = fopen($targetDir . DIRECTORY_SEPARATOR . $fileName, $chunk == 0 ? "wb" : "ab"); if ($out) { // Read binary input stream and append it to temp file $in = fopen("php://input", "rb"); if ($in) { while ($buff = fread($in, 4096)) { fwrite($out, $buff); } } else { die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}'); } fclose($in); fclose($out); } else { die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}'); } } // Return JSON-RPC response die('{"jsonrpc" : "2.0", "result": null, "success":true, "id" : "id"}'); }
/** * Run from the browser's address bar. Collects all language files, and puts * them in a zip file in the file storage path, respecting the folder * structure. I.e., you can later unpack the file contents to the * Group-Office path. * @param type $params */ protected function actionZipLanguage($params) { if (!empty($params['lang'])) { $langCode = $params['lang']; } else { die('<font color="red"><i>The GET parameter lang is required for the zipLanguage action!</i></font>'); } $fileNames = array(); //gather file list in array $commonLangFolder = new \GO\Base\Fs\Folder(\GO::config()->root_path . 'language/'); if ($commonLangFolder->exists()) { $commonLangFolderContentArr = $commonLangFolder->ls(); $moduleModelArr = \GO::modules()->getAllModules(); foreach ($commonLangFolderContentArr as $commonLangFolder) { if (get_class($commonLangFolder) == 'GO\\Base\\Fs\\Folder') { $commonLangFileArr = $commonLangFolder->ls(); foreach ($commonLangFileArr as $commonLangFile) { if (get_class($commonLangFile) == 'GO\\Base\\Fs\\File' && $commonLangFile->name() == $langCode . '.php') { $fileNames[] = str_replace(\GO::config()->root_path, '', $commonLangFile->path()); } } } } } foreach ($moduleModelArr as $moduleModel) { $modLangFolder = new \GO\Base\Fs\Folder($moduleModel->path . 'language/'); if ($modLangFolder->exists()) { $modLangFiles = $modLangFolder->ls(); foreach ($modLangFiles as $modLangFile) { if ($modLangFile->name() == $langCode . '.php') { $fileNames[] = str_replace(\GO::config()->root_path, '', $modLangFile->path()); } } } } $tmpFile = \GO\Base\Fs\File::tempFile($langCode . '-' . str_replace('.', '-', \GO::config()->version), 'zip'); //exec zip $cmdString = \GO::config()->cmd_zip . ' ' . $tmpFile->path() . ' ' . implode(" ", $fileNames); exec($cmdString, $outputArr, $retVal); if ($retVal > 0) { trigger_error("Creating ZIP file failed! " . implode("<br />", $outputArr), E_USER_ERROR); } \GO\Base\Util\Http::outputDownloadHeaders($tmpFile); $tmpFile->output(); $tmpFile->delete(); }
private function _duplicateFileColumns(ActiveRecord $duplicate) { foreach ($this->columns as $column => $attr) { if ($attr['gotype'] == 'file') { if (!empty($this->_attributes[$column])) { $file = new \GO\Base\Fs\File(GO::config()->file_storage_path . $this->_attributes[$column]); $tmpFile = \GO\Base\Fs\File::tempFile('', $file->extension()); $file->copy($tmpFile->parent(), $tmpFile->name()); $duplicate->{$column} = $tmpFile; } } } }
/** * Sends a meeting request to all participants. If the participant is not a Group-Office user * or the organizer has no permissions to schedule an event it will include an * icalendar attachment so the calendar software can schedule it. * * @return boolean * @throws Exception */ public function sendMeetingRequest($newParticipantsOnly = false, $update = false) { if (!$this->is_organizer) { throw new \Exception("Meeting request can only be send from the organizer's event"); } $stmt = $this->participants; //handle missing user if (!$this->user) { $this->user_id = 1; $this->save(true); } while ($participant = $stmt->fetch()) { if (!$newParticipantsOnly || isset(\GO::session()->values['new_participant_ids']) && in_array($participant->user_id, \GO::session()->values['new_participant_ids'])) { //don't invite organizer if ($participant->is_organizer) { continue; } // Set the language of the email to the language of the participant. $language = false; if (!empty($participant->user_id)) { $user = \GO\Base\Model\User::model()->findByPk($participant->user_id); if ($user) { \GO::language()->setLanguage($user->language); } } //if participant status is pending then send a new inviation subject. Otherwise send it as update if (!$update) { $subject = \GO::t('invitation', 'calendar') . ': ' . $this->name; $bodyLine = \GO::t('invited', 'calendar'); } else { $subject = \GO::t('invitation_update', 'calendar') . ': ' . $this->name; $bodyLine = \GO::t('eventUpdated', 'calendar'); } //create e-mail message $message = \GO\Base\Mail\Message::newInstance($subject)->setFrom($this->user->email, $this->user->name)->addTo($participant->email, $participant->name); //check if we have a Group-Office event. If so, we can handle accepting //and declining in Group-Office. Otherwise we'll use ICS calendar objects by mail $participantEvent = $participant->getParticipantEvent(); $body = '<p>' . $bodyLine . ': </p>' . $this->toHtml(); // if(!$participantEvent){ //build message for external program $acceptUrl = \GO::url("calendar/event/invitation", array("id" => $this->id, 'accept' => 1, 'email' => $participant->email, 'participantToken' => $participant->getSecurityToken()), false); $declineUrl = \GO::url("calendar/event/invitation", array("id" => $this->id, 'accept' => 0, 'email' => $participant->email, 'participantToken' => $participant->getSecurityToken()), false); // if($participantEvent){ //hide confusing buttons if user has a GO event. $body .= '<div class="go-hidden">'; // } $body .= '<p><br /><b>' . \GO::t('linkIfCalendarNotSupported', 'calendar') . '</b></p>' . '<p>' . \GO::t('acccept_question', 'calendar') . '</p>' . '<a href="' . $acceptUrl . '">' . \GO::t('accept', 'calendar') . '</a>' . ' | ' . '<a href="' . $declineUrl . '">' . \GO::t('decline', 'calendar') . '</a>'; // if($participantEvent){ $body .= '</div>'; // } $ics = $this->toICS("REQUEST"); $a = \Swift_Attachment::newInstance($ics, \GO\Base\Fs\File::stripInvalidChars($this->name) . '.ics', 'text/calendar; METHOD="REQUEST"'); $a->setEncoder(new Swift_Mime_ContentEncoder_PlainContentEncoder("8bit")); $a->setDisposition("inline"); $message->attach($a); //for outlook 2003 compatibility $a2 = \Swift_Attachment::newInstance($ics, 'invite.ics', 'application/ics'); $a2->setEncoder(new Swift_Mime_ContentEncoder_PlainContentEncoder("8bit")); $message->attach($a2); if ($participantEvent) { $url = \GO::createExternalUrl('calendar', 'openCalendar', array('unixtime' => $this->start_time)); $body .= '<br /><a href="' . $url . '">' . \GO::t('openCalendar', 'calendar') . '</a>'; } $message->setHtmlAlternateBody($body); // Set back the original language if ($language !== false) { \GO::language()->setLanguage($language); } \GO\Base\Mail\Mailer::newGoInstance()->send($message); } } unset(\GO::session()->values['new_participant_ids']); return true; }
/** * handleEmailFormInput * * This method can be used in Models and Controllers. It puts the email body * and inline (image) attachments from the client in the message, which can * then be used for storage in the database or sending emails. * * @param Array $params Must contain elements: body (string) and * * inlineAttachments (string). */ public function handleEmailFormInput($params) { if (!empty($params['subject'])) { $this->setSubject($params['subject']); } if (!empty($params['to'])) { $to = new EmailRecipients($params['to']); foreach ($to->getAddresses() as $email => $personal) { $this->addTo($email, $personal); } } if (!empty($params['cc'])) { $cc = new EmailRecipients($params['cc']); foreach ($cc->getAddresses() as $email => $personal) { $this->addCc($email, $personal); } } if (!empty($params['bcc'])) { $bcc = new EmailRecipients($params['bcc']); foreach ($bcc->getAddresses() as $email => $personal) { $this->addBcc($email, $personal); } } if (isset($params['alias_id'])) { $alias = \GO\Email\Model\Alias::model()->findByPk($params['alias_id']); $this->setFrom($alias->email, $alias->name); if (!empty($params['notification'])) { $this->setReadReceiptTo(array($alias->email => $alias->name)); } } if (isset($params['priority'])) { $this->setPriority($params['priority']); } if (isset($params['in_reply_to'])) { $headers = $this->getHeaders(); $headers->addTextHeader('In-Reply-To', $params['in_reply_to']); $headers->addTextHeader('References', $params['in_reply_to']); } if ($params['content_type'] == 'html') { $params['htmlbody'] = $this->_embedPastedImages($params['htmlbody']); //inlineAttachments is an array(array('url'=>'',tmp_file=>'relative/path/'); if (!empty($params['inlineAttachments'])) { $inlineAttachments = json_decode($params['inlineAttachments']); /* inline attachments must of course exist as a file, and also be used in * the message body */ if (count($inlineAttachments)) { foreach ($inlineAttachments as $ia) { //$tmpFile = new \GO\Base\Fs\File(\GO::config()->tmpdir.$ia['tmp_file']); if (empty($ia->tmp_file)) { continue; // Continue to the next inline attachment for processing. //throw new Exception("No temp file for inline attachment ".$ia->name); } $path = empty($ia->from_file_storage) ? \GO::config()->tmpdir . $ia->tmp_file : \GO::config()->file_storage_path . $ia->tmp_file; $tmpFile = new \GO\Base\Fs\File($path); if ($tmpFile->exists()) { //Different browsers reformat URL's to absolute or relative. So a pattern match on the filename. //$filename = rawurlencode($tmpFile->name()); $result = preg_match('/="([^"]*' . preg_quote($ia->token) . '[^"]*)"/', $params['htmlbody'], $matches); if ($result) { $img = \Swift_EmbeddedFile::fromPath($tmpFile->path()); $img->setContentType($tmpFile->mimeType()); $contentId = $this->embed($img); //$tmpFile->delete(); $params['htmlbody'] = \GO\Base\Util\String::replaceOnce($matches[1], $contentId, $params['htmlbody']); } else { //this may happen when an inline image was attached but deleted in the editor afterwards. // //throw new \Exception("Error: inline attachment could not be found in text: ".$ia->token); } } else { throw new \Exception("Error: inline attachment missing on server: " . $tmpFile->stripTempPath() . ".<br /><br />The temporary files folder is cleared on each login. Did you relogin?"); } } } } $params['htmlbody'] = $this->_fixRelativeUrls($params['htmlbody']); $htmlTop = '<html> <head> <style type="text/css"> body,p,td,div,span{ ' . \GO::config()->html_editor_font . ' }; body p{ margin:0px; } </style> </head> <body>'; $htmlBottom = '</body></html>'; $this->setHtmlAlternateBody($htmlTop . $params['htmlbody'] . $htmlBottom); } else { $this->setBody($params['plainbody'], 'text/plain'); } if (!empty($params['attachments'])) { $attachments = json_decode($params['attachments']); foreach ($attachments as $att) { $path = empty($att->from_file_storage) ? \GO::config()->tmpdir . $att->tmp_file : \GO::config()->file_storage_path . $att->tmp_file; $tmpFile = new \GO\Base\Fs\File($path); if ($tmpFile->exists()) { $file = \Swift_Attachment::fromPath($tmpFile->path()); $file->setContentType($tmpFile->mimeType()); $file->setFilename($att->fileName); $this->attach($file); //$tmpFile->delete(); } else { throw new \Exception("Error: attachment missing on server: " . $tmpFile->stripTempPath() . ".<br /><br />The temporary files folder is cleared on each login. Did you relogin?"); } } } }
/** * Movesthe node * * @param string $name The new name * @return void */ public function move($newPath) { $this->checkWritePermission(); \GO::debug('DAVFile::move(' . $this->path . ' -> ' . $newPath . ')'); $destFsFolder = new \GO\Base\Fs\Folder(dirname($newPath)); $destFolder = \GO\Files\Model\Folder::model()->findByPath($destFsFolder->stripFileStoragePath()); $file = \GO\Files\Model\File::model()->findByPath($this->relpath); $file->folder_id = $destFolder->id; $file->name = \GO\Base\Fs\File::utf8Basename($newPath); $file->save(); $this->relpath = $file->path; $this->path = \GO::config()->file_storage_path . $this->relpath; }
public function install() { // Install the notification cron for income contracts \GO\Projects2\Projects2Module::createDefaultIncomeContractNotificationCron(); // if(!GO::modules()->isInstalled('projects')){ GO::getDbConnection()->query("SET sql_mode=''"); if (!Utils::tableExists("pm_projects")) { parent::install(); $defaultType = new Type(); $defaultType->name = GO::t('default'); $defaultType->save(); $defaultStatus = new Status(); $defaultStatus->name = GO::t('ongoing', 'projects2'); $defaultStatus->show_in_tree = true; $defaultStatus->save(); $noneStatus = new Status(); $noneStatus->name = GO::t('none', 'projects2'); $noneStatus->show_in_tree = true; $noneStatus->filterable = true; $noneStatus->save(); $status = new Status(); $status->name = GO::t('complete', 'projects2'); $status->complete = true; $status->show_in_tree = false; $status->save(); $folder = new \GO\Base\Fs\Folder(GO::config()->file_storage_path . 'projects2/template-icons'); $folder->create(); if (!$folder->child('folder.png')) { $file = new \GO\Base\Fs\File(GO::modules()->projects2->path . 'install/images/folder.png'); $file->copy($folder); } if (!$folder->child('project.png')) { $file = new \GO\Base\Fs\File(GO::modules()->projects2->path . 'install/images/project.png'); $file->copy($folder); } $template = new Template(); $template->name = GO::t('projectsFolder', 'projects2'); $template->default_status_id = $noneStatus->id; $template->default_type_id = $defaultType->id; $template->icon = $folder->stripFileStoragePath() . '/folder.png'; $template->project_type = Template::PROJECT_TYPE_CONTAINER; $template->save(); $template->acl->addGroup(GO::config()->group_everyone); $template = new Template(); $template->name = GO::t('standardProject', 'projects2'); $template->default_status_id = $defaultStatus->id; $template->default_type_id = $defaultType->id; $template->project_type = Template::PROJECT_TYPE_PROJECT; $template->fields = 'responsible_user_id,status_date,customer,budget_fees,contact,expenses'; $template->icon = $folder->stripFileStoragePath() . '/project.png'; $template->save(); $template->acl->addGroup(GO::config()->group_everyone); } else { GO::setMaxExecutionTime(0); $oldModelTypeId = \GO\Base\Model\ModelType::model()->findByModelName("GO\\Projects\\Model\\Project"); $modelTypeId = \GO\Base\Model\ModelType::model()->findByModelName("GO\\Projects2\\Model\\Project"); //copy old projects module tables $stmt = GO::getDbConnection()->query('SHOW TABLES'); while ($r = $stmt->fetch()) { $tableName = $r[0]; if (substr($tableName, 0, 9) == 'go_links_' && !is_numeric(substr($tableName, 9, 1))) { try { $sql = "ALTER TABLE `{$tableName}` ADD `ctime` INT NOT NULL DEFAULT '0';"; GO::getDbConnection()->query($sql); } catch (Exception $e) { } $sql = "DELETE FROM `{$tableName}` WHERE model_type_id=" . intval($modelTypeId); GO::debug($sql); GO::getDbConnection()->query($sql); $sql = "INSERT IGNORE INTO `{$tableName}` SELECT id,folder_id, model_id,'{$modelTypeId}', description, ctime FROM `{$tableName}` WHERE model_type_id={$oldModelTypeId}"; GO::debug($sql); GO::getDbConnection()->query($sql); } if (strpos($tableName, 'pm_') !== false) { //some GLOBAL2000 tables we do not want to copy if (!in_array($tableName, array('pm_employees', 'pm_resources', 'pm_employment_agreements'))) { $newTable = str_replace('pm_', "pr2_", $tableName); $sql = "DROP TABLE IF EXISTS `{$newTable}`"; GO::getDbConnection()->query($sql); $sql = "CREATE TABLE `{$newTable}` LIKE `{$tableName}`"; GO::getDbConnection()->query($sql); $sql = "INSERT INTO `{$newTable}` SELECT * FROM `{$tableName}`"; GO::getDbConnection()->query($sql); } } } $sql = "update pr2_projects set name = replace(name, '/','-')"; GO::getDbConnection()->query($sql); // $sql = "update pr2_projects set files_folder_id=0"; // GO::getDbConnection()->query($sql); $sql = "select version from go_modules where id='projects'"; $stmt = GO::getDbConnection()->query($sql); $record = $stmt->fetch(PDO::FETCH_ASSOC); GO::modules()->projects2->version = $record['version']; GO::modules()->projects2->save(); // GO::modules()->projects->acl->copyPermissions(GO::modules()->projects2->acl); //start files // $sql = "UPDATE pr2_projects SET files_folder_id=(SELECT files_folder_id FROM pm_projects WHERE pm_projects.id=pr2_projects.id);"; // GO::getDbConnection()->query($sql); $fsFolder = new GO\Base\Fs\Folder(GO::config()->file_storage_path . 'projects2'); if ($fsFolder->exists()) { $fsFolder->rename('projects2-' . date('c')); } $folder = \GO\Files\Model\Folder::model()->findByPath('projects'); $folder->name = 'projects2'; $folder->acl_id = GO::modules()->projects2->acl_id; $folder->save(); // $sql = "UPDATE pm_projects SET files_folder_id=0;"; // GO::getDbConnection()->query($sql); $sql = "update `pr2_templates` set icon = replace(icon, 'projects/', 'projects2/');"; GO::getDbConnection()->query($sql); //end files //upgrade database ob_start(); $mc = new \GO\Core\Controller\MaintenanceController(); $mc->run("upgrade", array(), false); ob_end_clean(); //create new acl's // $types = \GO\Projects\Model\Type::model()->find(); // foreach($types as $type){ // $type2 = Model\Type::model()->findByPk($type->id); // $type2->setNewAcl($type->user_id); // $type->acl->copyPermissions($type2->acl); // $type2->save(); // } $sql = "ALTER TABLE `pr2_hours` CHANGE `income_id` `old_income_id` INT( 11 ) NULL DEFAULT NULL ;"; GO::getDbConnection()->query($sql); $sql = "ALTER TABLE `pr2_hours` ADD `income_id` INT( 11 ) NULL AFTER `old_income_id` ;"; GO::getDbConnection()->query($sql); $sql = "UPDATE `pr2_hours` SET old_income_id=-1*old_income_id;"; GO::getDbConnection()->query($sql); if (\GO\Base\Db\Utils::tableExists("pm_employment_agreements")) { //GLOBAL 2000 version $sql = "replace into pr2_employees (user_id, external_fee, internal_fee) select employee_id, max(external_fee),max(internal_fee) from pm_employment_agreements group by employee_id"; GO::getDbConnection()->query($sql); $sql = "replace into pr2_resources (user_id,project_id, external_fee, internal_fee) select user_id,project_id, external_fee, internal_fee from pm_resources"; GO::getDbConnection()->query($sql); // No longer necessary because of $updates['201310041023'] in updates.inc.php : // //untested // $sql = "ALTER TABLE `pr2_hours` CHANGE `external_value` `external_fee` DOUBLE NOT NULL DEFAULT '0'"; // GO::getDbConnection()->query($sql); } else { $sql = "insert ignore into pr2_employees (user_id, external_fee, internal_fee) select user_id, max(ext_fee_value), max(int_fee_value) from pm_hours group by user_id"; GO::getDbConnection()->query($sql); $sql = "insert ignore into pr2_resources (user_id,project_id, external_fee, internal_fee) select user_id,project_id, max(ext_fee_value), max(int_fee_value) from pm_hours group by user_id, project_id"; GO::getDbConnection()->query($sql); } $sql = "update pr2_templates set project_type=1"; GO::getDbConnection()->query($sql); if (GO::modules()->customfields) { // require(dirname(__FILE__).'/install/migrate/models.php'); // \GO\Customfields\CustomfieldsModule::replaceRecords("GO\Projects\Model\Project", "GO\Projects2\Model\Project"); // \GO\Customfields\CustomfieldsModule::replaceRecords("GO\Projects\Model\Hour", "GO\Projects2\Model\TimeEntry"); //$sql = "RENAME TABLE `cf_pm_projects` TO `cf_pr2_projects` "; //GO::getDbConnection()->query($sql); //$sql = "RENAME TABLE `cf_pm_hours` TO `cf_pr2_hours` "; //GO::getDbConnection()->query($sql); $sql = "update `cf_categories` set extends_model = 'GO\\\\Projects2\\\\Model\\\\Project' where extends_model = 'GO\\\\Projects\\\\Model\\\\Project';"; GO::getDbConnection()->query($sql); $sql = "update `cf_categories` set extends_model = 'GO\\\\Projects2\\\\Model\\\\Hour' where extends_model = 'GO\\\\Projects\\\\Model\\\\Hour';"; GO::getDbConnection()->query($sql); } // Now, let's make sure that all the projects have a template. $folder = new Folder(GO::config()->file_storage_path . 'projects2/template-icons'); $folder->create(); if (!$folder->child('folder.png')) { $file = new File(GO::modules()->projects2->path . 'install/images/folder.png'); $file->copy($folder); } if (!$folder->child('project.png')) { $file = new File(GO::modules()->projects2->path . 'install/images/project.png'); $file->copy($folder); } if (\GO::modules()->files) { $fileFolder = \GO\Files\Model\Folder::model()->findByPath('projects2/template-icons', true); if (!$fileFolder->acl_id != \GO::modules()->projects2->acl_id) { $oldIgnore = \GO::$ignoreAclPermissions; \GO::$ignoreAclPermissions = true; $fileFolder->acl_id = \GO::modules()->projects2->acl_id; $fileFolder->save(); \GO::$ignoreAclPermissions = $oldIgnore; } //for icons added after install $fileFolder->syncFilesystem(); } $normalTemplate = new Template(); $normalTemplate->name = GO::t('normalProject', 'projects2'); $normalTemplate->project_type = Template::PROJECT_TYPE_PROJECT; $normalTemplate->fields = 'responsible_user_id,status_date,customer,budget_fees,contact,expenses'; $normalTemplate->icon = $folder->stripFileStoragePath() . '/project.png'; $normalTemplate->save(); GO\Base\Db\Columns::$forceLoad = true; $noTemplateProjectsStmt = Project::model()->find(FindParams::newInstance()->criteria(FindCriteria::newInstance()->addCondition('template_id', 0))); GO\Base\Db\Columns::$forceLoad = false; foreach ($noTemplateProjectsStmt as $noTemplateProjectModel) { $noTemplateProjectModel->template_id = $normalTemplate->id; $noTemplateProjectModel->save(); } // Upgrade closed weeks ob_start(); $pc = new \GO\Projects2\Controller\ProjectController(); $pc->run("v1toV2Upgrade", array(), false); ob_end_clean(); } }
protected function actionSource($params) { $account = Account::model()->findByPk($params['account_id']); $imap = $account->openImapConnection($params['mailbox']); //$filename = empty($params['download']) ? "message.txt" :"message.eml"; $message = \GO\Email\Model\ImapMessage::model()->findByUid($account, $params['mailbox'], $params['uid']); $filename = GO\Base\Fs\File::stripInvalidChars($message->subject . ' - ' . \GO\Base\Util\Date::get_timestamp($message->udate)); $filename .= empty($params['download']) ? ".txt" : ".eml"; \GO\Base\Util\Http::outputDownloadHeaders(new \GO\Base\Fs\File($filename), empty($params['download'])); /* * Somehow fetching a message with an empty message part which should fetch it * all doesn't work. (http://tools.ietf.org/html/rfc3501#section-6.4.5) * * That's why I first fetch the header and then the text. */ $header = $imap->get_message_part($params['uid'], 'HEADER', true) . "\r\n\r\n"; $size = $imap->get_message_part_start($params['uid'], 'TEXT', true); header('Content-Length: ' . (strlen($header) + $size)); echo $header; while ($line = $imap->get_message_part_line()) { echo $line; } }
/** * * @return ImapMessageAttachment [] */ public function &getAttachments() { if (!$this->_imapAttachmentsLoaded) { $this->_imapAttachmentsLoaded = true; $imap = $this->getImapConnection(); $this->_loadBodyParts(); $parts = $imap->find_message_attachments($this->_getStruct(), $this->_bodyPartNumbers); $uniqueNames = array(); foreach ($parts as $part) { //ignore applefile's // Don't ignore it as it seems to be a valid attachment in some mails. // if($part['subtype']=='applefile') // continue; $a = new ImapMessageAttachment(); $a->setImapParams($this->account, $this->mailbox, $this->uid); if (empty($part['name']) || $part['name'] == 'false') { if (!empty($part['subject'])) { $a->name = \GO\Base\Fs\File::stripInvalidChars(\GO\Base\Mail\Utils::mimeHeaderDecode($part['subject'])) . '.eml'; } elseif ($part['type'] == 'message') { $a->name = isset($part['description']) ? \GO\Base\Fs\File::stripInvalidChars($part['description']) . '.eml' : 'message.eml'; } elseif ($part['subtype'] == 'calendar') { $a->name = \GO::t('event', 'email') . '.ics'; } else { if ($part['type'] == 'text') { $a->name = $part['subtype'] . '.txt'; } else { $a->name = $part['type'] . '-' . $part['subtype']; } } } else { $a->name = \GO\Base\Mail\Utils::mimeHeaderDecode($part['name']); $extension = \GO\Base\Fs\File::getExtension($a->name); if (!empty($part['filename']) && empty($extension)) { $a->name = \GO\Base\Mail\Utils::mimeHeaderDecode($part['filename']); } } $i = 1; $a->name = !empty($a->name) ? $a->name : \GO::t('noname', 'email'); $file = new \GO\Base\Fs\File($a->name); while (in_array($a->name, $uniqueNames)) { $a->name = $file->nameWithoutExtension() . ' (' . $i . ').' . $file->extension(); $i++; } $uniqueNames[] = $a->name; $a->disposition = isset($part['disposition']) ? strtolower($part['disposition']) : ''; $a->number = $part['number']; $a->content_id = ''; if (!empty($part["id"])) { //when an image has an id it belongs somewhere in the text we gathered above so replace the //source id with the correct link to display the image. $tmp_id = $part["id"]; if (strpos($tmp_id, '>')) { $tmp_id = substr($part["id"], 1, -1); } $id = $tmp_id; $a->content_id = $id; } $a->mime = $part['type'] . '/' . $part['subtype']; $a->index = count($this->attachments); $a->size = intval($part['size']); $a->encoding = $part['encoding']; $a->charset = !empty($part['charset']) ? $part['charset'] : $this->charset; $this->addAttachment($a); } } return $this->attachments; }
protected function actionDownload($params) { \GO::session()->closeWriting(); \GO::setMaxExecutionTime(0); if (isset($params['path'])) { $folder = \GO\Files\Model\Folder::model()->findByPath(dirname($params['path'])); $file = $folder->hasFile(\GO\Base\Fs\File::utf8Basename($params['path'])); } else { $file = \GO\Files\Model\File::model()->findByPk($params['id'], false, true); } if (!$file) { throw new \GO\Base\Exception\NotFound(); } if (!empty($params['random_code'])) { if ($file->random_code != $params['random_code']) { throw new \GO\Base\Exception\NotFound(); } if (time() > $file->expire_time) { throw new \Exception(\GO::t('downloadLinkExpired', 'files')); } } else { $public = substr($file->path, 0, 6) == 'public'; if (!$public) { if (!\GO::user()) { \GO\Base\Util\Http::basicAuth(); } if (!$file->checkPermissionLevel(\GO\Base\Model\Acl::READ_PERMISSION)) { throw new \GO\Base\Exception\AccessDenied(); } } } // Show the file inside the browser or give it as a download $inline = true; // Defaults to show inside the browser if (isset($params['inline']) && $params['inline'] == "false") { $inline = false; } \GO\Base\Util\Http::outputDownloadHeaders($file->fsFile, $inline, !empty($params['cache'])); $file->open(); $this->fireEvent('beforedownload', array(&$this, &$params, &$file)); $file->fsFile->output(); }
protected function afterSubmit(&$response, &$model, &$params, $modifiedAttributes) { $stmt = \GO\Addressbook\Model\Addresslist::model()->find(); while ($addresslist = $stmt->fetch()) { $linkModel = $addresslist->hasManyMany('companies', $model->id); $mustHaveLinkModel = isset($params['addresslist_' . $addresslist->id]); if ($linkModel && !$mustHaveLinkModel) { $linkModel->delete(); } if (!$linkModel && $mustHaveLinkModel) { $addresslist->addManyMany('companies', $model->id); } } if (!empty($params['delete_photo'])) { $model->removePhoto(); $model->save(); } if (isset($_FILES['image']['tmp_name'][0]) && is_uploaded_file($_FILES['image']['tmp_name'][0])) { $destinationFile = new \GO\Base\Fs\File(\GO::config()->getTempFolder()->path() . '/' . $_FILES['image']['name'][0]); move_uploaded_file($_FILES['image']['tmp_name'][0], $destinationFile->path()); $model->setPhoto($destinationFile); $model->save(); $response['photo_url'] = $model->photoThumbURL; $response['original_photo_url'] = $model->photoURL; } elseif (!empty($params['download_photo_url'])) { $file = \GO\Base\Fs\File::tempFile(); $c = new \GO\Base\Util\HttpClient(); if (!$c->downloadFile($params['download_photo_url'], $file)) { throw new \Exception("Could not download photo from: '" . $params['download_photo_url'] . "'"); } $model->setPhoto($file); $model->save(); $response['photo_url'] = $model->photoThumbURL; $response['original_photo_url'] = $model->photoURL; } return parent::afterSubmit($response, $model, $params, $modifiedAttributes); }
public function actionPasteUploadTemporary($filename, $filetype) { $type = explode('/', $filetype); $extension = $type[1]; $_FILES['pastedFile']['name'] = $filename . '.' . $extension; $file = new GO\Base\Fs\File($_FILES['pastedFile']['tmp_name']); $file->move(GO::config()->getTempFolder(), $filename . '.' . $extension, true); $response = new \GO\Base\Data\JsonResponse(array('success' => true, 'data' => array('tmp_file' => $file->stripTempPath(), 'name' => $file->name(), 'size' => $file->size(), 'type' => $file->mimeType(), 'extension' => $file->extension(), 'human_size' => $file->humanSize(), 'from_file_storage' => false))); echo $response; }
public static function toOutputArray(array &$response, \GO\Email\Model\ImapMessage $imapMessage) { if ($imapMessage->content_type == 'application/x-pkcs7-mime') { $imapMessage->content_type = 'application/pkcs7-mime'; } if ($imapMessage->content_type == 'application/pkcs7-mime' && isset($imapMessage->content_type_attributes['smime-type']) && $imapMessage->content_type_attributes['smime-type'] == 'signed-data') { //signed data but not in clear text. Outlook has this option. $outfile = \GO\Base\Fs\File::tempFile(); $imapMessage->getImapConnection()->save_to_file($imapMessage->uid, $outfile->path()); $verifyOutfile = \GO\Base\Fs\File::tempFile(); // $cmd = '/usr/bin/openssl smime -verify -in ' . $outfile->path() . ' -out ' . $verifyOutfile->path(); // exec($cmd); // //PHP can't output the verified data without the signature without //suppling the extracerts option. We generated a dummy certificate for //this. openssl_pkcs7_verify($outfile->path(), null, "/dev/null", array(), GO::config()->root_path . "modules/smime/dummycert.pem", $verifyOutfile->path()); $message = \GO\Email\Model\SavedMessage::model()->createFromMimeData($verifyOutfile->getContents()); //remove temp files $outfile->delete(); $verifyOutfile->delete(); $newResponse = $message->toOutputArray(true); unset($newResponse['to']); unset($newResponse['cc']); foreach ($newResponse as $key => $value) { if (!empty($value) || $key == 'attachments') { $response[$key] = $value; } } // $response['path'] = $outfile->stripTempPath(); return; } if ($imapMessage->content_type == 'application/pkcs7-mime') { $encrypted = !isset($imapMessage->content_type_attributes['smime-type']) || $imapMessage->content_type_attributes['smime-type'] != 'signed-data'; if ($encrypted) { GO::debug("Message is encrypted"); $cert = Model\Certificate::model()->findByPk($imapMessage->account->id); if (!$cert || empty($cert->cert)) { GO::debug('SMIME: No private key at all found for this account'); $response['htmlbody'] = GO::t('noPrivateKeyForDecrypt', 'smime'); return false; } if (isset($_REQUEST['password'])) { GO::session()->values['smime']['passwords'][$imapMessage->account->id] = $_REQUEST['password']; } if (!isset(GO::session()->values['smime']['passwords'][$imapMessage->account->id])) { $response['askPassword'] = true; GO::debug("Need to ask for password"); return false; } } $attachments = $imapMessage->getAttachments(); $att = array_shift($attachments); // array ( // 'type' => 'application', // 'subtype' => 'pkcs7-mime', // 'smime-type' => 'enveloped-data', // 'name' => 'smime.p7m', // 'id' => false, // 'encoding' => 'base64', // 'size' => '2302', // 'md5' => false, // 'disposition' => false, // 'language' => false, // 'location' => false, // 'charset' => false, // 'lines' => false, // 'number' => 1, // 'extension' => 'p7m', // 'human_size' => '2,2 KB', // 'tmp_file' => false, // ) $infile = \GO\Base\Fs\File::tempFile(); $outfile = \GO\Base\Fs\File::tempFile(); //$outfilerel = $reldir . 'unencrypted.txt'; if ($encrypted) { GO::debug('Message is encrypted'); // $imapMessage->getImapConnection()->save_to_file($imapMessage->uid, $infile->path(), 'TEXT', 'base64'); // throw new \Exception($infile->path()); if (!$imapMessage->saveToFile($infile->path())) { throw new \Exception("Could not save IMAP message to file for decryption"); } $password = GO::session()->values['smime']['passwords'][$imapMessage->account->id]; openssl_pkcs12_read($cert->cert, $certs, $password); if (empty($certs)) { //password invalid $response['askPassword'] = true; GO::debug("Invalid password"); return false; } $return = openssl_pkcs7_decrypt($infile->path(), $outfile->path(), $certs['cert'], array($certs['pkey'], $password)); $infile->delete(); if (!$return || !$outfile->exists() || !$outfile->size()) { $response['htmlbody'] = GO::t('decryptionFailed', 'smime') . '<br />'; while ($str = openssl_error_string()) { $response['htmlbody'] .= '<br />' . $str; } GO::debug("Decryption failed"); return false; } else { //check if also signed $data = $outfile->getContents(); if (strpos($data, 'signed-data')) { $verifyOutfile = \GO\Base\Fs\File::tempFile(); openssl_pkcs7_verify($outfile->path(), null, "/dev/null", array(), GO::config()->root_path . "modules/smime/dummycert.pem", $verifyOutfile->path()); $outfile = $verifyOutfile; } $message = \GO\Email\Model\SavedMessage::model()->createFromMimeData($outfile->getContents()); $newResponse = $message->toOutputArray(true); unset($newResponse['to']); unset($newResponse['to_string']); unset($newResponse['cc']); foreach ($newResponse as $key => $value) { if (!empty($value) || $key == 'attachments') { $response[$key] = $value; } } $response['smime_encrypted'] = true; //$response['path']=$outfile->stripTempPath(); $outfile->delete(); } } else { GO::debug('Message is NOT encrypted'); } } }