Commit 2854d8cc authored by lphuberdeau's avatar lphuberdeau

[MOD] Refactoring the mail-in code

parent c160a41f
......@@ -3015,6 +3015,10 @@ lib/core/Tiki/MailIn/Action/ArticlePut.php -text
lib/core/Tiki/MailIn/Action/DirectFactory.php -text
lib/core/Tiki/MailIn/Action/FactoryInterface.php -text
lib/core/Tiki/MailIn/Action/SubjectPrefixFactory.php -text
lib/core/Tiki/MailIn/Action/WikiAppend.php -text
lib/core/Tiki/MailIn/Action/WikiGet.php -text
lib/core/Tiki/MailIn/Action/WikiPrepend.php -text
lib/core/Tiki/MailIn/Action/WikiPut.php -text
lib/core/Tiki/MailIn/Exception/MailInException.php -text
lib/core/Tiki/MailIn/Exception/TransportException.php -text
lib/core/Tiki/MailIn/Source/Message.php -text
......
......@@ -258,7 +258,7 @@ class ArtLib extends TikiLib
'linkto' => $linkto,
'image_caption' => $image_caption,
'lang' => $lang,
'ispublished' => $ispublished,
//'ispublished' => $ispublished, // Does not exist
);
$article_table = $this->table('tiki_submissions');
......
......@@ -6,6 +6,7 @@
// $Id$
namespace Tiki\MailIn;
use TikiLib, TikiMail;
class Account
{
......@@ -17,38 +18,46 @@ class Account
private $adminAllowed;
private $sendResponses;
private $discardAfter;
private $defaultCategory;
private $saveHtml;
private $auto_attachments;
public static function fromDb(array $acc)
{
$account = new self;
$account->source = new Source\Pop3($acc['pop'], $acc['port'], $acc['username'], $acc['pass']);
$wikiParams = [
'namespace' => $acc['namespace'],
'structure_routing' => $acc['routing'] == 'y',
];
switch ($acc['type']) {
case 'article-put':
$this->factory = new Action\DirectFactory('Tiki\MailIn\Action\ArticlePut', array(
$account->actionFactory = new Action\DirectFactory('Tiki\MailIn\Action\ArticlePut', array(
'topic' => $acc['article_topicId'],
'type' => $acc['article_type'],
));
break;
case 'wiki-put':
$this->factory = new Action\DirectFactory('Tiki\MailIn\Action\WikiPut');
$account->actionFactory = new Action\DirectFactory('Tiki\MailIn\Action\WikiPut', $wikiParams);
break;
case 'wiki-get':
$this->factory = new Action\DirectFactory('Tiki\MailIn\Action\WikiGet');
$account->actionFactory = new Action\DirectFactory('Tiki\MailIn\Action\WikiGet', $wikiParams);
break;
case 'wiki-append':
$this->factory = new Action\DirectFactory('Tiki\MailIn\Action\WikiAppend');
$account->actionFactory = new Action\DirectFactory('Tiki\MailIn\Action\WikiAppend', $wikiParams);
break;
case 'wiki-prepend':
$this->factory = new Action\DirectFactory('Tiki\MailIn\Action\WikiPrepend');
$account->actionFactory = new Action\DirectFactory('Tiki\MailIn\Action\WikiPrepend', $wikiParams);
break;
case 'wiki':
$this->factory = new Action\SubjectPrefixFactory(array(
'GET:' => new Action\DirectFactory('Tiki\MailIn\Action\WikiGet'),
'APPEND:' => new Action\DirectFactory('Tiki\MailIn\Action\WikiAppend'),
'PREPEND:' => new Action\DirectFactory('Tiki\MailIn\Action\WikiPrepend'),
'PUT:' => new Action\DirectFactory('Tiki\MailIn\Action\WikiPut'),
'' => new Action\DirectFactory('Tiki\MailIn\Action\WikiPut'),
$account->actionFactory = new Action\SubjectPrefixFactory(array(
'GET:' => new Action\DirectFactory('Tiki\MailIn\Action\WikiGet', $wikiParams),
'APPEND:' => new Action\DirectFactory('Tiki\MailIn\Action\WikiAppend', $wikiParams),
'PREPEND:' => new Action\DirectFactory('Tiki\MailIn\Action\WikiPrepend', $wikiParams),
'PUT:' => new Action\DirectFactory('Tiki\MailIn\Action\WikiPut', $wikiParams),
'' => new Action\DirectFactory('Tiki\MailIn\Action\WikiPut', $wikiParams),
));
break;
default:
......@@ -60,6 +69,11 @@ class Account
$account->adminAllowed = $acc['admin'] == 'y';
$account->sendResponses = $acc['respond_email'] == 'y';
$account->discardAfter = $acc['discard_after'];
$account->defaultCategory = $acc['categoryId'];
$account->saveHtml = $acc['save_html'] == 'y';
$account->deleteOnError = $acc['leave_email'] != 'y';
$account->auto_attachments = $acc['attachments'] == 'y';
$account->inline_attachments = $acc['show_inlineImages'] == 'y';
return $account;
}
......@@ -70,7 +84,19 @@ class Account
function getMessages()
{
return $this->source->getMessage();
return $this->source->getMessages();
}
function completeSuccess($message)
{
$message->delete();
}
function completeFailure($message)
{
if ($this->deleteOnError) {
$message->delete();
}
}
function isAnyoneAllowed()
......@@ -109,23 +135,103 @@ class Account
$body = substr($body, 0, $pos);
$message->setBody($body);
}
$body = $message->getHtmlBody(false);
$pos = strpos($body, $this->discardAfter);
if ($pos !== false) {
$body = substr($body, 0, $pos);
$message->setHtmlBody($body);
}
}
}
function sendFailureResponse(Source\Message $message)
{
if (! $this->sendResponses) {
return;
}
global $prefs;
$l = $prefs['language'];
$mail = new TikiMail();
$mail->setFrom($this->accountAddress);
$mail = $this->getReplyMail($message);
$mail->setSubject(tra('Tiki mail-in auto-reply', $l));
$mail->setText(tra("Sorry, you can't use this feature.", $l));
$this->sendFailureReply($message, $mail);
}
function getReplyMail(Source\Message $message)
{
$mail = new TikiMail();
$mail->setFrom($this->accountAddress);
return $mail;
}
function getAddress()
{
return $this->accountAddress;
}
function sendFailureReply(Source\Message $message, TikiMail $mail)
{
if ($this->sendResponses) {
$this->sendReply($message, $mail);
}
}
function sendReply(Source\Message $message, TikiMail $mail)
{
$mail->send(array($message->getFromAddress()), 'mail');
}
function getDefaultCategory()
{
return $this->defaultCategory;
}
function parseBody($body)
{
global $prefs;
$is_html = false;
$wysiwyg = NULL;
if ($this->containsStringHTML($body)) {
$is_html = true;
$wysiwyg = 'y';
}
if ($is_html && $this->saveHtml) {
// Keep HTML setting. Always save as HTML
} elseif ($prefs['feature_wysiwyg'] === 'y' && $prefs['wysiwyg_default'] === 'y' && $prefs['wysiwyg_htmltowiki'] !== 'y' ) {
// WYSIWYG HTML editor is active
$is_html = true;
$wysiwyg = 'y';
} elseif ($is_html) {
include_once "lib/wiki/editlib.php";
$editlib = new EditLib;
$body = $editlib->parseToWiki($body);
$is_html = false;
$wysiwyg = NULL;
}
return array(
'body' => $body,
'is_html' => $is_html,
'wysiwyg' => $wysiwyg,
);
}
private function containsStringHTML($str)
{
return preg_match('/<[^>]*>/', $str);
}
function hasAutoAttach()
{
return $this->auto_attachments;
}
function hasInlineAttach()
{
return $this->inline_attachments;
}
}
......@@ -8,8 +8,9 @@
namespace Tiki\MailIn\Action;
use Tiki\MailIn\Account;
use Tiki\MailIn\Source\Message;
use TikiLib;
class ArticlePut extends ActionInterface
class ArticlePut implements ActionInterface
{
private $topicId;
private $type;
......@@ -24,7 +25,7 @@ class ArticlePut extends ActionInterface
{
global $prefs;
return $prefs['feature_articles'] == 'y';
return $prefs['feature_submissions'] == 'y';
}
function isAllowed(Account $account, Message $message)
......
......@@ -24,7 +24,7 @@ class SubjectPrefixFactory implements FactoryInterface
$subject = $message->getSubject();
foreach ($this->config as $prefix => $factory) {
if (strpos($subject, $prefix) === 0) {
if (strpos($subject, $prefix) === 0 || empty($prefix)) {
$subject = trim(substr($subject, strlen($prefix)));
$message->setSubject($subject);
......
<?php
// (c) Copyright 2002-2013 by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
namespace Tiki\MailIn\Action;
use Tiki\MailIn\Account;
use Tiki\MailIn\Source\Message;
use TikiLib;
class WikiAppend extends WikiPut
{
protected function handleContent($data, $info)
{
if ($info) {
return $info['data'] . "\n" . $data['body'];
} else {
return $data['body'];
}
}
}
<?php
// (c) Copyright 2002-2013 by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
namespace Tiki\MailIn\Action;
use Tiki\MailIn\Account;
use Tiki\MailIn\Source\Message;
use TikiLib;
class WikiGet extends WikiPut
{
function isAllowed(Account $account, Message $message)
{
$user = $message->getAssociatedUser();
$page = $this->getPage($message);
$perms = TikiLib::lib('tiki')->get_user_permission_accessor($user, 'wiki page', $page);
return $perms->view;
}
function execute(Account $account, Message $message)
{
$tikilib = TikiLib::lib('tiki');
$page = $this->getPage($message);
$info = $tikilib->get_page_info($page);
if ($info) {
$data = $tikilib->parse_data($info["data"]);
$mail = $account->getReplyMail($message);
$mail->setSubject($page);
$mail->addAttachment($info['data'], 'source.txt', 'plain/txt');
$mail->setHTML($data, strip_tags($data));
$account->sendReply($message, $mail);
} else {
$l = $prefs['language'];
$mail_data = $smarty->fetchLang($l, "mail/mailin_reply_subject.tpl");
$mail = $account->getReplyMail($message);
$mail->setSubject($mail_data . $page);
$account->sendReply($message, $mail);
}
}
}
<?php
// (c) Copyright 2002-2013 by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
namespace Tiki\MailIn\Action;
use Tiki\MailIn\Account;
use Tiki\MailIn\Source\Message;
use TikiLib;
class WikiPrepend extends WikiPut
{
protected function handleContent($data, $info)
{
if ($info) {
return $data['body'] . "\n" . $info['data'];
} else {
return $data['body'];
}
}
}
<?php
// (c) Copyright 2002-2013 by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
namespace Tiki\MailIn\Action;
use Tiki\MailIn\Account;
use Tiki\MailIn\Source\Message;
use TikiLib;
class WikiPut implements ActionInterface
{
private $namespace;
private $routing;
function __construct(array $params)
{
$this->namespace = isset($params['namespace']) ? intval($params['namespace']) : null;
$this->routing = ! empty($params['structure_routing']);
}
function isEnabled()
{
global $prefs;
return $prefs['feature_wiki'] == 'y';
}
function isAllowed(Account $account, Message $message)
{
$tikilib = TikiLib::lib('tiki');
$user = $message->getAssociatedUser();
$page = $this->getPage($message, true);
$perms = $tikilib->get_user_permission_accessor($user, 'wiki page', $page);
$info = $tikilib->get_page_info($page);
if (! $info) {
if ($route = $this->getRoute($message)) {
$structName = $route['structName'];
$structperms = $tikilib->get_user_permission_accessor($user, 'wiki page', $structName);
if (! $structperms->edit_structures) {
return false;
}
}
$defaultCategory = $account->getDefaultCategory();
if ($defaultCategory) {
$categperms = $tikilib->get_user_permission_accessor($user, 'category', $defaultCategory);
return $categperms->edit;
}
}
return $perms->edit;
}
function canAttach(Account $account, Message $message)
{
global $prefs;
if ($prefs['feature_wiki_attachments'] != 'y') {
return false;
}
$tikilib = TikiLib::lib('tiki');
$user = $message->getAssociatedUser();
$page = $this->getPage($message, true);
$info = $tikilib->get_page_info($page);
if (! $info) {
$defaultCategory = $account->getDefaultCategory();
if ($defaultCategory) {
$categperms = $tikilib->get_user_permission_accessor($user, 'category', $defaultCategory);
return $categperms->wiki_attach_files;
}
}
$perms = $tikilib->get_user_permission_accessor($user, 'wiki page', $page);
return $perms->wiki_attach_files;
}
function execute(Account $account, Message $message)
{
$tikilib = TikiLib::lib('tiki');
$wikilib = TikiLib::lib('wiki');
$user = $message->getAssociatedUser();
$page = $this->getPage($message, true);
if ($this->canAttach($account, $message) && $account->hasAutoAttach()) {
foreach ($message->getAttachments() as $att) {
$link = $this->attachFile($page, $att, $user);
$message->setLink($att['contentId'], $link);
}
}
if ($this->canAttach($account, $message) && $account->hasInlineAttach() && $body = $message->getHtmlBody(false)) {
$body = $this->handleInlineImages($page, $body, $message);
} else {
$body = $message->getHtmlBody(false);
}
$data = $account->parseBody($body);
$info = $tikilib->get_page_info($page);
// Allow sub-classes to play with the data
$body = $this->handleContent($data, $info);
if (! $info) {
if ($route = $this->getRoute($message)) {
// Use the page structure node, if specified, otherwise link to the rrot of the structure
if ($route['page_id'] > 0) {
$parent_id = $route['page_struct_refid']; // page_ref_id
} else {
$parent_id = $route['page_ref_id'];
}
$structName = $route['structName'];
$structure_id = $route['structure_id'];
$begin = true;
$after_ref_id = null;
$alias='';
$options = array();
$options['hide_toc'] = 'y';
$options['creator'] = $user;
$options['creator_msg'] = tra('created from mail-in');
$options['ip_source'] = '0.0.0.0';
$structlib = TikiLib::lib('struct');
$structlib->s_create_page($parent_id, $after_ref_id, $page, $alias, $structure_id, $options);
$content.= "Page: $page has been added to structureId: ".$structure_id."<br />";
$tikilib->update_page(
$page,
$body,
"Updated from " . $account->getAddress(),
$user,
$options['ip_source'],
'', //desc
0, //edit_minor
'', //lang
$data['is_html'], //is_html
'', //hash
null, //saveLastModif
$data['wysiwyg'] //wysiwyg
);
// Categorize with structure categories
$categlib = TikiLib::lib('categ');
$categParent = $categlib->get_object_categories('wiki page', $structName, -1, false);
foreach ($categParent as $c) {
$categoryId = $c['categoryId'];
$this->categorize($page, $categoryId, $user);
}
} else {
// No routing
$tikilib->create_page(
$page,
0,
$body,
$tikilib->now,
"Created from " . $account->getAddress(),
$user,
'0.0.0.0',
'', //description
'', //lang
$data['is_html'], //is_html
'', //hash
$data['wysiwyg'] //wysiwyg
);
}
$default = $account->getDefaultCategory();
if ($default) {
$this->categorize($page, $default, $user);
}
} else {
// Page exists
$tikilib->update_page(
$page,
$body,
"Updated from " . $account->getAddress(),
$user,
'0.0.0.0',
'', //desc
0, //edit_minor
'', //lang
$data['is_html'], //is_html
'', //hash
null, //saveLastModif
$data['wysiwyg'] //wysiwyg
);
}
return true;
}
protected function handleContent($data, $info)
{
return $data['body'];
}
private function categorize($pageName, $category, $user)
{
$categlib = TikiLib::lib('categ');
if ($categlib->get_category($categoryId)) {
$categlib->categorizePage($pageName, $category, $user);
}
}
protected function getPage($message, $routing = false)
{
$page = $message->getSubject();
$wikilib = Tikilib::lib('wiki');
$page = $wikilib->remove_badchars($page);
if ($this->namespace) {
return $wikilib->include_namespace($page, $this->namespace);
} elseif ($routing) {
if ($route = $this->getRoute($message)) {
$nsName = $wikilib->get_namespace($route['structName']);
if (!empty($nsName)) {
return $wikilib->include_namespace($page, $nsName);
}
}
}
return $page;
}
private function getRoute($message)
{
if (! $this->routing) {
return null;
}
$usermailinlib = TikiLib::lib('usermailin');
$body = $message->getHtmlBody();
$routes = $usermailinlib->locate_struct($chkUser, $aux['Subject'], $body);
if (!empty($routes['data'])) {
return $routes['data'][0]; // Only use the first route
}
}
private function attachFile($page, $att, $user)
{
if (! $att['link']) {
$wikilib = TikiLib::lib('wiki');
$attId = $wikilib->wiki_attach_file($page, $att['name'], $att['type'], $att['size'], $att['data'], "attached by mail $user");
return 'tiki-download_wiki_attachment.php?attId='.$attId.'&page='.urlencode($page);
} else {
return $att['link'];
}
}
private function handleInlineImages($page, $body, $message)
{
$user = $message->getAssociatedUser();
foreach ($message->getAttachments() as $att) {
if (substr($att['type'], 0, 6) != 'image/') {
// Skip non-images
continue;
}
$string = "cid:{$att['contentId']}"; // This string may differ
if (strpos($body, $string) !== false) {
$link = $this->attachFile($page, $att, $user);
$message->setLink($att['contentId'], $link);
$body = str_replace($string, $link, $body);
}
}
return $body;
}
}
......@@ -16,6 +16,8 @@ class Message
private $from;
private $subject;
private $body;
private $htmlBody;
private $attachments = [];
private $associatedUser;
......@@ -35,8 +37,8 @@ class Message
$this->from = $from;
if ($email = $this->getFromAddress()) {
$userlib = TikiLib::lib('user');
$this->associatedUser = $userlib->get_user_by_email($email_from);
$userlib = \TikiLib::lib('user');
$this->associatedUser = $userlib->get_user_by_email($email);
}
}
......@@ -80,5 +82,50 @@ class Message
{
return $this->body;
}
function setHtmlBody($body)
{
$this->htmlBody = $body;
}
function getHtmlBody($fallback = true)
{
if ($fallback) {
return $this->htmlBody ?: $this->body;
} else {
return $this->htmlBody;
}
}
function addAttachment($contentId, $name, $type, $size, $data)
{
$this->attachments[$contentId] = [
'contentId' => $contentId,
'name' => $name,
'type' => $type,
'size' => $size,
'data' => $data,
'link' => null,
];
}
function setLink($contentId, $link)
{
if (isset($this->attachments[$contentId])) {
$this->attachments[$contentId]['link'] = $link;
}
}
function getAttachments()
{
return array_values($this->attachments);
}
function getAttachment($contentId)
{
if (isset($this->attachments[$contentId])) {
return $this->attachments[$contentId];
}
}
}