WIP of mail integration

-Centralize mail functionality of mail message integration in mail module
-Some clean up of mail_import in infolog and tracker apps
-Use hook registery in order of an app uses mail integration services
-Implement mail import into calendar
This commit is contained in:
Hadi Nategh 2015-04-15 11:23:59 +00:00
parent ef40fa8ae7
commit b7c6be226d
9 changed files with 128 additions and 277 deletions

View File

@ -856,6 +856,16 @@ END:VALARM';
unset($data); // not used, but in function signature for hooks unset($data); // not used, but in function signature for hooks
return true; 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 'calendar.calendar_uiforms.mail_import';
}
} }
// Not part of the class, since config hooks are still using the old style // Not part of the class, since config hooks are still using the old style

View File

@ -2562,4 +2562,63 @@ class calendar_uiforms extends calendar_ui
} }
} }
} }
/**
* imports a mail as Calendar
*
* @param array $mailContent mail content
* @return array
*/
function mail_import($mailContent)
{
if (is_array($mailContent))
{
$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)
{
$participants []= array (
'app' => 'email',
'uid' => 'e'.$address['email'],
'status' => 'U',
'old_status' => 'U'
);
}
// Prepare calendar event draft
$event = array(
'title' => $mailContent['subject'],
'description' => $mailContent['message'],
'participants' => $participants,
'link_to' => array(
'to_app' => 'calendar',
'to_id' => 0,
),
);
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
{
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']['export_limit'] = 'calendar_hooks::getAppExportLimit';
$setup_info['calendar']['hooks']['acl_rights'] = 'calendar_hooks::acl_rights'; $setup_info['calendar']['hooks']['acl_rights'] = 'calendar_hooks::acl_rights';
$setup_info['calendar']['hooks']['categories'] = 'calendar_hooks::categories'; $setup_info['calendar']['hooks']['categories'] = 'calendar_hooks::categories';
$setup_info['calendar']['hooks']['mail_import'] = 'calendar_hooks::mail_import';
/* Dependencies for this app to work */ /* Dependencies for this app to work */
$setup_info['calendar']['depends'][] = array( $setup_info['calendar']['depends'][] = array(

View File

@ -1131,33 +1131,29 @@ class infolog_bo
* *
* @author Cornelius Weiss <nelius@cwtech.de> * @author Cornelius Weiss <nelius@cwtech.de>
* @todo search if infolog with from and subject allready exists ->appned body & inform user * @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 $_subject
* @param string $_message * @param string $_message
* @param array $_attachments * @param array $_attachments
* @param string $_date * @param string $_date
* @return array $content array for uiinfolog * @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($_addresses as $address)
foreach ((array)$address_array as $address)
{ {
$email[] = $emailadr = sprintf('%s@%s', $names[] = $address['name'];
trim($address->mailbox), $emails[] =$address['email'];
trim($address->host));
$name[] = !empty($address->personal) ? $address->personal : $emailadr;
} }
// 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'; $type = isset($this->enums['type']['email']) ? 'email' : 'note';
$status = isset($this->status['defaults'][$type]) ? $this->status['defaults'][$type] : 'done'; $status = isset($this->status['defaults'][$type]) ? $this->status['defaults'][$type] : 'done';
$info = array( $info = array(
'info_id' => 0, 'info_id' => 0,
'info_type' => $type, 'info_type' => $type,
'info_from' => implode(', ',$name), 'info_from' => implode(', ',$names),
'info_addr' => implode(', ',$email), 'info_addr' => implode(', ',$emails),
'info_subject' => $_subject, 'info_subject' => $_subject,
'info_des' => $_message, 'info_des' => $_message,
'info_startdate' => egw_time::server2user($_date), 'info_startdate' => egw_time::server2user($_date),
@ -1174,7 +1170,7 @@ class infolog_bo
// find the addressbookentry to link with // find the addressbookentry to link with
$addressbook = new addressbook_bo(); $addressbook = new addressbook_bo();
$contacts = array(); $contacts = array();
foreach ($email as $mailadr) foreach ($emails as $mailadr)
{ {
$contacts = array_merge($contacts,(array)$addressbook->search( $contacts = array_merge($contacts,(array)$addressbook->search(
array( array(
@ -1202,14 +1198,9 @@ class infolog_bo
{ {
foreach ($_attachments as $attachment) foreach ($_attachments as $attachment)
{ {
$is_vfs = false; if($attachment['egw_data'])
if (parse_url($attachment['tmp_name'],PHP_URL_SCHEME) == 'vfs' && egw_vfs::is_readable($attachment['tmp_name']))
{ {
$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)
{
egw_link::link('infolog',$info['link_to']['to_id'],'file',$attachment);
} }
} }
} }

View File

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

View File

@ -23,7 +23,6 @@ class infolog_ui
'admin' => True, 'admin' => True,
'hook_view' => True, 'hook_view' => True,
'writeLangFile' => True, 'writeLangFile' => True,
'import_mail' => True,
); );
/** /**
* reference to the infolog preferences of the user * reference to the infolog preferences of the user
@ -2487,185 +2486,17 @@ class infolog_ui
/** /**
* imports a mail as infolog * 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> * @data string $_data registered hook data
* @param string $_to_emailAddress * @return array
* @param string $_subject
* @param string $_body
* @param array $_attachments
* @param string $_date
* @param resource $_rawMail
*/ */
function import_mail($_to_emailAddress=false,$_subject=false,$_body=false,$_attachments=false,$_date=false,$_rawMail=null) function mail_import($mailContent)
{ {
$uid = $_GET['uid']; $this->edit($this->bo->import_mail($mailContent['addresses'],
$partid = $_GET['part']; $mailContent['subject'],
$mailbox = base64_decode($_GET['mailbox']); $mailContent['message'],
$mailClass = 'mail_bo'; $mailContent['attachments'],
$sessionLocation = 'mail'; $mailContent['date']));
// if rowid is set, we are called from new mail module.
if (method_exists('mail_ui','splitRowID') && isset($_GET['rowid']) && !empty($_GET['rowid']))
{
// 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';
}
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!'));
} }
/** /**

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']['pm_custom_app_icons'] = 'infolog.infolog_bo.pm_icons';
$setup_info['infolog']['hooks']['timesheet_set'] = 'infolog.infolog_ui.timesheet_set'; $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']['calendar_set'] = 'infolog.infolog_ui.calendar_set';
$setup_info['infolog']['hooks']['mail_import'] = 'infolog_hooks::mail_import';
/* Dependencies for this app to work */ /* Dependencies for this app to work */
$setup_info['infolog']['depends'][] = array( $setup_info['infolog']['depends'][] = array(

View File

@ -1237,8 +1237,7 @@ class mail_ui
'hint' => 'Save as InfoLog', 'hint' => 'Save as InfoLog',
'icon' => 'infolog/navbar', 'icon' => 'infolog/navbar',
'group' => ++$group, 'group' => ++$group,
'onExecute' => 'javaScript:app.mail.mail_infolog', 'onExecute' => 'javaScript:app.mail.mail_integrate',
'url' => 'menuaction=infolog.infolog_ui.import_mail',
'popup' => egw_link::get_registry('infolog', 'add_popup'), 'popup' => egw_link::get_registry('infolog', 'add_popup'),
'allowOnMultiple' => false, 'allowOnMultiple' => false,
'toolbarDefault' => true 'toolbarDefault' => true
@ -1248,11 +1247,20 @@ class mail_ui
'hint' => 'Save as ticket', 'hint' => 'Save as ticket',
'group' => $group, 'group' => $group,
'icon' => 'tracker/navbar', 'icon' => 'tracker/navbar',
'onExecute' => 'javaScript:app.mail.mail_tracker', 'onExecute' => 'javaScript:app.mail.mail_integrate',
'url' => 'menuaction=tracker.tracker_ui.import_mail',
'popup' => egw_link::get_registry('tracker', 'add_popup'), 'popup' => egw_link::get_registry('tracker', 'add_popup'),
'allowOnMultiple' => false, '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( 'print' => array(
'caption' => 'Print', 'caption' => 'Print',
'group' => ++$group, 'group' => ++$group,

View File

@ -2616,16 +2616,23 @@ app.classes.mail = AppJS.extend(
}, },
/** /**
* Save message as InfoLog * Integrate mail message into another app's entry
* *
* @param _action * @param _action
* @param _elems _elems[0].id is the row-id * @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 app = _action.id;
var reg = '750x580';
var w_h =reg.split('x'); if (typeof _action.data != 'undefined' && typeof _action.data.popup != 'undefined')
{
w_h = _action.data.popup.split('x');
}
else // define a default wxh if there's no popup size registered
{
var w_h = ['750','580'];
}
if (typeof _elems == 'undefined' || _elems.length==0) if (typeof _elems == 'undefined' || _elems.length==0)
{ {
@ -2642,78 +2649,11 @@ app.classes.mail = AppJS.extend(
_elems.push({id:this.mail_currentlyFocussed}); _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?'; var url = window.egw_webserverUrl+ '/index.php?menuaction=mail.mail_integration.integrate&rowid=' + _elems[0].id + '&app='+app;
url += 'menuaction=infolog.infolog_ui.import_mail'; // todo compose for Draft folder egw_openWindowCentered(url,'import_mail_'+_elems[0].id,w_h[0],w_h[1]);
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)
{
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 _elems = [];
_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('tracker');//this.appname);
}
if (typeof app_registry['add'] != 'undefined' && typeof app_registry['add_popup'] != 'undefined' )
{
w_h =app_registry['add_popup'].split('x');
}
}
}
//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]));
},
/** /**
* mail_getFormData * mail_getFormData
* *