forked from extern/egroupware
first version of linked attachments
This commit is contained in:
parent
e8056c388b
commit
63a6ac9a6d
@ -40,6 +40,29 @@ class mail_compose
|
||||
"plain"=>"plain",
|
||||
"html"=>"html"
|
||||
);
|
||||
/**
|
||||
* Modes for sending files
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static $filemodes = array(
|
||||
'attach' => array(
|
||||
'label' => 'Attachment',
|
||||
'title' => 'Works reliable for total size up to 1-2 MB, might work for 5-10 MB, most likely to fail for >10MB',
|
||||
),
|
||||
'link' => array(
|
||||
'label' => 'Download link',
|
||||
'title' => 'Link is appended to mail allowing recipients to download currently attached version of files',
|
||||
),
|
||||
'share_ro' => array(
|
||||
'label' => 'Share readonly',
|
||||
'title' => 'Link is appended to mail allowing recipients to download up to date version of files',
|
||||
),
|
||||
'share_rw' => array(
|
||||
'label' => 'Share writable',
|
||||
'title' => 'Link is appended to mail allowing recipients to download or modify up to date version of files (EPL only)'
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Instance of mail_bo
|
||||
@ -103,18 +126,17 @@ class mail_compose
|
||||
}
|
||||
|
||||
/**
|
||||
* function compose
|
||||
* this function is used to fill the compose dialog with the content provided by $_content
|
||||
* Compose dialog
|
||||
*
|
||||
* @var _content array the etemplate content array
|
||||
* @var msg string a possible message to be passed and displayed to the userinterface
|
||||
* @var _focusElement varchar subject, to, body supported
|
||||
* @var suppressSigOnTop boolean
|
||||
* @var isReply boolean
|
||||
* @var arra $_content =null etemplate content array
|
||||
* @var string $msg =null a possible message to be passed and displayed to the userinterface
|
||||
* @var string $_focusElement ='to' subject, to, body supported
|
||||
* @var boolean $suppressSigOnTop =false
|
||||
* @var boolean $isReply =false
|
||||
*/
|
||||
function compose(array $_content=null,$msg=null, $_focusElement='to',$suppressSigOnTop=false, $isReply=false)
|
||||
{
|
||||
unset($msg); // not used
|
||||
if ($msg) egw_framework::message($msg);
|
||||
|
||||
if (!empty($GLOBALS['egw_info']['user']['preferences']['mail']['LastSignatureIDUsed']))
|
||||
{
|
||||
@ -1103,6 +1125,7 @@ class mail_compose
|
||||
if (isset($content['mimeType'])) $preserv['mimeType'] = $content['mimeType'];
|
||||
$sel_options['mimeType'] = self::$mimeTypes;
|
||||
$sel_options['priority'] = self::$priorities;
|
||||
$sel_options['filemode'] = self::$filemodes;
|
||||
if (!isset($content['priority']) || empty($content['priority'])) $content['priority']=3;
|
||||
//$GLOBALS['egw_info']['flags']['currentapp'] = 'mail';//should not be needed
|
||||
$etpl = new etemplate_new('mail.compose');
|
||||
@ -1994,9 +2017,9 @@ class mail_compose
|
||||
* @param egw_mailer $_mailObject
|
||||
* @param array $_formData
|
||||
* @param array $_identity
|
||||
* @param boolean $_convertLinks
|
||||
* @param boolean $_send =false true: create to send message: false: create to save as draft
|
||||
*/
|
||||
function createMessage(egw_mailer $_mailObject, array $_formData, array $_identity, $_convertLinks=false)
|
||||
function createMessage(egw_mailer $_mailObject, array $_formData, array $_identity, $_send=false)
|
||||
{
|
||||
$mail_bo = $this->mail_bo;
|
||||
$activeMailProfile = emailadmin_account::read($this->mail_bo->profileID);
|
||||
@ -2078,10 +2101,25 @@ class mail_compose
|
||||
{
|
||||
$signature = mail_bo::merge($signature,array($GLOBALS['egw']->accounts->id2name($GLOBALS['egw_info']['user']['account_id'],'person_id')));
|
||||
}
|
||||
|
||||
if ($_formData['attachments'] && $_formData['filemode'] != 'attach' && $_send)
|
||||
{
|
||||
$attachment_links = $this->getAttachmentLinks($_formData['attachments'], $_formData['filemode'],
|
||||
$_formData['mimeType'] == 'html', array_merge((array)$_formData['to'], (array)$_formData['cc'], (array)$_formData['bcc']));
|
||||
}
|
||||
if($_formData['mimeType'] == 'html')
|
||||
{
|
||||
$body = $_formData['body'];
|
||||
if ($attachment_links)
|
||||
{
|
||||
if (strpos($body, '<!-- HTMLSIGBEGIN -->') !== false)
|
||||
{
|
||||
$body = str_replace('<!-- HTMLSIGBEGIN -->', $attachment_links.'<!-- HTMLSIGBEGIN -->', $body);
|
||||
}
|
||||
else
|
||||
{
|
||||
$body .= $attachment_links;
|
||||
}
|
||||
}
|
||||
if(!empty($signature))
|
||||
{
|
||||
$body .= ($disableRuler ?'<br>':'<hr style="border:1px dotted silver; width:90%;">').$signature;
|
||||
@ -2095,14 +2133,19 @@ class mail_compose
|
||||
$_mailObject->setBody($this->convertHTMLToText($_formData['body'],true,true));
|
||||
}
|
||||
// convert URL Images to inline images - if possible
|
||||
if ($_convertLinks) mail_bo::processURL2InlineImages($_mailObject, $body);
|
||||
if ($_send) mail_bo::processURL2InlineImages($_mailObject, $body);
|
||||
if (strpos($body,"<!-- HTMLSIGBEGIN -->")!==false)
|
||||
{
|
||||
$body = str_replace(array('<!-- HTMLSIGBEGIN -->','<!-- HTMLSIGEND -->'),'',$body);
|
||||
}
|
||||
$_mailObject->setHtmlBody($body, null, false); // false = no automatic alternative, we called setBody()
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$body = $this->convertHTMLToText($_formData['body'],false);
|
||||
|
||||
if ($attachment_links) $body .= $attachment_links;
|
||||
|
||||
#$_mailObject->Body = $_formData['body'];
|
||||
if(!empty($signature)) {
|
||||
$body .= ($disableRuler ?"\r\n":"\r\n-- \r\n").
|
||||
@ -2165,7 +2208,7 @@ class mail_compose
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
elseif ($_formData['filemode'] == 'attach')
|
||||
{
|
||||
if (isset($attachment['file']) && parse_url($attachment['file'],PHP_URL_SCHEME) == 'vfs')
|
||||
{
|
||||
@ -2189,6 +2232,66 @@ class mail_compose
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get html or text containing links to attachments
|
||||
*
|
||||
* We only care about file attachments, not forwarded messages or parts
|
||||
*
|
||||
* @param array $attachments
|
||||
* @param string $filemode 'attach', 'link', 'share_ro', 'share_rw'
|
||||
* @param boolean $html
|
||||
* @return string might be empty if no file attachments found
|
||||
*/
|
||||
protected function getAttachmentLinks(array $attachments, $filemode, $html, $recipients=array())
|
||||
{
|
||||
switch ($filemode)
|
||||
{
|
||||
case 'attach':
|
||||
return '';
|
||||
|
||||
case 'links':
|
||||
case 'share_ro':
|
||||
$func = 'egw_sharing::create';
|
||||
break;
|
||||
|
||||
case 'share_rw':
|
||||
$func = 'stylite_sharing::create';
|
||||
break;
|
||||
}
|
||||
$links = array();
|
||||
foreach($attachments as $attachment)
|
||||
{
|
||||
$path = $attachment['file'];
|
||||
if (empty($path)) continue; // we only care about file attachments, not forwarded messages or parts
|
||||
if (parse_url($attachment['file'],PHP_URL_SCHEME) != 'vfs')
|
||||
{
|
||||
$path = $GLOBALS['egw_info']['server']['temp_dir'].SEP.basename($path);
|
||||
}
|
||||
$share = call_user_func($func, $path, $attachment['name'], $filemode, $recipients);
|
||||
$link = egw_sharing::share2link($share);
|
||||
|
||||
$name = egw_vfs::basename($attachment['name'] ? $attachment['name'] : $attachment['file']);
|
||||
|
||||
if ($html)
|
||||
{
|
||||
$links[] = html::a_href($name, $link).' '.egw_vfs::hsize($attachment['size']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$links[] = $name.' '.egw_vfs::hsize($attachment['size']).': '.$link;
|
||||
}
|
||||
}
|
||||
if (!$links)
|
||||
{
|
||||
return null; // no file attachments found
|
||||
}
|
||||
elseif ($html)
|
||||
{
|
||||
return '<p>'.lang('Download attachments').":</p>\n<ul><li>".implode("</li>\n<li>", $links)."</li></ul>\n";
|
||||
}
|
||||
return lang('Download attachments').":\n- ".implode("\n- ", $links)."\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Save compose mail as draft
|
||||
*
|
||||
|
@ -315,12 +315,16 @@ class mail_hooks
|
||||
),
|
||||
'insertSignatureAtTopOfMessage' => array(
|
||||
'type' => 'select',
|
||||
'label' => 'signature at top',
|
||||
'help' => 'insert the signature at top of the new (or reply) message when opening compose dialog (you may not be able to switch signatures)',
|
||||
'label' => 'Signature position and visibility',
|
||||
'help' => 'Should signature be inserted after (standard) or before a reply or inline forward, and should signature be visible and changeable during compose.',
|
||||
'name' => 'insertSignatureAtTopOfMessage',
|
||||
'values' => $no_yes,
|
||||
'values' => array(
|
||||
'0' => 'After reply, visible during compose',
|
||||
'1' => 'Before reply, visible during compose',
|
||||
'' => 'Appened after reply before sending',
|
||||
),
|
||||
'xmlrpc' => True,
|
||||
'default'=> 0,
|
||||
'default'=> '0',
|
||||
'admin' => False,
|
||||
),
|
||||
'attachVCardAtCompose' => array(
|
||||
|
@ -364,6 +364,22 @@ input[type=button] {
|
||||
/*********************************
|
||||
************ mailCompose ******
|
||||
*********************************/
|
||||
div.mailUploadSection {
|
||||
border-top: 1px solid silver;
|
||||
margin-top: 16px;
|
||||
}
|
||||
div.mailUploadSection > label {
|
||||
margin-top: -10px;
|
||||
padding-left: 4px;
|
||||
padding-right: 12px;
|
||||
background-color: white;
|
||||
display: table-caption;
|
||||
white-space: nowrap;
|
||||
margin-left: 6px;
|
||||
}
|
||||
#mail-compose_filemode {
|
||||
margin-left: 6px;
|
||||
}
|
||||
#mail-compose_selectFromVFSForCompose{
|
||||
width:20px;
|
||||
float:none;
|
||||
|
@ -111,8 +111,8 @@
|
||||
<hbox disabled="@is_html" class="mailComposeBody">
|
||||
<textbox multiline="true" rows="40" cols="120" width="100%" span="all" no_lang="1" name="mail_plaintext" id="mail_plaintext"/>
|
||||
</hbox>
|
||||
<groupbox class="et2_file mailUploadSection" disabled="@no_griddata">
|
||||
<caption label="Files"/>
|
||||
<vbox class="et2_file mailUploadSection" disabled="@no_griddata">
|
||||
<select id="filemode" label="Send files as"/>
|
||||
<grid id="attachments" width="100%" maxheight="165" class="egwGridView_grid">
|
||||
<columns>
|
||||
<column disabled="!@showtempname" width="10%"/>
|
||||
@ -129,7 +129,7 @@
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</groupbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
</template>
|
||||
</overlay>
|
||||
|
@ -361,6 +361,22 @@ input[type=button] {
|
||||
/*********************************
|
||||
************ mailCompose ******
|
||||
*********************************/
|
||||
div.mailUploadSection {
|
||||
border-top: 1px solid silver;
|
||||
margin-top: 16px;
|
||||
}
|
||||
div.mailUploadSection > label {
|
||||
margin-top: -10px;
|
||||
padding-left: 4px;
|
||||
padding-right: 12px;
|
||||
background-color: white;
|
||||
display: table-caption;
|
||||
white-space: nowrap;
|
||||
margin-left: 6px;
|
||||
}
|
||||
#mail-compose_filemode {
|
||||
margin-left: 6px;
|
||||
}
|
||||
#mail-compose_selectFromVFSForCompose {
|
||||
width: 20px;
|
||||
float: none;
|
||||
|
@ -199,6 +199,145 @@ class egw_sharing
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new share
|
||||
*
|
||||
* @param string $path either path in temp_dir or vfs with optional vfs scheme
|
||||
* @param string $mode 'link': copy file in users tmp-dir or 'share_ro' share given vfs file, if no vfs behave as 'link'
|
||||
* @param string $name filename to use for $mode='link', default basename of $path
|
||||
* @param string|array $recipients one or more recipient email addresses
|
||||
* @param array $extra =array() extra data to store
|
||||
* @throw egw_exception_not_found if $path not found
|
||||
* @throw egw_excpetion_assertion_failed if user temp. directory does not exist and can not be created
|
||||
* @return array with share data, eg. value for key 'share_token'
|
||||
*/
|
||||
public static function create($path, $mode, $name, $recipients, $extra=array())
|
||||
{
|
||||
if (!isset(self::$db)) self::$db = $GLOBALS['egw']->db;
|
||||
|
||||
if (empty($name)) $name = $path;
|
||||
|
||||
$path2tmp =& egw_cache::getSession(__CLASS__, 'path2tmp');
|
||||
|
||||
// allow filesystem path only for temp_dir
|
||||
$temp_dir = $GLOBALS['egw_info']['server']['temp_dir'].'/';
|
||||
if (substr($path, 0, strlen($temp_dir)) == $temp_dir)
|
||||
{
|
||||
$mode = 'link';
|
||||
}
|
||||
elseif(parse_url($path, PHP_URL_SCHEME) !== 'vfs')
|
||||
{
|
||||
$path = 'vfs://default'.($path[0] == '/' ? '' : '/').$path;
|
||||
}
|
||||
// check if file exists and is readable
|
||||
if (!file_exists($path) || is_readable($path))
|
||||
{
|
||||
throw new egw_exception_not_found("'$path' NOT found!");
|
||||
}
|
||||
// check if file has been shared before
|
||||
if (($mode != 'link' || isset($path2tmp[$path])) &&
|
||||
($share = self::$db->select(self::TABLE, '*', array(
|
||||
'share_path' => $mode == 'link' ? $path2tmp[$path] : egw_vfs::parse_url($path, PHP_URL_PATH),
|
||||
'share_owner' => $GLOBALS['egw_info']['user']['account_id'],
|
||||
)+$extra, __LINE__, __FILE__)->fetch()))
|
||||
{
|
||||
// if yes, just add additional recipients
|
||||
$share['share_recipients'] = $share['share_recipients'] ? explode(',', $share['recipients']) : array();
|
||||
$need_save = false;
|
||||
foreach((array)$recipients as $recipient)
|
||||
{
|
||||
if (!in_array($recipient, $share['recipients']))
|
||||
{
|
||||
$share['recipients'][] = $recipient;
|
||||
$need_save = true;
|
||||
}
|
||||
}
|
||||
$share['share_recipients'] = implode(',', $share['recipients']);
|
||||
if ($need_save)
|
||||
{
|
||||
self::$db->update(self::TABLE, array(
|
||||
'share_recipients' => $share['share_recipients'],
|
||||
), array(
|
||||
'share_id' => $share['share_id'],
|
||||
), __LINE__, __FILE__);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if not create new share
|
||||
if ($mode == 'link')
|
||||
{
|
||||
$user_tmp = '/home/'.$GLOBALS['egw_info']['user']['account_lid'].'/.tmp';
|
||||
if (!egw_vfs::file_exists($user_tmp) && !egw_vfs::mkdir($user_tmp))
|
||||
{
|
||||
throw new egw_exception_assertion_failed("Could NOT create temp. directory '$user_tmp'!");
|
||||
}
|
||||
$n = 0;
|
||||
do {
|
||||
$tmp_file = egw_vfs::concat($user_tmp, ($n?$n.'.':'').egw_vfs::basename($name));
|
||||
} while(!($fp = egw_vfs::fopen($tmp_file, 'x')) && $n++ < 100);
|
||||
|
||||
if ($n >= 100)
|
||||
{
|
||||
throw new egw_exception_assertion_failed("Could NOT create temp. file '$tmp_file'!");
|
||||
}
|
||||
fclose($fp);
|
||||
|
||||
if (!copy($path, egw_vfs::PREFIX.$tmp_file))
|
||||
{
|
||||
throw new egw_exception_assertion_failed("Could NOT create temp. file '$tmp_file'!");
|
||||
}
|
||||
// store temp. path in session, to be able to add more recipients
|
||||
$path2tmp[$path] = $tmp_file;
|
||||
|
||||
$path = $tmp_file;
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
while(true) // self::token() can return an existing value
|
||||
{
|
||||
try {
|
||||
self::$db->insert(self::TABLE, $share = array(
|
||||
'share_token' => self::token(),
|
||||
'share_path' => egw_vfs::parse_url($path, PHP_URL_PATH),
|
||||
'share_owner' => $GLOBALS['egw_info']['user']['account_id'],
|
||||
'share_with' => implode(',', (array)$recipients),
|
||||
'share_created' => time(),
|
||||
)+$extra, false, __LINE__, __FILE__);
|
||||
|
||||
$share['share_id'] = self::$db->get_last_insert_id(self::TABLE, 'share_id');
|
||||
break;
|
||||
}
|
||||
catch(egw_exception_db $e) {
|
||||
if ($i++ > 3) throw $e;
|
||||
unset($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $share;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate link from share or share-token
|
||||
*
|
||||
* @param string|array $share share or share-token
|
||||
* @return string
|
||||
*/
|
||||
public static function share2link($share)
|
||||
{
|
||||
if (is_array($share)) $share = $share['share_token'];
|
||||
|
||||
$link = egw::link('/share.php').'/'.$share;
|
||||
if ($link[0] == '/')
|
||||
{
|
||||
$link = ($_SERVER['HTTPS'] ? 'https://' : 'http://').
|
||||
($GLOBALS['egw_info']['server']['hostname'] ?
|
||||
$GLOBALS['egw_info']['server']['hostname'] : $_SERVER['HTTP_HOST']).
|
||||
$link;
|
||||
}
|
||||
return $link;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_exists(__DIR__.'/../../filemanager/inc/class.filemanager_ui.inc.php'))
|
||||
|
Loading…
Reference in New Issue
Block a user