* Mail: Implement mail integration with new structure and add new feature

- Add mail to calendar as calendar entry, including all mail attachments as links
- Add user choice for saving mail into an existing ticket or a new ticket
- Fix mail attachments integration into infolog, tracker or calendar entry
This commit is contained in:
Hadi Nategh 2015-05-05 08:03:13 +00:00
commit 50782cfa8b
19 changed files with 840 additions and 576 deletions

View File

@ -856,6 +856,19 @@ END:VALARM';
unset($data); // not used, but in function signature for hooks
return true;
}
/**
* Mail integration hook to import mail message contents into a calendar entry
*
* @return string method to be executed for calendar mail integration
*/
public static function mail_import($args)
{
return array (
'menuaction' => 'calendar.calendar_uiforms.mail_import',
'popup' => egw_link::get_registry('calendar', 'edit_popup')
);
}
}
// Not part of the class, since config hooks are still using the old style
@ -879,4 +892,4 @@ function calendar_purge_old($config)
$GLOBALS['config_error'] = 'Unable to schedule purge';
}
}
}
}

View File

@ -32,6 +32,7 @@ class calendar_uiforms extends calendar_ui
'import' => true,
'cat_acl' => true,
'meeting' => true,
'mail_import' => true,
);
/**
@ -1317,13 +1318,12 @@ class calendar_uiforms extends calendar_ui
$event['whole_day'] = !$start['hour'] && !$start['minute'] && $end['hour'] == 23 && $end['minute'] == 59;
$link_to_id = $event['id'];
if (!$add_link && !$event['id'] && isset($_REQUEST['link_app']) && isset($_REQUEST['link_id']))
if (!$event['id'] && isset($_REQUEST['link_app']) && isset($_REQUEST['link_id']))
{
$link_ids = is_array($_REQUEST['link_id']) ? $_REQUEST['link_id'] : array($_REQUEST['link_id']);
foreach(is_array($_REQUEST['link_app']) ? $_REQUEST['link_app'] : array($_REQUEST['link_app']) as $n => $link_app)
{
$link_id = $link_ids[$n];
$app_entry = array();
if(!preg_match('/^[a-z_0-9-]+:[:a-z_0-9-]+$/i',$link_app.':'.$link_id)) // guard against XSS
{
continue;
@ -1687,9 +1687,9 @@ class calendar_uiforms extends calendar_ui
* Display for FMail an iCal meeting request and allow to accept, tentative or reject it or a reply and allow to apply it
*
* @todo Handle situation when user is NOT invited, but eg. can view that mail ...
* @param array $event=null; special usage if $event is array('event'=>null,'msg'=>'','useSession'=>true) we
* @param array $event = null; special usage if $event is array('event'=>null,'msg'=>'','useSession'=>true) we
* are called by new mail-app; and we intend to use the stuff passed on by session
* @param string $msg=null
* @param string $msg = null
*/
function meeting(array $event=null, $msg=null)
{
@ -1866,7 +1866,7 @@ class calendar_uiforms extends calendar_ui
$event['ics_method_label'] = strtolower($ical_method) == 'request' ?
lang('Meeting request') : lang('Reply to meeting request');
$tpl = new etemplate_new('calendar.meeting');
$tpl->exec('calendar.calendar_uiforms.meeting', $event, $sel_options, $readonlys, $event, 2);
$tpl->exec('calendar.calendar_uiforms.meeting', $event, array(), $readonlys, $event, 2);
}
/**
@ -2058,7 +2058,7 @@ class calendar_uiforms extends calendar_ui
{
if (!$content['duration']) $content['duration'] = $content['end'] - $content['start'];
$weekds = 0;
foreach ($content['weekdays'] as $keys =>$wdays)
foreach ($content['weekdays'] as &$wdays)
{
$weekds = $weekds + $wdays;
}
@ -2288,8 +2288,6 @@ class calendar_uiforms extends calendar_ui
}
if (!is_array($content))
{
$view = $GLOBALS['egw']->session->appsession('view','calendar');
$content = array(
'start' => $this->bo->date2ts($_REQUEST['start'] ? $_REQUEST['start'] : $this->date),
'end' => $this->bo->date2ts($_REQUEST['end'] ? $_REQUEST['end'] : $this->date),
@ -2562,4 +2560,100 @@ class calendar_uiforms extends calendar_ui
}
}
}
/**
* imports a mail as Calendar
*
* @param array $mailContent = null mail content
* @return array
*/
function mail_import(array $mailContent=null)
{
// It would get called from compose as a popup with egw_data
if (!is_array($mailContent) && ($_GET['egw_data']))
{
// get raw mail data
egw_link::get_data ($_GET['egw_data']);
return false;
}
if (is_array($mailContent))
{
// Addressbook
$AB = new addressbook_bo();
$accounts = array(0 => $GLOBALS['egw_info']['user']['account_id']);
$participants[0] = array (
'uid' => $GLOBALS['egw_info']['user']['account_id'],
'delete_id' => $GLOBALS['egw_info']['user']['account_id'],
'status' => 'A',
'old_status' => 'A',
'app' => 'User',
'role' => 'REQ-PARTICIPANT'
);
foreach($mailContent['addresses'] as $address)
{
// Get available contacts from the email
$contacts = $AB->search(array(
'email' => $address['email'],
'email_home' => $address['email']
),'contact_id,contact_email,contact_email_home,egw_addressbook.account_id as account_id','','','',false,'OR',false,array('owner' => 0),'',false);
if (is_array($contacts))
{
foreach($contacts as $account)
{
$accounts[] = $account['account_id'];
}
}
else
{
$participants []= array (
'app' => 'email',
'uid' => 'e'.$address['email'],
'status' => 'U',
'old_status' => 'U'
);
}
}
$participants = array_merge($participants , array(
"account" => $accounts,
"role" => "REQ-PARTICIPANT",
"add" => "pressed"
));
// Prepare calendar event draft
$event = array(
'title' => $mailContent['subject'],
'description' => $mailContent['message'],
'participants' => $participants,
'link_to' => array(
'to_app' => 'calendar',
'to_id' => 0,
),
'start' => $mailContent['date'],
'duration' => 60 * $this->cal_prefs['interval']
);
if (is_array($mailContent['attachments']))
{
foreach ($mailContent['attachments'] as $attachment)
{
if($attachment['egw_data'])
{
egw_link::link('calendar',$event['link_to']['to_id'],egw_link::DATA_APPNAME, $attachment);
}
else if(is_readable($attachment['tmp_name']))
{
egw_link::link('calendar',$event['link_to']['to_id'],'file', $attachment);
}
}
}
}
else
{
egw_framework::window_close(lang('No content found to show up as calendar entry.'));
}
return $this->process_edit($event);
}
}

View File

@ -46,6 +46,7 @@ $setup_info['calendar']['hooks']['infolog_set'] = 'calendar.calendar_bo.infolog_
$setup_info['calendar']['hooks']['export_limit'] = 'calendar_hooks::getAppExportLimit';
$setup_info['calendar']['hooks']['acl_rights'] = 'calendar_hooks::acl_rights';
$setup_info['calendar']['hooks']['categories'] = 'calendar_hooks::categories';
$setup_info['calendar']['hooks']['mail_import'] = 'calendar_hooks::mail_import';
/* Dependencies for this app to work */
$setup_info['calendar']['depends'][] = array(

File diff suppressed because it is too large Load Diff

View File

@ -1672,7 +1672,7 @@ var et2_link_list = et2_link_string.extend(
link.dom_id = 'temp_'+egw.uid();
}
// Icon should be in registry
if(typeof link.icon == 'undefined')
if(!link.icon)
{
link.icon = egw.link_get_registry(link.app,'icon');
// No icon, try by mime type - different place for un-saved entries
@ -1684,7 +1684,7 @@ var et2_link_list = et2_link_string.extend(
}
}
// Special handling for file - if not existing, we can't ask for title
if(link.app == 'file' && typeof link.title == 'undefined')
if(typeof link.id =='object' && !link.title)
{
link.title = link.id.name || '';
}

View File

@ -297,7 +297,7 @@ class infolog_bo
* checks if there are customfields for typ $typ
*
* @param string $type
* @param boolean $links=false if true check only customfields containing links, default false = all custom fields
* @param boolean $links = false if true check only customfields containing links, default false = all custom fields
* @return boolean True if there are customfields for $typ, else False
*/
function has_customfields($type,$links=false)
@ -321,7 +321,7 @@ class infolog_bo
* @param int|array $info data or info_id of infolog entry to check
* @param int $required_rights EGW_ACL_{READ|EDIT|ADD|DELETE}
* @param int $other uid to check (if info==0) or 0 to check against $this->user
* @param int $user=null user whos rights to check, default current user
* @param int $user = null user whos rights to check, default current user
* @return boolean
*/
function check_access($info,$required_rights,$other=0,$user=null)
@ -413,8 +413,8 @@ class infolog_bo
* convert a link_id value into an info_from text
*
* @param array &$info infolog entry, key info_from gets set by this function
* @param string $not_app='' app to exclude
* @param string $not_id='' id to exclude
* @param string $not_app = '' app to exclude
* @param string $not_id = '' id to exclude
* @return boolean True if we have a linked item, False otherwise
*/
function link_id2from(&$info,$not_app='',$not_id='')
@ -482,8 +482,8 @@ class infolog_bo
* and $fromTZId is only used to qualify dates.
*
* @param array $values to modify
* @param string $fromTZId=null
* @param string $toTZId=false
* @param string $fromTZId = null
* @param string $toTZId = false
* TZID timezone name e.g. 'UTC'
* or NULL for timestamps in user-time
* or false for timestamps in server-time
@ -555,7 +555,7 @@ class infolog_bo
* convert a date from server to user-time
*
* @param int $ts timestamp in server-time
* @param string $date_format='ts' date-formats: 'ts'=timestamp, 'server'=timestamp in server-time, 'array'=array or string with date-format
* @param string $date_format = 'ts' date-formats: 'ts'=timestamp, 'server'=timestamp in server-time, 'array'=array or string with date-format
* @return mixed depending of $date_format
*/
function date2usertime($ts,$date_format='ts')
@ -569,11 +569,11 @@ class infolog_bo
* Read an infolog entry specified by $info_id
*
* @param int|array $info_id integer id or array with id's or array with column=>value pairs of the entry to read
* @param boolean $run_link_id2from=true should link_id2from run, default yes,
* @param boolean $run_link_id2from = true should link_id2from run, default yes,
* need to be set to false if called from link-title to prevent an infinit recursion
* @param string $date_format='ts' date-formats: 'ts'=timestamp, 'server'=timestamp in server-time,
* @param string $date_format = 'ts' date-formats: 'ts'=timestamp, 'server'=timestamp in server-time,
* 'array'=array or string with date-format
* @param boolean $ignore_acl=false if true, do NOT check access, default false
* @param boolean $ignore_acl = false if true, do NOT check access, default false
*
* @return array|boolean infolog entry, null if not found or false if no permission to read it
*/
@ -705,12 +705,12 @@ class infolog_bo
* checks and asures ACL
*
* @param array &$values values to write
* @param boolean $check_defaults=true check and set certain defaults
* @param boolean|int $touch_modified=true touch the modification date and sets the modifier's user-id, 2: only modifier
* @param boolean $user2server=true conversion between user- and server-time necessary
* @param boolean $skip_notification=false true = do NOT send notification, false (default) = send notifications
* @param boolean $throw_exception=false Throw an exception (if required fields are not set)
* @param string $purge_cfs=null null=dont, 'ical'=only iCal X-properties (cfs name starting with "#"), 'all'=all cfs
* @param boolean $check_defaults = true check and set certain defaults
* @param boolean|int $touch_modified = true touch the modification date and sets the modifier's user-id, 2: only modifier
* @param boolean $user2server = true conversion between user- and server-time necessary
* @param boolean $skip_notification = false true = do NOT send notification, false (default) = send notifications
* @param boolean $throw_exception = false Throw an exception (if required fields are not set)
* @param string $purge_cfs = null null=dont, 'ical'=only iCal X-properties (cfs name starting with "#"), 'all'=all cfs
*
* @return int|boolean info_id on a successfull write or false
*/
@ -1102,7 +1102,7 @@ class infolog_bo
/**
* Query ctag for infolog
*
* @param array $filter=array('filter'=>'own','info_type'=>'task')
* @param array $filter = array('filter'=>'own','info_type'=>'task')
* @return string
*/
public function getctag(array $filter=array('filter'=>'own','info_type'=>'task'))
@ -1131,33 +1131,29 @@ class infolog_bo
*
* @author Cornelius Weiss <nelius@cwtech.de>
* @todo search if infolog with from and subject allready exists ->appned body & inform user
* @param string $_email_address rfc822 conform emailaddresses
* @param array $_addresses array of addresses
* - array (email,name)
* @param string $_subject
* @param string $_message
* @param array $_attachments
* @param string $_date
* @return array $content array for uiinfolog
*/
function import_mail($_email_address,$_subject,$_message,$_attachments,$_date)
function import_mail($_addresses,$_subject,$_message,$_attachments,$_date)
{
$address_array = imap_rfc822_parse_adrlist($_email_address,'');
foreach ((array)$address_array as $address)
foreach($_addresses as $address)
{
$email[] = $emailadr = sprintf('%s@%s',
trim($address->mailbox),
trim($address->host));
$name[] = !empty($address->personal) ? $address->personal : $emailadr;
$names[] = $address['name'];
$emails[] =$address['email'];
}
// shorten long (> $this->max_line_chars) lines of "line" chars (-_+=~) in mails
$_message = preg_replace_callback('/[-_+=~\.]{'.$this->max_line_chars.',}/m',
create_function('$matches',"return substr(\$matches[0],0,$this->max_line_chars);"),$_message);
$type = isset($this->enums['type']['email']) ? 'email' : 'note';
$status = isset($this->status['defaults'][$type]) ? $this->status['defaults'][$type] : 'done';
$info = array(
'info_id' => 0,
'info_type' => $type,
'info_from' => implode(', ',$name),
'info_addr' => implode(', ',$email),
'info_from' => implode(', ',$names),
'info_addr' => implode(', ',$emails),
'info_subject' => $_subject,
'info_des' => $_message,
'info_startdate' => egw_time::server2user($_date),
@ -1174,7 +1170,7 @@ class infolog_bo
// find the addressbookentry to link with
$addressbook = new addressbook_bo();
$contacts = array();
foreach ($email as $mailadr)
foreach ($emails as $mailadr)
{
$contacts = array_merge($contacts,(array)$addressbook->search(
array(
@ -1202,14 +1198,13 @@ class infolog_bo
{
foreach ($_attachments as $attachment)
{
$is_vfs = false;
if (parse_url($attachment['tmp_name'],PHP_URL_SCHEME) == 'vfs' && egw_vfs::is_readable($attachment['tmp_name']))
if($attachment['egw_data'])
{
$is_vfs = true;
egw_link::link('infolog',$info['link_to']['to_id'],egw_link::DATA_APPNAME, $attachment);
}
if(is_readable($attachment['tmp_name']) || $is_vfs)
else if(is_readable($attachment['tmp_name']))
{
egw_link::link('infolog',$info['link_to']['to_id'],'file',$attachment);
egw_link::link('infolog',$info['link_to']['to_id'],'file', $attachment);
}
}
}
@ -1294,8 +1289,8 @@ class infolog_bo
*
* @param int|array $id id of entry or entry array
* @param int $check EGW_ACL_READ for read and EGW_ACL_EDIT for write or delete access
* @param string $rel_path=null currently not used in InfoLog
* @param int $user=null for which user to check, default current user
* @param string $rel_path = null currently not used in InfoLog
* @param int $user = null for which user to check, default current user
* @return boolean true if access is granted or false otherwise
*/
function file_access($id,$check,$rel_path=null,$user=null)
@ -1439,7 +1434,7 @@ class infolog_bo
* currently used for ical/sif import
*
* @param array $catname_list names of the categories which should be found or added
* @param int $info_id=-1 match against existing infolog and expand the returned category ids
* @param int $info_id = -1 match against existing infolog and expand the returned category ids
* by the ones the user normally does not see due to category permissions - used to preserve categories
* @return array category ids (found, added and preserved categories)
*/
@ -1692,8 +1687,8 @@ class infolog_bo
*
* As status value can have different translations depending on type, we list all translations
*
* @param string $type=null
* @param array &$icons=null on return name of icons
* @param string $type = null
* @param array &$icons = null on return name of icons
* @return array value => (commaseparated) translations
*/
function get_status($type=null, array &$icons=null)
@ -1763,8 +1758,8 @@ class infolog_bo
* This expects timestamps to be in server-time.
*
* @param array $infoData the infolog data we try to find
* @param boolean $relax=false if asked to relax, we only match against some key fields
* @param string $tzid=null timezone, null => user time
* @param boolean $relax = false if asked to relax, we only match against some key fields
* @param string $tzid = null timezone, null => user time
*
* @return array of infolog_ids of matching entries
*/

View File

@ -558,4 +558,17 @@ class infolog_hooks
unset($location); // not used, but part of hook signature
return true;
}
/**
* Mail integration hook to import mail message contents into an infolog entry
*
* @return array
*/
public static function mail_import($args)
{
return array (
'menuaction' => 'infolog.infolog_ui.mail_import',
'popup' => egw_link::get_registry('infolog', 'edit_popup')
);
}
}

View File

@ -23,7 +23,7 @@ class infolog_ui
'admin' => True,
'hook_view' => True,
'writeLangFile' => True,
'import_mail' => True,
'mail_import' => True
);
/**
* reference to the infolog preferences of the user
@ -2482,185 +2482,25 @@ class infolog_ui
/**
* imports a mail as infolog
* two possible calls:
* 1. with function args set. (we come from send mail)
* 2. with $_GET['uid] = someuid (we come from display mail)
*
* @author Cornelius Weiss <nelius@cwtech.de>
* @param string $_to_emailAddress
* @param string $_subject
* @param string $_body
* @param array $_attachments
* @param string $_date
* @param resource $_rawMail
* @param array $mailContent = null content of mail
* @return array
*/
function import_mail($_to_emailAddress=false,$_subject=false,$_body=false,$_attachments=false,$_date=false,$_rawMail=null)
function mail_import(array $mailContent=null)
{
$uid = $_GET['uid'];
$partid = $_GET['part'];
$mailbox = base64_decode($_GET['mailbox']);
$mailClass = 'mail_bo';
$sessionLocation = 'mail';
// if rowid is set, we are called from new mail module.
if (method_exists('mail_ui','splitRowID') && isset($_GET['rowid']) && !empty($_GET['rowid']))
// It would get called from compose as a popup with egw_data
if (!is_array($mailContent) && ($_GET['egw_data']))
{
// rowid holds all needed information: server, folder, uid, etc.
$rowID = $_GET['rowid'];
$hA = mail_ui::splitRowID($rowID);
$sessionLocation = $hA['app']; // THIS is part of the row ID, we may use this for validation
if ($sessionLocation != 'mail') throw new egw_exception_assertion_failed(lang('Application mail expected but got: %1',$sessionLocation));
$uid = $hA['msgUID'];
$mailbox = $hA['folder'];
$icServerID = $hA['profileID'];
$mailClass = 'mail_bo';
// get the mail raw data
egw_link::get_data ($_GET['egw_data']);
return false;
}
if ($_date == false || empty($_date)) $_date = $this->bo->user_time_now;
if (!empty($_to_emailAddress))
{
$GLOBALS['egw_info']['flags']['currentapp'] = 'infolog';
if (!($GLOBALS['egw_info']['user']['preferences'][$sessionLocation]['saveAsOptions']==='text_only')&&is_array($_attachments))
{
//echo __METHOD__.'<br>';
//_debug_array($_attachments);
if (!isset($icServerID)) $icServerID =& egw_cache::getSession($sessionLocation,'activeProfileID');
$mailobject = $mailClass::getInstance(true,$icServerID);
$mailobject->openConnection();
foreach ($_attachments as $attachment)
{
//error_log(__METHOD__.__LINE__.array2string($attachment));
if (trim(strtoupper($attachment['type'])) == 'MESSAGE/RFC822' && !empty($attachment['uid']) && !empty($attachment['folder']))
{
$mailobject->reopen(($attachment['folder']?$attachment['folder']:$mailbox));
// get the message itself, and attach it, as we are able to display it in egw
// instead of fetching only the attachments attached files (as we did previously)
$message = $mailobject->getMessageRawBody($attachment['uid'],$attachment['partID'],($attachment['folder']?$attachment['folder']:$mailbox));
$headers = $mailobject->getMessageHeader($attachment['uid'],$attachment['partID'],true,false,($attachment['folder']?$attachment['folder']:$mailbox));
$subject = $mailClass::adaptSubjectForImport($headers['SUBJECT']);
$attachment_file =tempnam($GLOBALS['egw_info']['server']['temp_dir'],$GLOBALS['egw_info']['flags']['currentapp']."_");
$tmpfile = fopen($attachment_file,'w');
fwrite($tmpfile,$message);
fclose($tmpfile);
$size = filesize($attachment_file);
$attachments[] = array(
'name' => trim($subject).'.eml',
'mimeType' => 'message/rfc822',
'type' => 'message/rfc822',
'tmp_name' => $attachment_file,
'size' => $size,
);
}
else
{
if (!empty($attachment['folder']))
{
$is_winmail = $_GET['is_winmail'] ? $_GET['is_winmail'] : 0;
$mailobject->reopen($attachment['folder']);
$attachmentData = $mailobject->getAttachment($attachment['uid'],$attachment['partID'],$is_winmail);
$attachment['file'] =tempnam($GLOBALS['egw_info']['server']['temp_dir'],$GLOBALS['egw_info']['flags']['currentapp']."_");
$tmpfile = fopen($attachment['file'],'w');
fwrite($tmpfile,$attachmentData['attachment']);
fclose($tmpfile);
}
//make sure we search for our attached file in our configured temp_dir
if (isset($attachment['file']) && parse_url($attachment['file'],PHP_URL_SCHEME) != 'vfs' &&
file_exists($GLOBALS['egw_info']['server']['temp_dir'].SEP.basename($attachment['file'])))
{
$attachment['file'] = $GLOBALS['egw_info']['server']['temp_dir'].SEP.basename($attachment['file']);
}
$attachments[] = array(
'name' => $attachment['name'],
'mimeType' => $attachment['type'],
'type' => $attachment['type'],
'tmp_name' => $attachment['file'],
'size' => $attachment['size'],
);
}
}
$mailobject->closeConnection();
}
// this one adds the mail itself (as message/rfc822 (.eml) file) to the infolog as additional attachment
// this is done to have a simple archive functionality (ToDo: opening .eml in email module)
if (is_resource($_rawMail) && $GLOBALS['egw_info']['user']['preferences'][$sessionLocation]['saveAsOptions']==='add_raw')
{
$subject = $mailClass::adaptSubjectForImport($_subject);
$attachment_file =tempnam($GLOBALS['egw_info']['server']['temp_dir'],$GLOBALS['egw_info']['flags']['currentapp']."_");
$tmpfile = fopen($attachment_file,'w');
fseek($_rawMail, 0, SEEK_SET);
stream_copy_to_stream($_rawMail, $tmpfile);
fclose($tmpfile);
$size = filesize($attachment_file);
$attachments[] = array(
'name' => trim($subject).'.eml',
'mimeType' => 'message/rfc822',
'type' => 'message/rfc822',
'tmp_name' => $attachment_file,
'size' => $size,
);
}
//_debug_array($_to_emailAddress);
$toaddr = array();
foreach(array('to','cc','bcc') as $x)
{
if (is_array($_to_emailAddress[$x]) && !empty($_to_emailAddress[$x]))
{
$toaddr = array_merge($toaddr,$_to_emailAddress[$x]);
}
}
//_debug_array($attachments);
$body_striped = strip_tags($_body); //we need to fix broken tags (or just stuff like "<800 USD/p" )
$body_decoded = htmlspecialchars_decode($body_striped,ENT_QUOTES);
$body = $mailClass::createHeaderInfoSection(array('FROM'=>$_to_emailAddress['from'],
'TO'=>(!empty($_to_emailAddress['to'])?implode(',',$_to_emailAddress['to']):null),
'CC'=>(!empty($_to_emailAddress['cc'])?implode(',',$_to_emailAddress['cc']):null),
'BCC'=>(!empty($_to_emailAddress['bcc'])?implode(',',$_to_emailAddress['bcc']):null),
'SUBJECT'=>$_subject,
'DATE'=>$mailClass::_strtotime($_date))).$body_decoded;
$this->edit($this->bo->import_mail(
implode(',',$toaddr),$_subject,$body,$attachments,$_date
));
exit;
}
elseif ($uid && $mailbox)
{
if (!isset($icServerID)) $icServerID =& egw_cache::getSession($sessionLocation,'activeProfileID');
$mailobject = $mailClass::getInstance(true,$icServerID);
$mailobject->openConnection();
$mailobject->reopen($mailbox);
$mailcontent = $mailClass::get_mailcontent($mailobject,$uid,$partid,$mailbox,false,true,(!($GLOBALS['egw_info']['user']['preferences'][$sessionLocation]['saveAsOptions']==='text_only')));
// this one adds the mail itself (as message/rfc822 (.eml) file) to the infolog as additional attachment
// this is done to have a simple archive functionality (ToDo: opening .eml in email module)
if ($GLOBALS['egw_info']['user']['preferences'][$sessionLocation]['saveAsOptions']==='add_raw')
{
$message = $mailobject->getMessageRawBody($uid, $partid,$mailbox);
$headers = $mailobject->getMessageHeader($uid, $partid,true,false,$mailbox);
$subject = $mailClass::adaptSubjectForImport($headers['SUBJECT']);
$attachment_file =tempnam($GLOBALS['egw_info']['server']['temp_dir'],$GLOBALS['egw_info']['flags']['currentapp']."_");
$tmpfile = fopen($attachment_file,'w');
fwrite($tmpfile,$message);
fclose($tmpfile);
$size = filesize($attachment_file);
$mailcontent['attachments'][] = array(
'name' => trim($subject).'.eml',
'mimeType' => 'message/rfc822',
'type' => 'message/rfc822',
'tmp_name' => $attachment_file,
'size' => $size,
);
}
//_debug_array($mailcontent);
return $this->edit($this->bo->import_mail(
$mailcontent['mailaddress'],
$mailcontent['subject'],
$mailcontent['message'],
$mailcontent['attachments'],
strtotime($mailcontent['headers']['DATE'])
));
}
egw_framework::window_close(lang('Error: no mail (Mailbox / UID) given!'));
return $this->edit($this->bo->import_mail($mailContent['addresses'],
$mailContent['subject'],
$mailContent['message'],
$mailContent['attachments'],
$mailContent['date']));
}
/**

View File

@ -63,6 +63,7 @@ $setup_info['infolog']['hooks']['search_link'] = 'infolog_hooks::search_link';
$setup_info['infolog']['hooks']['pm_custom_app_icons'] = 'infolog.infolog_bo.pm_icons';
$setup_info['infolog']['hooks']['timesheet_set'] = 'infolog.infolog_ui.timesheet_set';
$setup_info['infolog']['hooks']['calendar_set'] = 'infolog.infolog_ui.calendar_set';
$setup_info['infolog']['hooks']['mail_import'] = 'infolog_hooks::mail_import';
/* Dependencies for this app to work */
$setup_info['infolog']['depends'][] = array(

View File

@ -163,6 +163,14 @@ class mail_compose
'hint' => 'check to save as trackerentry on send',
'onExecute' => 'javaScript:app.mail.compose_setToggle'
),
'to_calendar' => array(
'caption' => 'Calendar',
'icon' => 'to_calendar',
'group' => $group,
'checkbox' => true,
'hint' => 'check to save as calendar event on send',
'onExecute' => 'javaScript:app.mail.compose_setToggle'
),
'disposition' => array(
'caption' => 'Notification',
'icon' => 'high',
@ -1002,14 +1010,11 @@ class mail_compose
}
}
}
//Since the ckeditor is not stable enough on mobile devices, we always convert html messages to plain text
//TODO: needs to remove html:$ua_mobile condition after better mobile support from CKeditor
//mobile compatibility is disabled expilcitly in ckeditor.js plugin too, which needs to be removed
if ($content['mimeType'] == 'html' && html::htmlarea_availible()===false || html::$ua_mobile)
if ($content['mimeType'] == 'html' && html::htmlarea_availible()===false)
{
$_content['mimeType'] = $content['mimeType'] = 'plain';
$content['body'] = $this->convertHTMLToText($content['body']);
$readonlys['mimeType'] = true;
}
// is a certain signature requested?
// only the following values are supported (and make sense)
@ -1290,7 +1295,7 @@ class mail_compose
$content['to'] = self::resolveEmailAddressList($content['to']);
//error_log(__METHOD__.__LINE__.array2string($content));
$etpl->exec('mail.mail_compose.compose',$content,$sel_options,$readonlys,$preserv,2);
$etpl->exec('mail.mail_compose.compose',$content,$sel_options,array(),$preserv,2);
}
/**
@ -2448,7 +2453,7 @@ class mail_compose
*/
public function ajax_saveAsDraft ($content, $action='button[saveAsDraft]')
{
//error_log(__METHOD__."(, action=$action)");
//error_log(__METHOD__.__LINE__.array2string($content)."(, action=$action)");
$response = egw_json_response::get();
$success = true;
@ -3047,43 +3052,44 @@ class mail_compose
if (is_array($this->sessionData['cc'])) $mailaddresses['cc'] = $this->sessionData['cc'];
if (is_array($this->sessionData['bcc'])) $mailaddresses['bcc'] = $this->sessionData['bcc'];
if (!empty($mailaddresses)) $mailaddresses['from'] = $GLOBALS['egw']->translation->decodeMailHeader($fromAddress);
// attention: we dont return from infolog/tracker. You cannot check both. cleanups will be done there.
if ($_formData['to_infolog'] == 'on') {
$uiinfolog = new infolog_ui();
$uiinfolog->import_mail(
$mailaddresses,
$this->sessionData['subject'],
$this->convertHTMLToText($this->sessionData['body']),
$this->sessionData['attachments'],
false, // date
$mail->getRaw()
);
}
if ($_formData['to_tracker'] == 'on') {
$uitracker = new tracker_ui();
$uitracker->import_mail(
$mailaddresses,
$this->sessionData['subject'],
$this->convertHTMLToText($this->sessionData['body']),
$this->sessionData['attachments'],
false, // date
$mail->getRaw()
);
}
/*
if ($_formData['to_calendar'] == 'on') {
$uical =& CreateObject('calendar.calendar_uiforms');
$uical->import_mail(
$mailaddresses,
$this->sessionData['subject'],
$this->convertHTMLToText($this->sessionData['body']),
$this->sessionData['attachments']
);
}
*/
if ($_formData['to_infolog'] == 'on' || $_formData['to_tracker'] == 'on' || $_formData['to_calendar'] == 'on' )
{
foreach(array('to_infolog','to_tracker','to_calendar') as $app_key)
{
if ($_formData[$app_key] == 'on')
{
$app_name = substr($app_key,3);
// Get registered hook data of the app called for integration
$hook = $GLOBALS['egw']->hooks->single(array('location'=> 'mail_import'),$app_name);
if(is_array($this->sessionData['attachments'])) {
// store mail / eml in temp. file to not have to download it from mail-server again
$eml = tempnam($GLOBALS['egw_info']['server']['temp_dir'],'mail_integrate');
$eml_fp = fopen($eml, 'w');
stream_copy_to_stream($mail->getRaw(), $eml_fp);
fclose($eml_fp);
// Open the app called for integration in a popup
// and store the mail raw data as egw_data, in order to
// be stored from registered app method later
egw_framework::popup(egw::link('/index.php', array(
'menuaction' => $hook['menuaction'],
'egw_data' => egw_link::set_data(null,'mail_integration::integrate',array(
$mailaddresses,
$this->sessionData['subject'],
$this->convertHTMLToText($this->sessionData['body']),
$this->sessionData['attachments'],
false, // date
$eml,
$_formData['serverID']),true),
'app' => $app_name
)),'_blank',$hook['popup']);
}
}
}
// only clean up temp-files, if we dont need them for mail_integration::integrate
elseif(is_array($this->sessionData['attachments']))
{
foreach($this->sessionData['attachments'] as $value) {
if (!empty($value['file']) && parse_url($value['file'],PHP_URL_SCHEME) != 'vfs') { // happens when forwarding mails
unlink($GLOBALS['egw_info']['server']['temp_dir'].'/'.$value['file']);
@ -3302,6 +3308,22 @@ class mail_compose
}
}
// Add groups
$group_options = array('account_type' => 'groups');
$groups = $GLOBALS['egw']->accounts->link_query($_searchString, $group_options);
foreach($groups as $g_id => $name)
{
$group = $GLOBALS['egw']->accounts->read($g_id);
if(!$group['account_email']) continue;
$completeMailString = trim($name) .' <'. trim($group['account_email']) .'>';
$results[] = array(
'id' => $completeMailString,
'label' => $completeMailString,
'name' => $name,
'title' => $group['account_email']
);
}
// Add up to 5 matching mailing lists
if($include_lists)
{

View File

@ -0,0 +1,288 @@
<?php
/**
* EGroupware - Mail - integration interface class
*
* @link http://www.egroupware.org
* @package mail
* @author Hadi Nategh [hn@stylite.de]
* @copyright (c) 2015 by Stylite AG <info-AT-stylite.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id:$
*/
/**
* Class cotains methods and functions
* to be used to integrate mail's message into other applications
*
*/
class mail_integration {
/**
* Public functions
* @var type
*/
var $public_functions = array(
'integrate' => true
);
/**
* Maximum number of line characters (-_+=~) allowed in a mail, to not stall the layout.
* Longer lines / biger number of these chars are truncated to that max. number or chars.
*
* @var int
*/
const MAX_LINE_CHARS = 40;
/**
* Gets requested mail information and sets them as data link
* -Execute registered hook method from the requested app for integration
* -with provided content from mail:
*
* -array( 'addresses' => array (
* 'email'=> stirng,
* 'personel' => string),
* 'attachments' => array (
* 'name' => string, // file name
* 'type' => string, // mime type
* 'egw_data'=> string, // hash md5 id of an stored attachment in session (attachment which is in IMAP server)
* // NOTE: the attachmet either have egw_data OR tmp_name (e.g. raw mail eml file stores in tmp)
* 'tmp_name' => string), // tmp dir path
* 'message' => string,
* 'date' => string,
* 'subject' => string,
* 'entry_id => string // Id of the app entry which mail content will append to
* )
*
* @param string $_to_emailAddress
* @param string $_subject mail subject
* @param string $_body mail message
* @param array $_attachments attachments
* @param string $_date
* @param string $_rawMail path to file with raw mail
* @param int $_icServerID mail profile id
* @throws egw_exception_assertion_failed
*/
public static function integrate ($_to_emailAddress=false,$_subject=false,$_body=false,$_attachments=false,$_date=false,$_rawMail=null,$_icServerID=null)
{
// App name which is called for integration
$app = isset($GLOBALS['egw_info']['user']['apps'][$_GET['app']])? $_GET['app'] : null;
// preset app entry id, selected by user from app_entry_dialog
$app_entry_id = $_GET['entry_id'];
// Set the date
if (!$_date)
{
$time = time();
$_date = egw_time::server2user($time->now,'ts');
}
// Integrate not yet saved mail
if (empty($_GET['rowid']) && $_to_emailAddress && $app)
{
$sessionLocation = 'mail';
$mailbox = base64_decode($_GET['mailbox']);
$GLOBALS['egw_info']['flags']['currentapp'] = $app;
if (!($GLOBALS['egw_info']['user']['preferences'][$sessionLocation]['saveAsOptions']==='text_only')&&is_array($_attachments))
{
// initialize mail open connection requirements
if (!isset($_icServerID)) $_icServerID =& egw_cache::getSession($sessionLocation,'activeProfileID');
$mo = mail_bo::getInstance(true,$_icServerID);
$mo->openConnection();
foreach ($_attachments as $attachment)
{
if (trim(strtoupper($attachment['type'])) == 'MESSAGE/RFC822' && !empty($attachment['uid']) && !empty($attachment['folder']))
{
$mo->reopen(($attachment['folder']?$attachment['folder']:$mailbox));
// get the message itself, and attach it, as we are able to display it in egw
// instead of fetching only the attachments attached files (as we did previously)
$message = $mo->getMessageRawBody($attachment['uid'],$attachment['partID'],($attachment['folder']?$attachment['folder']:$mailbox));
$headers = $mo->getMessageHeader($attachment['uid'],$attachment['partID'],true,false,($attachment['folder']?$attachment['folder']:$mailbox));
$subject = mail_bo::adaptSubjectForImport($headers['SUBJECT']);
$attachment_file =tempnam($GLOBALS['egw_info']['server']['temp_dir'],$GLOBALS['egw_info']['flags']['currentapp']."_");
$tmpfile = fopen($attachment_file,'w');
fwrite($tmpfile,$message);
fclose($tmpfile);
$size = filesize($attachment_file);
$attachments[] = array(
'name' => trim($subject).'.eml',
'mimeType' => 'message/rfc822',
'type' => 'message/rfc822',
'tmp_name' => $attachment_file,
'size' => $size,
);
}
else
{
if (!empty($attachment['folder']))
{
$is_winmail = $_GET['is_winmail'] ? $_GET['is_winmail'] : 0;
$mo->reopen($attachment['folder']);
$attachmentData = $mo->getAttachment($attachment['uid'],$attachment['partID'],$is_winmail);
$attachment['file'] =tempnam($GLOBALS['egw_info']['server']['temp_dir'],$GLOBALS['egw_info']['flags']['currentapp']."_");
$tmpfile = fopen($attachment['file'],'w');
fwrite($tmpfile,$attachmentData['attachment']);
fclose($tmpfile);
}
//make sure we search for our attached file in our configured temp_dir
if (isset($attachment['file']) && parse_url($attachment['file'],PHP_URL_SCHEME) != 'vfs' &&
file_exists($GLOBALS['egw_info']['server']['temp_dir'].SEP.basename($attachment['file'])))
{
$attachment['file'] = $GLOBALS['egw_info']['server']['temp_dir'].SEP.basename($attachment['file']);
}
$attachments[] = array(
'name' => $attachment['name'],
'mimeType' => $attachment['type'],
'type' => $attachment['type'],
'tmp_name' => $attachment['file'],
'size' => $attachment['size'],
);
}
}
$mo->closeConnection();
}
// this one adds the mail itself (as message/rfc822 (.eml) file) to the app as additional attachment
// this is done to have a simple archive functionality (ToDo: opening .eml in email module)
if ($GLOBALS['egw_info']['user']['preferences'][$sessionLocation]['saveAsOptions']==='add_raw' &&
$_rawMail && file_exists($_rawMail))
{
$subject = mail_bo::adaptSubjectForImport($_subject);
$attachments[] = array(
'name' => trim($subject).'.eml',
'mimeType' => 'message/rfc822',
'type' => 'message/rfc822',
'tmp_name' => $_rawMail,
'size' => filesize($_rawMail),
'add_raw' => true
);
}
$toaddr = array();
foreach(array('to','cc','bcc') as $x)
{
if (is_array($_to_emailAddress[$x]) && !empty($_to_emailAddress[$x]))
{
$toaddr = array_merge($toaddr,$_to_emailAddress[$x]);
}
}
$body_striped = strip_tags($_body); //we need to fix broken tags (or just stuff like "<800 USD/p" )
$body_decoded = htmlspecialchars_decode($body_striped,ENT_QUOTES);
$body = mail_bo::createHeaderInfoSection(array('FROM'=>$_to_emailAddress['from'],
'TO'=>(!empty($_to_emailAddress['to'])?implode(',',$_to_emailAddress['to']):null),
'CC'=>(!empty($_to_emailAddress['cc'])?implode(',',$_to_emailAddress['cc']):null),
'BCC'=>(!empty($_to_emailAddress['bcc'])?implode(',',$_to_emailAddress['bcc']):null),
'SUBJECT'=>$_subject,
'DATE'=>mail_bo::_strtotime($_date))).$body_decoded;
$mailcontent = array(
'mailaddress' => implode(',',$toaddr),
'subject' => $_subject,
'message' => $body,
'attachments' => $attachments,
'date' => $_date
);
}
// Integrate already saved mail with ID
else
{
// Initializing mail connection requirements
$hA = mail_ui::splitRowID($_GET['rowid']);
$sessionLocation = $hA['app']; // THIS is part of the row ID, we may use this for validation
// Check the mail app
if ($sessionLocation != 'mail') throw new egw_exception_assertion_failed(lang('Application mail expected but got: %1',$sessionLocation));
$uid = $hA['msgUID'];
$mailbox = $hA['folder'];
$icServerID = $hA['profileID'];
if ($uid && $mailbox)
{
if (!isset($icServerID)) $icServerID =& egw_cache::getSession($sessionLocation,'activeProfileID');
$mo = mail_bo::getInstance(true,$icServerID);
$mo->openConnection();
$mo->reopen($mailbox);
$mailcontent = mail_bo::get_mailcontent($mo,$uid,'',$mailbox,false,true,(!($GLOBALS['egw_info']['user']['preferences'][$sessionLocation]['saveAsOptions']==='text_only')));
// this one adds the mail itself (as message/rfc822 (.eml) file) to the app as additional attachment
// this is done to have a simple archive functionality (ToDo: opening .eml in email module)
if ($GLOBALS['egw_info']['user']['preferences'][$sessionLocation]['saveAsOptions']==='add_raw')
{
$message = $mo->getMessageRawBody($uid, '',$mailbox);
$headers = $mo->getMessageHeader($uid, '',true,false,$mailbox);
$subject = mail_bo::adaptSubjectForImport($headers['SUBJECT']);
$attachment_file =tempnam($GLOBALS['egw_info']['server']['temp_dir'],$GLOBALS['egw_info']['flags']['currentapp']."mail_integrate");
$tmpfile = fopen($attachment_file,'w');
fwrite($tmpfile,$message);
fclose($tmpfile);
$size = filesize($attachment_file);
$mailcontent['attachments'][] = array(
'name' => trim($subject).'.eml',
'mimeType' => 'message/rfc822',
'type' => 'message/rfc822',
'tmp_name' => $attachment_file,
'size' => $size,
'add_raw' => true
);
}
$mailcontent['date'] = strtotime($mailcontent['headers']['DATE']);
}
}
// Convert addresses to email and personal
$addresses = imap_rfc822_parse_adrlist($mailcontent['mailaddress'],'');
foreach ($addresses as $address)
{
$email = sprintf('%s@%s',trim($address->mailbox),trim($address->host));
$data_addresses[] = array (
'email' => $email,
'name' => !empty($address->personal) ? $address->personal : $email
);
}
// shorten long (> self::max_line_chars) lines of "line" chars (-_+=~) in mails
$data_message = preg_replace_callback(
'/[-_+=~\.]{'.self::MAX_LINE_CHARS.',}/m',
function($matches) {
return substr($matches[0],0,self::MAX_LINE_CHARS);
},
$mailcontent['message']
);
// Get attachments ready for integration as link
if (is_array($mailcontent['attachments']))
{
foreach($mailcontent['attachments'] as $key => $attachment)
{
$data_attachments[$key] = array(
'name' => $mailcontent['attachments'][$key]['name'],
'type' => $mailcontent['attachments'][$key]['type'],
'size' => $mailcontent['attachments'][$key]['size'],
'tmp_name' => $mailcontent['attachments'][$key]['tmp_name']
);
if ($uid && !$mailcontent['attachments'][$key]['add_raw'])
{
$data_attachments[$key]['egw_data'] = egw_link::set_data($mailcontent['attachments'][$key]['mimeType'],
'emailadmin_imapbase::getAttachmentAccount',array($icServerID, $mailbox, $uid, $attachment['partID'], $is_winmail, true),true);
}
unset($mailcontent['attachments'][$key]['add_raw']);
}
}
// Get the registered hook method of requested app for integration
$hook = $GLOBALS['egw']->hooks->single(array('location' => 'mail_import'),$app);
// Execute import mail with provided content
ExecMethod($hook['menuaction'],array (
'addresses' => $data_addresses,
'attachments' => $data_attachments,
'message' => $data_message,
'date' => $mailcontent['date'],
'subject' => $mailcontent['subject'],
'entry_id' => $app_entry_id
));
}
}

View File

@ -125,12 +125,12 @@ class mail_ui
if ($_GET["resetConnection"])
{
unset($_GET["resetConnection"]);
if (mail_bo::$debug) error_log(__METHOD__.__LINE__.' Connection Reset triggered:'.$connectionReset.' for Profile with ID:'.self::$icServerID);
if (mail_bo::$debug) error_log(__METHOD__.__LINE__.' Connection Reset triggered: for Profile with ID:'.self::$icServerID);
emailadmin_imapbase::unsetCachedObjects(self::$icServerID);
}
try {
$this->mail_bo = mail_bo::getInstance(true,self::$icServerID,$_validate=true, $_oldImapServerObject=false, $_reuseCache=true);
$this->mail_bo = mail_bo::getInstance(true,self::$icServerID, true, false, true);
if (mail_bo::$debug) error_log(__METHOD__.__LINE__.' Fetched IC Server:'.self::$icServerID.'/'.$this->mail_bo->profileID.':'.function_backtrace());
//error_log(__METHOD__.__LINE__.array2string($this->mail_bo->icServer));
@ -1224,8 +1224,7 @@ class mail_ui
'hint' => 'Save as InfoLog',
'icon' => 'infolog/navbar',
'group' => ++$group,
'onExecute' => 'javaScript:app.mail.mail_infolog',
'url' => 'menuaction=infolog.infolog_ui.import_mail',
'onExecute' => 'javaScript:app.mail.mail_integrate',
'popup' => egw_link::get_registry('infolog', 'add_popup'),
'allowOnMultiple' => false,
'toolbarDefault' => true
@ -1235,11 +1234,21 @@ class mail_ui
'hint' => 'Save as ticket',
'group' => $group,
'icon' => 'tracker/navbar',
'onExecute' => 'javaScript:app.mail.mail_tracker',
'url' => 'menuaction=tracker.tracker_ui.import_mail',
'onExecute' => 'javaScript:app.mail.mail_integrate',
'popup' => egw_link::get_registry('tracker', 'add_popup'),
'mail_import' => $GLOBALS['egw']->hooks->single(array('location' => 'mail_import'),'tracker'),
'allowOnMultiple' => false,
),
'calendar' => array(
'caption' => 'Calendar',
'hint' => 'Save as Calendar',
'icon' => 'calendar/navbar',
'group' => $group,
'onExecute' => 'javaScript:app.mail.mail_integrate',
'popup' => egw_link::get_registry('calendar', 'add_popup'),
'allowOnMultiple' => false,
'toolbarDefault' => true
),
'print' => array(
'caption' => 'Print',
'group' => ++$group,
@ -3239,7 +3248,6 @@ class mail_ui
$file = $content['uploadForImport'];
}
$destination = $content['FOLDER'][0];
$rememberServerID = $icServerID = $this->mail_bo->profileID;
if (stripos($destination,self::$delimiter)!==false) list($icServerID,$destination) = explode(self::$delimiter,$destination,2);
if ($icServerID && $icServerID != $this->mail_bo->profileID)
@ -3462,7 +3470,6 @@ class mail_ui
$folder = $uidA['folder']; // all messages in one set are supposed to be within the same folder
$messageID = $uidA['msgUID'];
$icServerID = $uidA['profileID'];
$rememberServerID = $this->mail_bo->profileID;
if ($icServerID && $icServerID != $this->mail_bo->profileID)
{
//error_log(__METHOD__.__LINE__.' change Profile to ->'.$icServerID);
@ -4693,7 +4700,7 @@ class mail_ui
//error_log(__METHOD__.__LINE__.$uID);
if ($_copyOrMove=='move')
{
$messageListForRefresh[] = self::generateRowID($sourceProfileID, $folderName, $uID, $_prependApp=false);
$messageListForRefresh[] = self::generateRowID($sourceProfileID, $_folderName, $uID, $_prependApp=false);
}
}
}

View File

@ -2565,16 +2565,23 @@ app.classes.mail = AppJS.extend(
},
/**
* Save message as InfoLog
* Integrate mail message into another app's entry
*
* @param _action
* @param _elems _elems[0].id is the row-id
*/
mail_infolog: function(_action, _elems)
mail_integrate: function(_action, _elems)
{
//define/preset w_h in case something fails
var reg = '750x580';
var w_h =reg.split('x');
var app = _action.id;
var w_h = ['750','580']; // define a default wxh if there's no popup size registered
var add_as_new = true;
if (typeof _action.data != 'undefined' )
{
if (typeof _action.data.popup != 'undefined') w_h = _action.data.popup.split('x');
if (typeof _action.data.mail_import != 'undefined') var mail_import_hook = _action.data.mail_import;
}
if (typeof _elems == 'undefined' || _elems.length==0)
{
@ -2591,78 +2598,73 @@ app.classes.mail = AppJS.extend(
_elems.push({id:this.mail_currentlyFocussed});
}
}
if (typeof _action.data.width == 'undefined' && typeof _action.data.height == 'undefined' && !(typeof _action.data.event == 'undefined' &&typeof _action.data.event.popup == 'undefined'))
{
if (_action.data.event.popup)
{
var app_registry = _action.data.event.popup;
}
else
{
var app_registry = egw.link_get_registry('infolog');//this.appname);
}
if (typeof app_registry['edit'] != 'undefined' && typeof app_registry['edit_popup'] != 'undefined' )
{
w_h =app_registry['edit_popup'].split('x');
}
}
}
var url = window.egw_webserverUrl+'/index.php?';
url += 'menuaction=infolog.infolog_ui.import_mail'; // todo compose for Draft folder
url += '&rowid='+_elems[0].id;
egw_openWindowCentered(url,'import_mail_'+_elems[0].id,(_action.data.width?_action.data.width:w_h[0]),(_action.data.height?_action.data.height:w_h[1]));
},
/**
* Save message as ticket
*
* @param _action _action.id is 'read', 'unread', 'flagged' or 'unflagged'
* @param _elems
*/
mail_tracker: function(_action, _elems)
{
//define/preset w_h in case something fails
var reg = '780x535';
var w_h =reg.split('x');
if (typeof _elems == 'undefined' || _elems.length==0)
var url = window.egw_webserverUrl+ '/index.php?menuaction=mail.mail_integration.integrate&rowid=' + _elems[0].id + '&app='+app;
/**
* Checks the application entry existance and offers user
* to select desire app id to append mail content into it,
* or add the mail content as a new app entry
*
* @param {string} _title select app entry title
* @param {string} _appName app to be integrated
* @param {string} _appCheckCallback registered mail_import hook method
* for check app entry existance
*/
check_app_entry = function (_title, _appName, _appCheckCallback)
{
if (this.et2.getArrayMgr("content").getEntry('mail_id'))
{
var _elems = [];
_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
}
if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
{
if (this.mail_currentlyFocussed)
var data = egw.dataGetUIDdata(_elems[0].id);
var subject = (data && typeof data.data != 'undefined')? data.data.subject : '';
egw.json(_appCheckCallback, subject,function(_entryId){
// if there's no entry saved already
// open dialog in order to select one
if (!_entryId)
{
var _elems = [];
_elems.push({id:this.mail_currentlyFocussed});
var buttons = [
{text: 'Append', id: 'append', image: 'check', default:true},
{text: 'Add as new', id: 'new', image: 'check'},
{text: 'Cancel', id: 'cancel', image: 'check'}
];
et2_createWidget("dialog",
{
callback: function(_buttons, _value)
{
if (_buttons == 'cancel') return;
if (_buttons == 'append' && _value)
{
url += '&entry_id=' + _value.id;
}
egw_openWindowCentered(url,'import_mail_'+_elems[0].id,w_h[0],w_h[1]);
},
title: egw.lang(_title),
buttons: buttons||et2_dialog.BUTTONS_OK_CANCEL,
value:{
content:{
appName:_appName // appName to search on its list later
}},
template: egw.webserverUrl+'/mail/templates/default/integration_to_entry_dialog.xet'
},et2_dialog._create_parent('mail'));
}
}
if (typeof _action.data.width == 'undefined' && typeof _action.data.height == 'undefined' && !(typeof _action.data.event == 'undefined' &&typeof _action.data.event.popup == 'undefined'))
{
if (_action.data.event.popup)
else // there is an entry saved related to this mail's subject
{
var app_registry = _action.data.event.popup;
egw_openWindowCentered(url,'import_mail_'+_elems[0].id,w_h[0],w_h[1]);
}
else
{
var app_registry = egw.link_get_registry('tracker');//this.appname);
}
if (typeof app_registry['add'] != 'undefined' && typeof app_registry['add_popup'] != 'undefined' )
{
w_h =app_registry['add_popup'].split('x');
}
}
},this,true,this).sendRequest();
}
//alert('mail_tracker('+_elems[0].id+')');
var url = window.egw_webserverUrl+'/index.php?';
url += 'menuaction=tracker.tracker_ui.import_mail'; // todo compose for Draft folder
url += '&rowid='+_elems[0].id;
egw_openWindowCentered(url,'import_tracker_'+_elems[0].id,(_action.data.width?_action.data.width:w_h[0]),(_action.data.height?_action.data.height:w_h[1]));
if (mail_import_hook && typeof mail_import_hook.app_entry_method != 'undefined')
{
check_app_entry('Select '+ app + ' entry', app, mail_import_hook.app_entry_method);
}
else
{
egw_openWindowCentered(url,'import_mail_'+_elems[0].id,w_h[0],w_h[1]);
}
},
/**
* mail_getFormData
*

View File

@ -373,6 +373,7 @@ saving of message %1 failed. destination folder %2 does not exist. mail de Speic
saving of message %1 succeeded. check folder %2. mail de Speichern der Nachricht %1 war erfolgreich. Prüfen Sie den Ziel Ordner %2
saving the rule failed: mail de Speichern der Regel ist fehlgeschlagen:
select all mail de Alle Auswählen
select an existing entry in order to append mail content to it mail de Bestehendes Ticket auswählen, zu dem die Mail als Kommentar hinzugefügt werden soll.
select file to attach to message mail de Wählen Sie die Dateien aus, die Sie an diese Nachricht anhängen möchten.
select file to import into folder mail de Wählen Sie ein E-Mail als Datei aus, damit Sie in ein Ordner importiert werden kann.
select file(s) from vfs mail de Dateien aus dem EGroupware Dateimanager anhängen.

View File

@ -373,6 +373,7 @@ saving of message %1 failed. destination folder %2 does not exist. mail en Savin
saving of message %1 succeeded. check folder %2. mail en Saving of message %1 succeeded. Check Folder %2.
saving the rule failed: mail en Saving the rule failed:
select all mail en Select all
select an existing entry in order to append mail content to it mail en Select an existing entry in order to append mail content to it
select file to attach to message mail en Select file to attach to message
select file to import into folder mail en Select file to import into Folder
select file(s) from vfs mail en Select file(s) from VFS

View File

@ -10,6 +10,7 @@
<file class="mail-compose_fileselector" statustext="Select file to attach to message" multiple='true' progress='attachments' onFinish="app.mail.uploadForCompose" onStart="app.mail.composeUploadStart" id="uploadForCompose" drop_target ="mail-compose"/>
<checkbox statustext="check to save as infolog on send" id="to_infolog" options="on,off"/>
<checkbox statustext="check to save as trackerentry on send" id="to_tracker" options="on,off"/>
<checkbox statustext="check to save as calendar event on send" id="to_calendar" options="on,off"/>
<checkbox statustext="check to recieve a notification when the message is read (note: not all clients support this and/or the reciever may not authorize the notification)" id="disposition" options="on,off"/>
<menulist>
<menupopup id="priority"/>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE overlay PUBLIC "-//Stylite AG//eTemplate 2//EN" "http://www.egroupware.org/etemplate2.dtd">
<!-- $Id$ -->
<overlay>
<template id="mail.integration_to_entry_dialog" template="" lang="" group="0" version="1.9.001">
<vbox width="100%">
<description value="Select an existing entry in order to append mail content to it"/>
<description/>
<link-entry id="id" only_app="@appName" class="et2_fullWidth"/>
</vbox>
</template>
</overlay>

View File

@ -112,6 +112,11 @@ class egw_link extends solink
*/
const VFS_APPNAME = 'file'; // pseudo-appname for own file-attachments in vfs, this is NOT the vfs-app
/**
* Appname used of files stored via egw_link::set_data()
*/
const DATA_APPNAME = 'egw-data';
/**
* appname used for linking existing files to VFS
*/
@ -188,9 +193,10 @@ class egw_link extends solink
static function init_static( )
{
// FireFox 36 can not display pdf with it's internal viewer in an iframe used by mobile theme/template for popups
if (html::$user_agent == 'firefox' && $GLOBALS['egw_info']['user']['preferences']['common']['theme'] == 'mobile')
// same is true for all mobile devices
if (html::$user_agent == 'firefox' && $GLOBALS['egw_info']['user']['preferences']['common']['theme'] == 'mobile' || html::$ua_mobile)
{
unset(self::$app_register['home']['mime']['application/pdf']['mime_popup']);
unset(self::$app_register['home']['mime']['application/pdf']);
}
// other apps can participate in the linking by implementing a search_link hook, which
// has to return an array in the format of an app_register entry
@ -307,13 +313,12 @@ class egw_link extends solink
* of not created item or $file-array if $app1 == self::VFS_APPNAME (see below).
* If $id==0 it will be set on return to an array with the links for the new item.
* @param string|array $app2 app of 2.linkend or array with links ($id2 not used)
* @param string $id2 ='' id of 2. item of $file-array if $app2 == self::VFS_APPNAME (see below)<br>
* $file array with informations about the file in format of the etemplate file-type<br>
* $file['name'] name of the file (no directory)<br>
* $file['type'] mine-type of the file<br>
* $file['tmp_name'] name of the uploaded file (incl. directory)<br>
* $file['path'] path of the file on the client computer<br>
* $file['ip'] of the client (path and ip in $file are only needed if u want a symlink (if possible))
* @param string $id2 ='' id of 2. item of $file-array if $app2 == self::VFS_APPNAME or self::DATA_APPNAME
* $file array with informations about the file in format of the etemplate file-type
* $file['name'] name of the file (no directory)
* $file['type'] mime-type of the file
* $file['tmp_name'] name of the uploaded file (incl. directory) for self::VFS_APPNAME or
* $file['egw_data'] id of egw_link::set_data() call for self::DATA_APPNAME
* @param string $remark ='' Remark to be saved with the link (defaults to '')
* @param int $owner =0 Owner of the link (defaults to user)
* @param int $lastmod =0 timestamp of last modification (defaults to now=time())
@ -346,22 +351,30 @@ class egw_link extends solink
self::link($app1, $id1, $link['app'], $link['id'], $link['remark'],$link['owner'],$link['lastmod']);
continue;
}
if ($link['app'] == self::VFS_APPNAME)
switch ($link['app'])
{
$link_id = self::attach_file($app1,$id1,$link['id'],$link['remark']);
}
else if ($link['app'] == self::VFS_LINK)
{
$link_id = self::link_file($app1,$id1, $link['id'],$link['remark']);
}
else
{
$link_id = solink::link($app1,$id1,$link['app'],$link['id'],
$link['remark'],$link['owner'],$link['lastmod']);
case self::DATA_APPNAME:
if (!($link['id']['tmp_name'] = self::get_data($link['id']['egw_data'], true)))
{
$link_id = false;
break;
}
// fall through
case self::VFS_APPNAME:
$link_id = self::attach_file($app1,$id1,$link['id'],$link['remark']);
break;
// notify both sides
if (!($no_notify&2)) self::notify('link',$link['app'],$link['id'],$app1,$id1,$link_id);
if (!($no_notify&1)) self::notify('link',$app1,$id1,$link['app'],$link['id'],$link_id);
case self::VFS_LINK:
$link_id = self::link_file($app1,$id1, $link['id'],$link['remark']);
break;
default:
$link_id = solink::link($app1,$id1,$link['app'],$link['id'],
$link['remark'],$link['owner'],$link['lastmod']);
// notify both sides
if (!($no_notify&2)) self::notify('link',$link['app'],$link['id'],$app1,$id1,$link_id);
if (!($no_notify&1)) self::notify('link',$app1,$id1,$link['app'],$link['id'],$link_id);
break;
}
}
return $link_id;
@ -421,7 +434,7 @@ class egw_link extends solink
*/
static function temp_link_id($app,$id)
{
return $app.':'.($app != self::VFS_APPNAME && $app != self::VFS_LINK ? $id : $id['name']);
return $app.':'.(!in_array($app, array(self::VFS_APPNAME,self::VFS_LINK, self::DATA_APPNAME)) ? $id : $id['name']);
}
/**
@ -1178,9 +1191,7 @@ class egw_link extends solink
* @param array $file informations about the file in format of the etemplate file-type
* $file['name'] name of the file (no directory)
* $file['type'] mine-type of the file
* $file['tmp_name'] name of the uploaded file (incl. directory)
* $file['path'] path of the file on the client computer
* $file['ip'] of the client (path and ip are only needed if u want a symlink (if possible))
* $file['tmp_name'] name of the uploaded file (incl. directory) or resource of opened file
* @param string $comment ='' comment to add to the link
* @return int negative id of egw_sqlfs table as negative link-id's are for vfs attachments
*/
@ -1552,16 +1563,18 @@ class egw_link extends solink
* @param string $mime_type
* @param string $method
* @param array $params
* @param boolean $ignore_mime =false true: return id, even if nothing registered for given mime-type
* @return string|null md5 hash of stored data of server-side supported mime-type or null otherwise
*/
public static function set_data($mime_type, $method, array $params)
public static function set_data($mime_type, $method, array $params, $ignore_mime=false)
{
if (!($info = self::get_mime_info($mime_type)) || empty($info['mime_data']))
if (!$ignore_mime && (!($info = self::get_mime_info($mime_type)) || empty($info['mime_data'])))
{
return null;
}
array_unshift($params, $method);
$id = md5(json_encode($params));
$id = md5(serialize($params));
//error_log(__METHOD__."('$mime_type', '$method', ...) params=".array2string($params)." --> json=".array2string(serialize($params)).' --> id='.array2string($id));
egw_cache::setSession(__CLASS__, $id, $params);
return $id;
}
@ -1584,6 +1597,8 @@ class egw_link extends solink
}
$ret = call_user_func_array('ExecMethod2', $data);
if (is_resource($ret)) fseek($ret, 0);
if ($return_resource != is_resource($ret))
{
if ($return_resource && ($fp = fopen('php://temp', 'w')))
@ -1596,7 +1611,6 @@ class egw_link extends solink
{
$fp = $ret;
$ret = '';
fseek($fp, 0);
while(!feof($fp))
{
$ret .= fread($fp, 8192);

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB