diff --git a/calendar/inc/class.calendar_hooks.inc.php b/calendar/inc/class.calendar_hooks.inc.php index ce4a21a17c..d9fb4acbb6 100644 --- a/calendar/inc/class.calendar_hooks.inc.php +++ b/calendar/inc/class.calendar_hooks.inc.php @@ -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'; } } -} +} \ No newline at end of file diff --git a/calendar/inc/class.calendar_uiforms.inc.php b/calendar/inc/class.calendar_uiforms.inc.php index b394568555..6a50c67d44 100644 --- a/calendar/inc/class.calendar_uiforms.inc.php +++ b/calendar/inc/class.calendar_uiforms.inc.php @@ -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); + } } diff --git a/calendar/setup/setup.inc.php b/calendar/setup/setup.inc.php index 3dfa9ecbef..8c8fe6bdaa 100755 --- a/calendar/setup/setup.inc.php +++ b/calendar/setup/setup.inc.php @@ -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( diff --git a/emailadmin/inc/class.emailadmin_imapbase.inc.php b/emailadmin/inc/class.emailadmin_imapbase.inc.php index a9fe9f2060..086f83fff5 100644 --- a/emailadmin/inc/class.emailadmin_imapbase.inc.php +++ b/emailadmin/inc/class.emailadmin_imapbase.inc.php @@ -166,13 +166,13 @@ class emailadmin_imapbase /** * Singleton for emailadmin_imapbase * - * @param boolean $_restoreSession=true - * @param int $_profileID=0 - * @param boolean $_validate=true - flag wether the profileid should be validated or not, if validation is true, you may receive a profile + * @param boolean $_restoreSession = true + * @param int $_profileID = 0 + * @param boolean $_validate = true - flag wether the profileid should be validated or not, if validation is true, you may receive a profile * not matching the input profileID, if we can not find a profile matching the given ID * @param mixed boolean/object $_icServerObject - if object, return instance with object set as icServer * immediately, if boolean === true use oldImapServer in constructor - * @param boolean $_reuseCache=null if null it is set to the value of $_restoreSession + * @param boolean $_reuseCache = null if null it is set to the value of $_restoreSession * @return emailadmin_imapbase */ public static function getInstance($_restoreSession=true, &$_profileID=0, $_validate=true, $_oldImapServerObject=false, $_reuseCache=null) @@ -272,8 +272,8 @@ class emailadmin_imapbase /** * store given ProfileID to Session and pref * - * @param int $_profileID=0 - * @param boolean $_testConnection=0 + * @param int $_profileID = 0 + * @param boolean $_testConnection = 0 * @return mixed $_profileID or false on failed ConnectionTest */ public static function storeActiveProfileIDToPref($_icServerObject, $_profileID=0, $_testConnection=true) @@ -290,7 +290,7 @@ class emailadmin_imapbase { try { - $mailbox = $_icServerObject->getCurrentMailbox(); + $_icServerObject->getCurrentMailbox(); } catch (Exception $e) { @@ -318,7 +318,7 @@ class emailadmin_imapbase * - non-empty imap-host * - non-empty imap-username * - * @param int $_acc_id=0 + * @param int $_acc_id = 0 * @return int validated acc_id -> either acc_id given, or first valid one */ public static function validateProfileID($_acc_id=0) @@ -356,11 +356,11 @@ class emailadmin_imapbase /** * Private constructor, use emailadmin_imapbase::getInstance() instead * - * @param string $_displayCharset='utf-8' - * @param boolean $_restoreSession=true - * @param int $_profileID=0 if not nummeric, we assume we only want an empty class object - * @param boolean $_oldImapServerObject=false - * @param boolean $_reuseCache=null if null it is set to the value of $_restoreSession + * @param string $_displayCharset = 'utf-8' + * @param boolean $_restoreSession = true + * @param int $_profileID = 0 if not nummeric, we assume we only want an empty class object + * @param boolean $_oldImapServerObject = false + * @param boolean $_reuseCache = null if null it is set to the value of $_restoreSession */ private function __construct($_displayCharset='utf-8',$_restoreSession=true, $_profileID=0, $_oldImapServerObject=false, $_reuseCache=null) { @@ -445,7 +445,7 @@ class emailadmin_imapbase function restoreSessionData() { $this->sessionData = array();//egw_cache::getCache(egw_cache::SESSION,'mail','session_data',$callback=null,$callback_params=array(),$expiration=60*60*1); - self::$activeFolderCache = egw_cache::getCache(egw_cache::INSTANCE,'email','activeMailbox'.trim($GLOBALS['egw_info']['user']['account_id']),$callback=null,$callback_params=array(),$expiration=60*60*10); + self::$activeFolderCache = egw_cache::getCache(egw_cache::INSTANCE,'email','activeMailbox'.trim($GLOBALS['egw_info']['user']['account_id']),null,array(),60*60*10); if (!empty(self::$activeFolderCache[$this->profileID])) $this->sessionData['mailbox'] = self::$activeFolderCache[$this->profileID]; } @@ -458,7 +458,7 @@ class emailadmin_imapbase if (!empty($this->sessionData['mailbox'])) self::$activeFolderCache[$this->profileID]=$this->sessionData['mailbox']; if (isset(self::$activeFolderCache) && is_array(self::$activeFolderCache)) { - egw_cache::setCache(egw_cache::INSTANCE,'email','activeMailbox'.trim($GLOBALS['egw_info']['user']['account_id']),self::$activeFolderCache, $expiration=60*60*10); + egw_cache::setCache(egw_cache::INSTANCE,'email','activeMailbox'.trim($GLOBALS['egw_info']['user']['account_id']),self::$activeFolderCache, 60*60*10); } } @@ -471,7 +471,7 @@ class emailadmin_imapbase * 4) HierarchyDelimiter * 5) VacationNotice * - * @param int $_profileID=null default profile of user as returned by getUserDefaultProfileID + * @param int $_profileID = null default profile of user as returned by getUserDefaultProfileID * @return void */ static function unsetCachedObjects($_profileID=null) @@ -522,10 +522,10 @@ class emailadmin_imapbase $_profileID = null; self::resetConnectionErrorCache($_profileID,$account_id); self::resetFolderObjectCache($_profileID,$account_id); - egw_cache::setCache(egw_cache::INSTANCE,'email','rawHeadersCache'.trim($account_id),array(), $expiration=60*60*1); - egw_cache::setCache(egw_cache::INSTANCE,'email','HierarchyDelimiter'.trim($account_id),array(), $expiration=60*60*24*5); - egw_cache::setCache(egw_cache::INSTANCE,'email','eMailListContainsDeletedMessages'.trim($account_id),array(), $expiration=60*60*1); - egw_cache::setCache(egw_cache::INSTANCE,'email','vacationNotice'.trim($account_id),array(), $expiration=60*60*24*1); + egw_cache::setCache(egw_cache::INSTANCE,'email','rawHeadersCache'.trim($account_id),array(), 60*60*1); + egw_cache::setCache(egw_cache::INSTANCE,'email','HierarchyDelimiter'.trim($account_id),array(), 60*60*24*5); + egw_cache::setCache(egw_cache::INSTANCE,'email','eMailListContainsDeletedMessages'.trim($account_id),array(), 60*60*1); + egw_cache::setCache(egw_cache::INSTANCE,'email','vacationNotice'.trim($account_id),array(), 60*60*24*1); } } } @@ -549,7 +549,6 @@ class emailadmin_imapbase } if (is_null($_ImapServerId)) { - $buff = array(); $isConError = array(); $waitOnFailure = array(); } @@ -560,14 +559,14 @@ class emailadmin_imapbase { unset($isConError[$_ImapServerId]); } - $waitOnFailure = egw_cache::getCache(egw_cache::INSTANCE,'email','ActiveSyncWaitOnFailure'.trim($account_id),$callback=null,$callback_params=array(),$expiration=60*60*2); + $waitOnFailure = egw_cache::getCache(egw_cache::INSTANCE,'email','ActiveSyncWaitOnFailure'.trim($account_id),null,array(),60*60*2); if (isset($waitOnFailure[$_ImapServerId])) { unset($waitOnFailure[$_ImapServerId]); } } - egw_cache::setCache(egw_cache::INSTANCE,'email','icServerSIEVE_connectionError'.trim($account_id),$isConError,$expiration=60*15); - egw_cache::setCache(egw_cache::INSTANCE,'email','ActiveSyncWaitOnFailure'.trim($account_id),$waitOnFailure,$expiration=60*60*2); + egw_cache::setCache(egw_cache::INSTANCE,'email','icServerSIEVE_connectionError'.trim($account_id),$isConError,60*15); + egw_cache::setCache(egw_cache::INSTANCE,'email','ActiveSyncWaitOnFailure'.trim($account_id),$waitOnFailure,60*60*2); } /** @@ -591,12 +590,12 @@ class emailadmin_imapbase } else { - $folders2return = egw_cache::getCache(egw_cache::INSTANCE,'email','folderObjects'.trim($account_id),$callback=null,$callback_params=array(),$expiration=60*60*1); + $folders2return = egw_cache::getCache(egw_cache::INSTANCE,'email','folderObjects'.trim($account_id),null,array(),60*60*1); if (!empty($folders2return) && isset($folders2return[$_ImapServerId])) { unset($folders2return[$_ImapServerId]); } - $folderInfo = egw_cache::getCache(egw_cache::INSTANCE,'email','icServerFolderExistsInfo'.trim($account_id),null,array(),$expiration=60*60*5); + $folderInfo = egw_cache::getCache(egw_cache::INSTANCE,'email','icServerFolderExistsInfo'.trim($account_id),null,array(),60*60*5); if (!empty($folderInfo) && isset($folderInfo[$_ImapServerId])) { unset($folderInfo[$_ImapServerId]); @@ -608,23 +607,23 @@ class emailadmin_imapbase unset($lastFolderUsedForMove[$_ImapServerId]); } */ - $folderBasicInfo = egw_cache::getCache(egw_cache::INSTANCE,'email','folderBasicInfo'.trim($account_id),null,array(),$expiration=60*60*1); + $folderBasicInfo = egw_cache::getCache(egw_cache::INSTANCE,'email','folderBasicInfo'.trim($account_id),null,array(),60*60*1); if (!empty($folderBasicInfo) && isset($folderBasicInfo[$_ImapServerId])) { unset($folderBasicInfo[$_ImapServerId]); } - $_specialUseFolders = egw_cache::getCache(egw_cache::INSTANCE,'email','specialUseFolders'.trim($account_id),null,array(),$expiration=60*60*12); + $_specialUseFolders = egw_cache::getCache(egw_cache::INSTANCE,'email','specialUseFolders'.trim($account_id),null,array(),60*60*12); if (!empty($_specialUseFolders) && isset($_specialUseFolders[$_ImapServerId])) { unset($_specialUseFolders[$_ImapServerId]); self::$specialUseFolders=null; } } - egw_cache::setCache(egw_cache::INSTANCE,'email','folderObjects'.trim($account_id),$folders2return, $expiration=60*60*1); - egw_cache::setCache(egw_cache::INSTANCE,'email','icServerFolderExistsInfo'.trim($account_id),$folderInfo,$expiration=60*60*5); + egw_cache::setCache(egw_cache::INSTANCE,'email','folderObjects'.trim($account_id),$folders2return, 60*60*1); + egw_cache::setCache(egw_cache::INSTANCE,'email','icServerFolderExistsInfo'.trim($account_id),$folderInfo,60*60*5); //egw_cache::setCache(egw_cache::INSTANCE,'email','lastFolderUsedForMove'.trim($account_id),$lastFolderUsedForMove,$expiration=60*60*1); - egw_cache::setCache(egw_cache::INSTANCE,'email','folderBasicInfo'.trim($account_id),$folderBasicInfo,$expiration=60*60*1); - egw_cache::setCache(egw_cache::INSTANCE,'email','specialUseFolders'.trim($account_id),$_specialUseFolders,$expiration=60*60*12); + egw_cache::setCache(egw_cache::INSTANCE,'email','folderBasicInfo'.trim($account_id),$folderBasicInfo,60*60*1); + egw_cache::setCache(egw_cache::INSTANCE,'email','specialUseFolders'.trim($account_id),$_specialUseFolders,60*60*12); } /** @@ -663,7 +662,7 @@ class emailadmin_imapbase /** * getAllIdentities - function to gather the identities connected to the current user - * @param string/int $_accountToSearch; null; if set search accounts for user specified + * @param string/int $_accountToSearch = null if set search accounts for user specified * @param boolean $resolve_placeholders wether or not resolve possible placeholders in identities * @return array - array(email=>realname) */ @@ -726,7 +725,7 @@ class emailadmin_imapbase */ function getDefaultIdentity() { // retrieve the signature accociated with the identity - $id = $this->getIdentitiesWithAccounts($_accountData); + $id = $this->getIdentitiesWithAccounts($_accountData=array()); $acc = emailadmin_account::read($this->profileID); $accountDataIT = ($_accountData[$this->profileID]?$acc->identities($this->profileID,false,'ident_id'):$acc->identities($_accountData[$id],false,'ident_id')); foreach($accountDataIT as $it => $accountData) @@ -745,7 +744,7 @@ class emailadmin_imapbase { // account select box $selectedID = $this->profileID; - $allAccountData = emailadmin_account::search($only_current_user=true, $just_name=false, $order_by=null); + $allAccountData = emailadmin_account::search($only_current_user=true, false, null); if ($allAccountData) { $rememberFirst=$selectedFound=null; foreach ($allAccountData as $tmpkey => $icServers) @@ -808,7 +807,7 @@ class emailadmin_imapbase /** * reopens a connection for the active Server ($this->icServer), and selects the folder given * - * @param string $_foldername, folder to open/select + * @param string $_foldername folder to open/select * @return void */ function reopen($_foldername) @@ -835,8 +834,8 @@ class emailadmin_imapbase /** * openConnection * - * @param int $_icServerID - * @param boolean $_adminConnection + * @param int $_icServerID = 0 + * @param boolean $_adminConnection = false * @throws Horde_Imap_Client_Exception on connection error or authentication failure * @throws InvalidArgumentException on missing credentials */ @@ -939,7 +938,6 @@ class emailadmin_imapbase { foreach ($singleNameSpaceArray as $k => $singleNameSpace) { - $prefix_present = false; $_foldersNameSpace = array(); if($type == 'personal' && $singleNameSpace['name'] == '#mh/' && ($this->folderExists('Mail')||$this->folderExists('INBOX'))) { @@ -975,7 +973,7 @@ class emailadmin_imapbase */ function getFolderPrefixFromNamespace($nameSpace, $folderName) { - foreach($nameSpace as $k => $singleNameSpace) + foreach($nameSpace as &$singleNameSpace) { //if (substr($singleNameSpace['prefix'],0,strlen($folderName))==$folderName) return $singleNameSpace['prefix']; if (substr($folderName,0,strlen($singleNameSpace['prefix']))==$singleNameSpace['prefix']) return $singleNameSpace['prefix']; @@ -991,7 +989,7 @@ class emailadmin_imapbase function getHierarchyDelimiter($_useCache=true) { static $HierarchyDelimiter; - if (is_null($HierarchyDelimiter)) $HierarchyDelimiter = egw_cache::getCache(egw_cache::INSTANCE,'email','HierarchyDelimiter'.trim($GLOBALS['egw_info']['user']['account_id']),$callback=null,$callback_params=array(),$expiration=60*60*24*5); + if (is_null($HierarchyDelimiter)) $HierarchyDelimiter = egw_cache::getCache(egw_cache::INSTANCE,'email','HierarchyDelimiter'.trim($GLOBALS['egw_info']['user']['account_id']),null,array(),60*60*24*5); if ($_useCache===false) unset($HierarchyDelimiter[$this->icServer->ImapServerId]); if (isset($HierarchyDelimiter[$this->icServer->ImapServerId])&&!empty($HierarchyDelimiter[$this->icServer->ImapServerId])) { @@ -1007,7 +1005,7 @@ class emailadmin_imapbase { $HierarchyDelimiter[$this->icServer->ImapServerId] = '/'; } - egw_cache::setCache(egw_cache::INSTANCE,'email','HierarchyDelimiter'.trim($GLOBALS['egw_info']['user']['account_id']),$HierarchyDelimiter, $expiration=60*60*24*5); + egw_cache::setCache(egw_cache::INSTANCE,'email','HierarchyDelimiter'.trim($GLOBALS['egw_info']['user']['account_id']),$HierarchyDelimiter, 60*60*24*5); return $HierarchyDelimiter[$this->icServer->ImapServerId]; } @@ -1020,7 +1018,7 @@ class emailadmin_imapbase { //error_log(__METHOD__.' ('.__LINE__.') '.':'.$this->icServer->ImapServerId.' Connected:'.$this->icServer->_connected); static $_specialUseFolders; - if (is_null($_specialUseFolders)||empty($_specialUseFolders)) $_specialUseFolders = egw_cache::getCache(egw_cache::INSTANCE,'email','specialUseFolders'.trim($GLOBALS['egw_info']['user']['account_id']),$callback=null,$callback_params=array(),$expiration=60*60*24*5); + if (is_null($_specialUseFolders)||empty($_specialUseFolders)) $_specialUseFolders = egw_cache::getCache(egw_cache::INSTANCE,'email','specialUseFolders'.trim($GLOBALS['egw_info']['user']['account_id']),null,array(),60*60*24*5); //error_log(__METHOD__.' ('.__LINE__.') '.array2string($this->icServer->acc_folder_trash)); //error_log(__METHOD__.' ('.__LINE__.') '.array2string($this->icServer->acc_folder_sent)); //error_log(__METHOD__.' ('.__LINE__.') '.array2string($this->icServer->acc_folder_draft)); @@ -1040,7 +1038,7 @@ class emailadmin_imapbase $_specialUseFolders[$this->icServer->ImapServerId][$this->icServer->acc_folder_junk]='Junk'; //error_log(__METHOD__.' ('.__LINE__.') '.array2string($_specialUseFolders));//.'<->'.array2string($this->icServer)); self::$specialUseFolders = $_specialUseFolders[$this->icServer->ImapServerId]; - egw_cache::setCache(egw_cache::INSTANCE,'email','specialUseFolders'.trim($GLOBALS['egw_info']['user']['account_id']),$_specialUseFolders, $expiration=60*60*24*5); + egw_cache::setCache(egw_cache::INSTANCE,'email','specialUseFolders'.trim($GLOBALS['egw_info']['user']['account_id']),$_specialUseFolders, 60*60*24*5); return $_specialUseFolders[$this->icServer->ImapServerId]; } @@ -1210,7 +1208,7 @@ class emailadmin_imapbase if (!empty($nameSpace[$this->profileID])) { $nsNoPersonal=array(); - foreach($nameSpace[$this->profileID] as $k => $ns) + foreach($nameSpace[$this->profileID] as &$ns) { if ($ns['type']!='personal') $nsNoPersonal[]=$ns; } @@ -1249,7 +1247,7 @@ class emailadmin_imapbase // we filter for the combined status of unseen and undeleted, as this is what we show in list try { - $sortResult = $this->getSortedList($_folderName, $_sort=0, $_reverse=1, $_filter=array('status'=>array('UNSEEN','UNDELETED')),$byUid=true,false); + $sortResult = $this->getSortedList($_folderName, $_sort=0, 1, array('status'=>array('UNSEEN','UNDELETED')),true,false); $retValue['unseen'] = $sortResult['count']; } catch (Exception $ee) @@ -1277,8 +1275,8 @@ class emailadmin_imapbase * @param array $_sort sort by criteria * @param boolean $_reverse reverse sorting of the result array (may be switched, as it is passed to getSortedList by reference) * @param array $_filter filter to apply to getSortedList - * @param mixed $_thisUIDOnly=null, if given fetch the headers of this uid only (either one, or array of uids) - * @param boolean $_cacheResult=true try touse the cache of getSortedList + * @param mixed $_thisUIDOnly = null, if given fetch the headers of this uid only (either one, or array of uids) + * @param boolean $_cacheResult = true try touse the cache of getSortedList * @return array result as array(header=>array,total=>int,first=>int,last=>int) */ function getHeaders($_folderName, $_startMessage, $_numberOfMessages, $_sort, $_reverse, $_filter, $_thisUIDOnly=null, $_cacheResult=true) @@ -1300,8 +1298,8 @@ class emailadmin_imapbase { // this will not work we must calculate the range we want to retieve as e.g.: 0:20 retirieves the first 20 mails and sorts them // if sort capability is applied to the range fetched, not sort first and fetch the range afterwards - $start = $_startMessage-1; - $end = $_startMessage-1+$_numberOfMessages; + //$start = $_startMessage-1; + //$end = $_startMessage-1+$_numberOfMessages; //$_filter['range'] ="$start:$end"; //$_filter['range'] ="$_startMessage:*"; } @@ -1376,7 +1374,7 @@ class emailadmin_imapbase $sortResult = (is_array($_thisUIDOnly) ? $_thisUIDOnly:(array)$_thisUIDOnly); } - //$queryString = implode(',', $sortResult); + // fetch the data for the selected messages if (self::$debug||self::$debugTimes) $starttime = microtime(true); try @@ -1414,7 +1412,11 @@ class emailadmin_imapbase if (self::$debug||self::$debugTimes) { self::logRunTimes($starttime,null,'HordeFetch: for Folder:'.$_folderName.' Filter:'.array2string($_filter),__METHOD__.' ('.__LINE__.') '); - if (self::$debug) error_log(__METHOD__.' ('.__LINE__.') '.' Query:'.$queryString.' Result:'.array2string($headersNew)); + if (self::$debug) + { + $queryString = implode(',', $sortResult); + error_log(__METHOD__.' ('.__LINE__.') '.' Query:'.$queryString.' Result:'.array2string($headersNew)); + } } $count = 0; @@ -1506,7 +1508,7 @@ class emailadmin_imapbase if ($mime_type=='message/rfc822') { //error_log(__METHOD__.' ('.__LINE__.') '.' Uid:'.$uid.'->'.$mime_id.':'.array2string($part->contentTypeMap())); - foreach($part->contentTypeMap() as $sub_id => $sub_type) if ($sub_id != $mime_id) $skipParts[$sub_id] = $sub_type; + foreach($part->contentTypeMap() as $sub_id => $sub_type) { if ($sub_id != $mime_id) $skipParts[$sub_id] = $sub_type;} } //error_log(__METHOD__.' ('.__LINE__.') '.' Uid:'.$uid.'->'.$mime_id.' Disp:'.$partdisposition.' Type:'.$partPrimaryType.' Skip:'.array2string($skipParts)); if (array_key_exists($mime_id,$skipParts)) continue; @@ -1543,7 +1545,7 @@ class emailadmin_imapbase if (!isset($attachment['name'])||empty($attachment['name'])) $attachment['name'] = $part->getName(); $attachment['size'] = $part->getBytes(); if (($cid = $part->getContentId())) $attachment['cid'] = $cid; - if (empty($attachment['name'])) $attachment['name'] = (isset($attachment['cid'])&&!empty($attachment['cid'])?$attachment['cid']:lang("unknown").'_Uid'.$_uid.'_Part'.$mime_id).'.'.mime_magic::mime2ext($attachment['mimeType']); + if (empty($attachment['name'])) $attachment['name'] = (isset($attachment['cid'])&&!empty($attachment['cid'])?$attachment['cid']:lang("unknown").'_Uid'.$attachment['uid'].'_Part'.$mime_id).'.'.mime_magic::mime2ext($attachment['mimeType']); $headerObject['ATTACHMENTS'][$mime_id.'.'.$vmime_id] = $attachment; } if ($tnefResolved) unset($headerObject['ATTACHMENTS'][$mime_id]); @@ -1568,7 +1570,7 @@ class emailadmin_imapbase } //error_log(__METHOD__.' ('.__LINE__.') '.' '.$headerObject['SUBJECT'].'->'.$headerObject['DATE']); //error_log(__METHOD__.' ('.__LINE__.') '.' '.$this->decode_subject($headerObject['SUBJECT']).'->'.$headerObject['DATE']); - if (isset($headerObject['ATTACHMENTS']) && count($headerObject['ATTACHMENTS'])) foreach ($headerObject['ATTACHMENTS'] as $pID =>$a) $retValue['header'][$sortOrder[$uid]]['attachments'][]=$a; + if (isset($headerObject['ATTACHMENTS']) && count($headerObject['ATTACHMENTS'])) foreach ($headerObject['ATTACHMENTS'] as &$a) { $retValue['header'][$sortOrder[$uid]]['attachments'][]=$a;} $retValue['header'][$sortOrder[$uid]]['subject'] = $this->decode_subject($headerObject['SUBJECT']); $retValue['header'][$sortOrder[$uid]]['size'] = $headerObject['SIZE']; $retValue['header'][$sortOrder[$uid]]['date'] = self::_strtotime(($headerObject['DATE']&&!($headerObject['DATE']=='NIL')?$headerObject['DATE']:$headerObject['INTERNALDATE']),'ts',true); @@ -1703,23 +1705,23 @@ class emailadmin_imapbase //error_log(__METHOD__.' ('.__LINE__.') '.' Filter:'.array2string($_filter)); $try2useCache = true; static $eMailListContainsDeletedMessages; - if (is_null($eMailListContainsDeletedMessages)) $eMailListContainsDeletedMessages = egw_cache::getCache(egw_cache::INSTANCE,'email','eMailListContainsDeletedMessages'.trim($GLOBALS['egw_info']['user']['account_id']),$callback=null,$callback_params=array(),$expiration=60*60*1); + if (is_null($eMailListContainsDeletedMessages)) $eMailListContainsDeletedMessages = egw_cache::getCache(egw_cache::INSTANCE,'email','eMailListContainsDeletedMessages'.trim($GLOBALS['egw_info']['user']['account_id']),null,array(),60*60*1); // this indicates, that there is no Filter set, and the returned set/subset should not contain DELETED Messages, nor filtered for UNDELETED if ($setSession==true && ((strpos(array2string($_filter), 'UNDELETED') === false && strpos(array2string($_filter), 'DELETED') === false))) { if (self::$debugTimes) $starttime = microtime(true); - if (is_null($eMailListContainsDeletedMessages) || empty($eMailListContainsDeletedMessages[$this->profileID]) || empty($eMailListContainsDeletedMessages[$this->profileID][$_folderName])) $eMailListContainsDeletedMessages = egw_cache::getCache(egw_cache::INSTANCE,'email','eMailListContainsDeletedMessages'.trim($GLOBALS['egw_info']['user']['account_id']),$callback=null,$callback_params=array(),$expiration=60*60*1); + if (is_null($eMailListContainsDeletedMessages) || empty($eMailListContainsDeletedMessages[$this->profileID]) || empty($eMailListContainsDeletedMessages[$this->profileID][$_folderName])) $eMailListContainsDeletedMessages = egw_cache::getCache(egw_cache::INSTANCE,'email','eMailListContainsDeletedMessages'.trim($GLOBALS['egw_info']['user']['account_id']),null,array(),60*60*1); $deletedMessages = $this->getSortedList($_folderName, 0, $three=1, array('status'=>array('DELETED')),$five=true,false); - if (self::$debug) error_log(__METHOD__.' ('.__LINE__.') Found DeletedMessages:'.array2string($sortResult['match']->ids)); + if (self::$debug) error_log(__METHOD__.' ('.__LINE__.') Found DeletedMessages:'.array2string($eMailListContainsDeletedMessages)); $eMailListContainsDeletedMessages[$this->profileID][$_folderName] =$deletedMessages['count']; - egw_cache::setCache(egw_cache::INSTANCE,'email','eMailListContainsDeletedMessages'.trim($GLOBALS['egw_info']['user']['account_id']),$eMailListContainsDeletedMessages, $expiration=60*60*1); + egw_cache::setCache(egw_cache::INSTANCE,'email','eMailListContainsDeletedMessages'.trim($GLOBALS['egw_info']['user']['account_id']),$eMailListContainsDeletedMessages, 60*60*1); if (self::$debugTimes) self::logRunTimes($starttime,null,'setting eMailListContainsDeletedMessages for Profile:'.$this->profileID.' Folder:'.$_folderName.' to '.$eMailListContainsDeletedMessages[$this->profileID][$_folderName],__METHOD__.' ('.__LINE__.') '); //error_log(__METHOD__.' ('.__LINE__.') '.' Profile:'.$this->profileID.' Folder:'.$_folderName.' -> EXISTS/SessStat:'.array2string($folderStatus['MESSAGES']).'/'.self::$folderStatusCache[$this->profileID][$_folderName]['messages'].' ListContDelMsg/SessDeleted:'.$eMailListContainsDeletedMessages[$this->profileID][$_folderName].'/'.self::$folderStatusCache[$this->profileID][$_folderName]['deleted']); } $try2useCache = false; //self::$supportsORinQuery[$this->profileID]=true; if (is_null(self::$supportsORinQuery) || !isset(self::$supportsORinQuery[$this->profileID])) { - self::$supportsORinQuery = egw_cache::getCache(egw_cache::INSTANCE,'email','supportsORinQuery'.trim($GLOBALS['egw_info']['user']['account_id']),$callback=null,$callback_params=array(),$expiration=60*60*10); + self::$supportsORinQuery = egw_cache::getCache(egw_cache::INSTANCE,'email','supportsORinQuery'.trim($GLOBALS['egw_info']['user']['account_id']),null,array(),60*60*10); if (!isset(self::$supportsORinQuery[$this->profileID])) self::$supportsORinQuery[$this->profileID]=true; } //error_log(__METHOD__.' ('.__LINE__.') '.array2string($_filter).' SupportsOrInQuery:'.self::$supportsORinQuery[$this->profileID]); @@ -1777,7 +1779,7 @@ class emailadmin_imapbase //error_log(__METHOD__.'('.__LINE__.'):'.$e->getMessage()); // possible error OR Query. But Horde gives no detailed Info :-( self::$supportsORinQuery[$this->profileID]=false; - egw_cache::setCache(egw_cache::INSTANCE,'email','supportsORinQuery'.trim($GLOBALS['egw_info']['user']['account_id']),self::$supportsORinQuery,$expiration=60*60*10); + egw_cache::setCache(egw_cache::INSTANCE,'email','supportsORinQuery'.trim($GLOBALS['egw_info']['user']['account_id']),self::$supportsORinQuery,60*60*10); if (self::$debug) error_log(__METHOD__.__LINE__." Mailserver seems to have NO OR Capability for Search:".$sortResult->message); $filter = $this->createIMAPFilter($_folderName, $_filter, self::$supportsORinQuery[$this->profileID]); try @@ -1889,7 +1891,7 @@ class emailadmin_imapbase $imapFilter->charset('UTF-8'); //_debug_array($_criterias); - if (self::$debug) error_log(__METHOD__.' ('.__LINE__.') '.' Criterias:'.(!is_array($_criterias)?" none -> returning $all":array2string($_criterias))); + if (self::$debug) error_log(__METHOD__.' ('.__LINE__.') '.' Criterias:'.(!is_array($_criterias)?" none -> returning":array2string($_criterias))); if((!is_array($_criterias) || $_criterias['status']=='any') && (!isset($_criterias['string']) || empty($_criterias['string']))) { $imapFilter->flag('DELETED', $set=false); return $imapFilter; @@ -2222,7 +2224,7 @@ class emailadmin_imapbase { $opts['special_use'] = self::$specialUseFolders[$newFolderName]; } - $rv = $this->icServer->createMailbox($newFolderName, $opts); + $this->icServer->createMailbox($newFolderName, $opts); } catch (Exception $e) { @@ -2232,7 +2234,7 @@ class emailadmin_imapbase } try { - $srv = $this->icServer->subscribeMailbox($newFolderName); + $this->icServer->subscribeMailbox($newFolderName); } catch (Exception $e) { @@ -2267,14 +2269,14 @@ class emailadmin_imapbase if (self::$debug) error_log("create folder: $newFolderName"); try { - $rv = $this->icServer->renameMailbox($oldFolderName, $newFolderName); + $this->icServer->renameMailbox($oldFolderName, $newFolderName); } catch (Exception $e) { throw new egw_exception(__METHOD__." failed for $oldFolderName (rename to: $newFolderName) with error:".$e->getMessage());; } // clear FolderExistsInfoCache - egw_cache::setCache(egw_cache::INSTANCE,'email','icServerFolderExistsInfo'.trim($GLOBALS['egw_info']['user']['account_id']),$folderInfo,$expiration=60*60*5); + egw_cache::setCache(egw_cache::INSTANCE,'email','icServerFolderExistsInfo'.trim($GLOBALS['egw_info']['user']['account_id']),$folderInfo,60*60*5); return $newFolderName; @@ -2297,10 +2299,10 @@ class emailadmin_imapbase } catch (Exception $e) { - throw new egw_exception("Deleting Folder $_foldername failed! Error:".$e->getMessage());; + throw new egw_exception("Deleting Folder $_folderName failed! Error:".$e->getMessage());; } // clear FolderExistsInfoCache - egw_cache::setCache(egw_cache::INSTANCE,'email','icServerFolderExistsInfo'.trim($GLOBALS['egw_info']['user']['account_id']),$folderInfo,$expiration=60*60*5); + egw_cache::setCache(egw_cache::INSTANCE,'email','icServerFolderExistsInfo'.trim($GLOBALS['egw_info']['user']['account_id']),$folderInfo,60*60*5); return true; } @@ -2352,7 +2354,7 @@ class emailadmin_imapbase if ($_subscribedOnly && $_getCounters===false) { - if (is_null($folders2return)) $folders2return = egw_cache::getCache(egw_cache::INSTANCE,'email','folderObjects'.trim($GLOBALS['egw_info']['user']['account_id']),$callback=null,$callback_params=array(),$expiration=60*60*1); + if (is_null($folders2return)) $folders2return = egw_cache::getCache(egw_cache::INSTANCE,'email','folderObjects'.trim($GLOBALS['egw_info']['user']['account_id']),null,array(),60*60*1); if ($_useCacheIfPossible && isset($folders2return[$this->icServer->ImapServerId]) && !empty($folders2return[$this->icServer->ImapServerId])) { //error_log(__METHOD__.' ('.__LINE__.') '.' using Cached folderObjects'.array2string($folders2return[$this->icServer->ImapServerId])); @@ -2362,9 +2364,8 @@ class emailadmin_imapbase } // use $folderBasicInfo for holding attributes and other basic folderinfo $folderBasicInfo[$this->icServer->ImapServerId] static $folderBasicInfo; - if (is_null($folderBasicInfo)||!isset($folderBasicInfo[$this->icServer->ImapServerId])) $folderBasicInfo = egw_cache::getCache(egw_cache::INSTANCE,'email','folderBasicInfo'.trim($GLOBALS['egw_info']['user']['account_id']),null,array(),$expiration=60*60*1); + if (is_null($folderBasicInfo)||!isset($folderBasicInfo[$this->icServer->ImapServerId])) $folderBasicInfo = egw_cache::getCache(egw_cache::INSTANCE,'email','folderBasicInfo'.trim($GLOBALS['egw_info']['user']['account_id']),null,array(),60*60*1); //error_log(__METHOD__.' ('.__LINE__.') '.array2string(array_keys($folderBasicInfo[$this->icServer->ImapServerId]))); - $isUWIMAP = false; $delimiter = $this->getHierarchyDelimiter(); @@ -2391,6 +2392,7 @@ class emailadmin_imapbase //$nameSpace = $this->icServer->getNameSpaces(); $nameSpace = $this->_getNameSpaces(); $fetchedAllInOneGo = false; + $subscribedFoldersForCache = $foldersNameSpace = array(); //error_log(__METHOD__.__LINE__.array2string($nameSpace)); if (is_array($nameSpace)) { @@ -2653,7 +2655,7 @@ class emailadmin_imapbase $rv = false; foreach ($haystack as $k => $v) { - foreach($v as $sk => $sv) if (trim($sv)==trim($needle)) return $k; + foreach($v as &$sv) {if (trim($sv)==trim($needle)) return $k;} } return $rv; } @@ -2663,7 +2665,7 @@ class emailadmin_imapbase * * Helper function to sort folder-objects by displayname * @param object $a - * @param object $b, array of folderobjects + * @param object $b array of folderobjects * @return int expect values (0, 1 or -1) */ function sortByDisplayName($a,$b) @@ -2677,7 +2679,7 @@ class emailadmin_imapbase * * Helper function to sort folder-objects by auto Folder Position * @param object $a - * @param object $b, array of folderobjects + * @param object $b array of folderobjects * @return int expect values (0, 1 or -1) */ function sortByAutoFolderPos($a,$b) @@ -2754,7 +2756,7 @@ class emailadmin_imapbase if (is_array($mbx[$mbxkeys[0]]["ATTRIBUTES"]) && (in_array('\HasChildren',$mbx[$mbxkeys[0]]["ATTRIBUTES"]) || in_array('\Haschildren',$mbx[$mbxkeys[0]]["ATTRIBUTES"]) || in_array('\haschildren',$mbx[$mbxkeys[0]]["ATTRIBUTES"]))) { // if there are children fetch them //echo $mbx[$mbxkeys[0]]['MAILBOX']."
"; - unset($buff); + $buff = $this->icServer->getMailboxes($mbx[$mbxkeys[0]]['MAILBOX'].($mbx[$mbxkeys[0]]['MAILBOX'] == $prefix ? '':$delimiter),2,false); //$buff = $this->icServer->getMailboxes($mbx[$mbxkeys[0]]['MAILBOX'],2,false); //_debug_array($buff); @@ -2778,8 +2780,8 @@ class emailadmin_imapbase /** * _getSpecialUseFolder * abstraction layer for getDraftFolder, getTemplateFolder, getTrashFolder and getSentFolder - * @param string $type the type to fetch (Drafts|Template|Trash|Sent) - * @param boolean $_checkexistance, trigger check for existance + * @param string $_type the type to fetch (Drafts|Template|Trash|Sent) + * @param boolean $_checkexistance trigger check for existance * @param boolean& $created =null on return true: if folder was just created, false if not * @return mixed string or false */ @@ -2870,7 +2872,7 @@ class emailadmin_imapbase /** * getDraftFolder wrapper for _getSpecialUseFolder Type Drafts - * @param boolean $_checkexistance, trigger check for existance + * @param boolean $_checkexistance trigger check for existance * @return mixed string or false */ function getJunkFolder($_checkexistance=TRUE) @@ -2880,7 +2882,7 @@ class emailadmin_imapbase /** * getDraftFolder wrapper for _getSpecialUseFolder Type Drafts - * @param boolean $_checkexistance, trigger check for existance + * @param boolean $_checkexistance trigger check for existance * @return mixed string or false */ function getDraftFolder($_checkexistance=TRUE) @@ -2890,7 +2892,7 @@ class emailadmin_imapbase /** * getTemplateFolder wrapper for _getSpecialUseFolder Type Template - * @param boolean $_checkexistance, trigger check for existance + * @param boolean $_checkexistance trigger check for existance * @return mixed string or false */ function getTemplateFolder($_checkexistance=TRUE) @@ -2900,7 +2902,7 @@ class emailadmin_imapbase /** * getTrashFolder wrapper for _getSpecialUseFolder Type Trash - * @param boolean $_checkexistance, trigger check for existance + * @param boolean $_checkexistance trigger check for existance * @return mixed string or false */ function getTrashFolder($_checkexistance=TRUE) @@ -2910,7 +2912,7 @@ class emailadmin_imapbase /** * getSentFolder wrapper for _getSpecialUseFolder Type Sent - * @param boolean $_checkexistance, trigger check for existance + * @param boolean $_checkexistance trigger check for existance * @return mixed string or false */ function getSentFolder($_checkexistance=TRUE) @@ -2920,7 +2922,7 @@ class emailadmin_imapbase /** * getOutboxFolder wrapper for _getSpecialUseFolder Type Outbox - * @param boolean $_checkexistance, trigger check for existance + * @param boolean $_checkexistance trigger check for existance * @return mixed string or false */ function getOutboxFolder($_checkexistance=TRUE) @@ -2930,8 +2932,8 @@ class emailadmin_imapbase /** * isSentFolder is the given folder the sent folder or at least a subfolder of it - * @param string $_foldername, folder to perform the check on - * @param boolean $_checkexistance, trigger check for existance + * @param string $_folderName folder to perform the check on + * @param boolean $_checkexistance trigger check for existance * @return boolean */ function isSentFolder($_folderName, $_checkexistance=TRUE) @@ -2954,8 +2956,8 @@ class emailadmin_imapbase /** * checks if the Outbox folder exists and is part of the foldername to be checked - * @param string $_foldername, folder to perform the check on - * @param boolean $_checkexistance, trigger check for existance + * @param string $_folderName folder to perform the check on + * @param boolean $_checkexistance trigger check for existance * @return boolean */ function isOutbox($_folderName, $_checkexistance=TRUE) @@ -2977,8 +2979,8 @@ class emailadmin_imapbase /** * isDraftFolder is the given folder the sent folder or at least a subfolder of it - * @param string $_foldername, folder to perform the check on - * @param boolean $_checkexistance, trigger check for existance + * @param string $_folderName folder to perform the check on + * @param boolean $_checkexistance trigger check for existance * @return boolean */ function isDraftFolder($_folderName, $_checkexistance=TRUE) @@ -3001,8 +3003,8 @@ class emailadmin_imapbase /** * isTrashFolder is the given folder the sent folder or at least a subfolder of it - * @param string $_foldername, folder to perform the check on - * @param boolean $_checkexistance, trigger check for existance + * @param string $_folderName folder to perform the check on + * @param boolean $_checkexistance trigger check for existance * @return boolean */ function isTrashFolder($_folderName, $_checkexistance=TRUE) @@ -3025,8 +3027,8 @@ class emailadmin_imapbase /** * isTemplateFolder is the given folder the sent folder or at least a subfolder of it - * @param string $_foldername, folder to perform the check on - * @param boolean $_checkexistance, trigger check for existance + * @param string $_folderName folder to perform the check on + * @param boolean $_checkexistance trigger check for existance * @return boolean */ function isTemplateFolder($_folderName, $_checkexistance=TRUE) @@ -3049,8 +3051,8 @@ class emailadmin_imapbase /** * folderExists checks for existance of a given folder - * @param string $_foldername, folder to perform the check on - * @param boolean $_forceCheck, trigger check for existance on icServer + * @param string $_folder folder to perform the check on + * @param boolean $_forceCheck trigger check for existance on icServer * @return mixed string or false */ function folderExists($_folder, $_forceCheck=false) @@ -3145,7 +3147,6 @@ class emailadmin_imapbase function deleteMessages($_messageUID, $_folder=NULL, $_forceDeleteMethod='no') { //error_log(__METHOD__.' ('.__LINE__.') '.'->'.array2string($_messageUID).','.array2string($_folder).', '.$_forceDeleteMethod); - $msglist = ''; $oldMailbox = ''; if (is_null($_folder) || empty($_folder)) $_folder = $this->sessionData['mailbox']; if (empty($_messageUID)) @@ -3183,13 +3184,13 @@ class emailadmin_imapbase case "move_to_trash": //error_log(__METHOD__.' ('.__LINE__.') '); $updateCache = true; - if(!empty($trashFolder)); { + if(!empty($trashFolder)) { if (self::$debug) error_log(__METHOD__.' ('.__LINE__.') '.implode(' : ', $_messageUID)); if (self::$debug) error_log(__METHOD__.' ('.__LINE__.') '."$trashFolder <= $_folder / ". $this->sessionData['mailbox']); // copy messages try { - $retValue = $this->icServer->copy($_folder, $trashFolder, array('ids'=>$uidsToDelete,'move'=>true)); + $this->icServer->copy($_folder, $trashFolder, array('ids'=>$uidsToDelete,'move'=>true)); } catch (Exception $e) { @@ -3347,7 +3348,7 @@ class emailadmin_imapbase } try { - foreach($messageUIDs as $k => $uids) + foreach($messageUIDs as &$uids) { if ($uids==='all') { @@ -3468,9 +3469,8 @@ class emailadmin_imapbase */ function moveMessages($_foldername, $_messageUID, $deleteAfterMove=true, $currentFolder = Null, $returnUIDs = false, $_sourceProfileID = Null, $_targetProfileID = Null) { - $msglist = ''; $source = emailadmin_account::read(($_sourceProfileID?$_sourceProfileID:$this->icServer->ImapServerId))->imapServer(); - $deleteOptions = $GLOBALS['egw_info']["user"]["preferences"]["mail"]["deleteOptions"]; + //$deleteOptions = $GLOBALS['egw_info']["user"]["preferences"]["mail"]["deleteOptions"]; if (empty($_messageUID)) { if (self::$debug) error_log(__METHOD__." no Message(s): ".implode(',',$_messageUID)); @@ -3512,7 +3512,7 @@ class emailadmin_imapbase $retUid = new Horde_Imap_Client_Ids(); // we copy chunks of 5 to avoid too much memory and/or server stress // some servers seem not to allow/support the appendig of multiple messages. so we are down to one - foreach($headersNew as $id=>$_headerObject) { + foreach($headersNew as &$_headerObject) { $c++; $flags = $_headerObject->getFlags(); //unseen status seems to be lost when retrieving the full message $date = $_headerObject->getImapDate(); @@ -3578,7 +3578,6 @@ class emailadmin_imapbase { error_log(__METHOD__.' ('.__LINE__.') '."Copying to Folder $_foldername failed! Error:".$e->getMessage()); throw new egw_exception("Copying to Folder $_foldername failed! Error:".$e->getMessage()); - return false; } } @@ -3763,11 +3762,11 @@ class emailadmin_imapbase case 'BASE64': // use imap_base64 to decode, not any longer, as it is strict, and fails if it encounters invalid chars return base64_decode($_mimeMessage); - break; + case 'QUOTED-PRINTABLE': // use imap_qprint to decode return quoted_printable_decode($_mimeMessage); - break; + case 'WEDONTKNOWTHEENCODING': // try base64 $r = base64_decode($_mimeMessage); @@ -3779,7 +3778,6 @@ class emailadmin_imapbase default: // it is either not encoded or we don't know about it return $_mimeMessage; - break; } } @@ -3789,7 +3787,7 @@ class emailadmin_imapbase * a wrapper for multipartmixed * @param string/int $_uid the messageuid, * @param Horde_Mime_Part $_structure structure for parsing - * @param string $_htmlMode, how to display a message, html, plain text, ... + * @param string $_htmlMode how to display a message, html, plain text, ... * @param boolean $_preserveSeen flag to preserve the seenflag by using body.peek * @return array containing the desired part */ @@ -3919,8 +3917,8 @@ class emailadmin_imapbase * Get part of the message, if its stucture is indicating its of multipart mixed style * * @param int $_uid the messageuid, - * @param Horde_Mime_Part $_structure='', if given use structure for parsing - * @param string $_htmlMode, how to display a message, html, plain text, ... + * @param Horde_Mime_Part $_structure = '' if given use structure for parsing + * @param string $_htmlMode how to display a message, html, plain text, ... * @param boolean $_preserveSeen flag to preserve the seenflag by using body.peek * @return array containing the desired part */ @@ -4014,7 +4012,7 @@ class emailadmin_imapbase if($part->getSubType() == 'rfc822' || $part->getDisposition() == 'attachment') { $skipParts[$mime_id.'.0'] = $mime_type; - foreach($part->contentTypeMap() as $sub_id => $sub_type) $skipParts[$sub_id] = $sub_type; + foreach($part->contentTypeMap() as $sub_id => $sub_type){ $skipParts[$sub_id] = $sub_type;} //error_log(__METHOD__.' ('.__LINE__.') '.' Uid:'.$_uid.' Part:'.$mime_id.':'.array2string($skipParts)); //break 2; } @@ -4033,8 +4031,8 @@ class emailadmin_imapbase * get part of the message, if its stucture is indicating its of multipart related style * a wrapper for multipartmixed * @param string/int $_uid the messageuid, - * @param Horde_Mime_Part $_structure, if given use structure for parsing - * @param string $_htmlMode, how to display a message, html, plain text, ... + * @param Horde_Mime_Part $_structure if given use structure for parsing + * @param string $_htmlMode how to display a message, html, plain text, ... * @param boolean $_preserveSeen flag to preserve the seenflag by using body.peek * @return array containing the desired part */ @@ -4047,12 +4045,12 @@ class emailadmin_imapbase * Fetch a body part * * @param int $_uid - * @param string $_partID=null - * @param string $_folder=null - * @param boolean $_preserveSeen=false - * @param boolean $_stream=false true return a stream, false return string - * @param string &$_encoding=null on return: transfer encoding of returned part - * @param boolean $_tryDecodingServerside=true; wether to try to fetch Data with BINARY instead of BODY + * @param string $_partID = null + * @param string $_folder = null + * @param boolean $_preserveSeen = false + * @param boolean $_stream = false true return a stream, false return string + * @param string &$_encoding = null on return: transfer encoding of returned part + * @param boolean $_tryDecodingServerside = true; wether to try to fetch Data with BINARY instead of BODY * @return string|resource */ function getBodyPart($_uid, $_partID=null, $_folder=null, $_preserveSeen=false, $_stream=false, &$_encoding=null, $_tryDecodingServerside=true) @@ -4105,10 +4103,10 @@ class emailadmin_imapbase * Get Body from message * * @param int $_uid the messageuid - * @param Horde_Mime_Part $_structure=null, if given use structure for parsing + * @param Horde_Mime_Part $_structure = null if given use structure for parsing * @param string $_htmlMode how to display a message: 'html_only', 'always_display', 'only_if_no_text' or '' * @param boolean $_preserveSeen flag to preserve the seenflag by using body.peek - * @param boolean $_stream=false true return a stream, false return string + * @param boolean $_stream = false true return a stream, false return string * @return array containing the desired text part, mimeType and charset */ function getTextPart($_uid, Horde_Mime_Part $_structure, $_htmlMode='', $_preserveSeen=false, $_stream=false) @@ -4203,7 +4201,7 @@ class emailadmin_imapbase if ($method == 'REPLY') $event['title'] = $oldevent[$eventid[0]]['title']; } // we prepare the message - $details = $calboupdate->_get_event_details($event,$action,$event_arr); + $details = $calboupdate->_get_event_details($event,'',$event_arr=array()); $details['olddate']=$olddate; //_debug_array($_structure); list($subject,$info) = $calboupdate->get_update_message($event, $method !='REPLY'); @@ -4235,9 +4233,9 @@ class emailadmin_imapbase * Get Body of message * * @param int $_uid the messageuid, - * @param string $_htmlOptions, how to display a message, html, plain text, ... - * @param string $_partID=null , the partID, may be omitted - * @param Horde_Mime_Part $_structure=null if given use structure for parsing + * @param string $_htmlOptions how to display a message, html, plain text, ... + * @param string $_partID = null the partID, may be omitted + * @param Horde_Mime_Part $_structure = null if given use structure for parsing * @param boolean $_preserveSeen flag to preserve the seenflag by using body.peek * @param string $_folder folder to work on * @return array containing the message body, mimeType and charset @@ -4377,7 +4375,7 @@ class emailadmin_imapbase { if (!isset($singleBodyPart['body'])) { $buff = self::normalizeBodyParts($singleBodyPart); - foreach ((array)$buff as $val) $body2return[] = $val; + foreach ((array)$buff as $val) { $body2return[] = $val;} continue; } $body2return[] = $singleBodyPart; @@ -4475,7 +4473,7 @@ class emailadmin_imapbase if (!$preserveHTML) { // filter only the 'body', as we only want that part, if we throw away the html - preg_match('`(]*>)(.+?)(.*?)`ims', $newBody, $matches); + preg_match('`(]*>)(.+?)(.*?)`ims', $newBody, $matches=array()); if ($matches[2]) { $hasOther = true; @@ -4486,7 +4484,7 @@ class emailadmin_imapbase else { // htmLawed filter only the 'body' - preg_match('`(]*>)(.+?)(.*?)`ims', $newBody, $matches); + preg_match('`(]*>)(.+?)(.*?)`ims', $newBody, $matches=array()); if ($matches[2]) { $hasOther = true; @@ -4500,7 +4498,7 @@ class emailadmin_imapbase if ($hasOther && $preserveHTML) $newBody = $matches[1]. $newBody. $matches[3]; } //error_log(__METHOD__.' ('.__LINE__.') '.' after purify:'.$newBody); - if ($preserveHTML==false) $newBody = translation::convertHTMLToText($newBody,self::$displayCharset,true,$stripalltags=true); + if ($preserveHTML==false) $newBody = translation::convertHTMLToText($newBody,self::$displayCharset,true,true); //error_log(__METHOD__.' ('.__LINE__.') '.' after convertHTMLToText:'.$newBody); if ($preserveHTML==false) $newBody = nl2br($newBody); // we need this, as htmLawed removes \r\n $mailClass->getCleanHTML($newBody,false,$preserveHTML); // remove stuff we regard as unwanted @@ -4542,7 +4540,7 @@ class emailadmin_imapbase $s=explode(" ", $line); $line = ""; $linecnt = 0; - foreach ($s as $k=>$v) { + foreach ($s as &$v) { $cnt = strlen($v); // only break long words within the wordboundaries, // but it may destroy links, so we check for href and dont do it if we find one @@ -4571,7 +4569,7 @@ class emailadmin_imapbase * getMessageEnvelope * get parsed headers from message * @param string/int $_uid the messageuid, - * @param string/int $_partID='' , the partID, may be omitted + * @param string/int $_partID = '' , the partID, may be omitted * @param boolean $decode flag to do the decoding on the fly * @param string $_folder folder to work on * @param boolean $_useHeaderInsteadOfEnvelope - force getMessageHeader method to be used for fetching Envelope Information @@ -4594,10 +4592,11 @@ class emailadmin_imapbase 'ids' => $uidsToFetch, )); if (is_object($headersNew)) { - foreach($headersNew as $id=>$_headerObject) { + foreach($headersNew as &$_headerObject) { $env = $_headerObject->getEnvelope(); //_debug_array($envFields->singleFields()); - foreach ($envFields->singleFields() as $e => $v) + $singleFields = $envFields->singleFields(); + foreach ($singleFields as &$v) { switch ($v) { @@ -4758,7 +4757,7 @@ class emailadmin_imapbase * getMessageRawHeader * get messages raw header data * @param string/int $_uid the messageuid, - * @param string/int $_partID='' , the partID, may be omitted + * @param string/int $_partID = '' , the partID, may be omitted * @param string $_folder folder to work on * @return string the message header */ @@ -4768,7 +4767,7 @@ class emailadmin_imapbase if (empty($_folder)) $_folder = ($this->sessionData['mailbox']? $this->sessionData['mailbox'] : $this->icServer->getCurrentMailbox()); //error_log(__METHOD__.' ('.__LINE__.') '." Try Using Cache for raw Header $_uid, $_partID in Folder $_folder"); - if (is_null($rawHeaders)||!is_array($rawHeaders)) $rawHeaders = egw_cache::getCache(egw_cache::INSTANCE,'email','rawHeadersCache'.trim($GLOBALS['egw_info']['user']['account_id']),$callback=null,$callback_params=array(),$expiration=60*60*1); + if (is_null($rawHeaders)||!is_array($rawHeaders)) $rawHeaders = egw_cache::getCache(egw_cache::INSTANCE,'email','rawHeadersCache'.trim($GLOBALS['egw_info']['user']['account_id']),null,array(),60*60*1); if (isset($rawHeaders[$this->icServer->ImapServerId][(string)$_folder][$_uid][(empty($_partID)?'NIL':$_partID)])) { //error_log(__METHOD__.' ('.__LINE__.') '." Using Cache for raw Header $_uid, $_partID in Folder $_folder"); @@ -4793,7 +4792,7 @@ class emailadmin_imapbase 'ids' => $uidsToFetch, )); if (is_object($headersNew)) { - foreach($headersNew as $id=>$_headerObject) { + foreach($headersNew as &$_headerObject) { $retValue = $_headerObject->getHeaderText(); if ($_partID != '') { @@ -4809,13 +4808,13 @@ class emailadmin_imapbase } } $rawHeaders[$this->icServer->ImapServerId][(string)$_folder][$_uid][(empty($_partID)?'NIL':$_partID)]=$retValue; - egw_cache::setCache(egw_cache::INSTANCE,'email','rawHeadersCache'.trim($GLOBALS['egw_info']['user']['account_id']),$rawHeaders,$expiration=60*60*1); + egw_cache::setCache(egw_cache::INSTANCE,'email','rawHeadersCache'.trim($GLOBALS['egw_info']['user']['account_id']),$rawHeaders,60*60*1); return $retValue; } /** * getStyles - extracts the styles from the given bodyparts - * @param array $bodyParts with the bodyparts + * @param array $_bodyParts with the bodyparts * @return string a preformatted string with the mails converted to text */ static function &getStyles($_bodyParts) @@ -4836,7 +4835,7 @@ class emailadmin_imapbase ); $ct = 0; - if (stripos($singleBodyPart['body'],'(.+)#isU', $singleBodyPart['body'], $newStyle); + if (stripos($singleBodyPart['body'],'(.+)#isU', $singleBodyPart['body'], $newStyle=array()); if ($ct>0) { //error_log(__METHOD__.' ('.__LINE__.') '.array2string($newStyle[0])); @@ -4881,7 +4880,7 @@ class emailadmin_imapbase * getMessageRawBody * get the message raw body * @param string/int $_uid the messageuid, - * @param string/int $_partID='' , the partID, may be omitted + * @param string/int $_partID = '' , the partID, may be omitted * @param string $_folder folder to work on * @return string the message body */ @@ -4913,7 +4912,7 @@ class emailadmin_imapbase 'ids' => $uidsToFetch, )); if (is_object($headersNew)) { - foreach($headersNew as $id=>$_headerObject) { + foreach($headersNew as &$_headerObject) { $body = $_headerObject->getFullMsg(); if ($_partID != '') { @@ -4938,9 +4937,9 @@ class emailadmin_imapbase * Get structure of a mail or part of a mail * * @param int $_uid - * @param string $_partID=null - * @param string $_folder=null - * @param boolean $_preserveSeen=false flag to preserve the seenflag by using body.peek + * @param string $_partID = null + * @param string $_folder = null + * @param boolean $_preserveSeen = false flag to preserve the seenflag by using body.peek * @param Horde_Imap_Client_Fetch_Query $fquery=null default query just structure * @return Horde_Mime_Part */ @@ -5019,7 +5018,7 @@ class emailadmin_imapbase if ($mime_type=='message/rfc822' && $_partID!=$mime_id) { //error_log(__METHOD__.' ('.__LINE__.') '.' Uid:'.$uid.'->'.$mime_id.':'.array2string($part->contentTypeMap())); - foreach($part->contentTypeMap() as $sub_id => $sub_type) if ($sub_id != $mime_id) $skipParts[$sub_id] = $sub_type; + foreach($part->contentTypeMap() as $sub_id => $sub_type) {if ($sub_id != $mime_id) $skipParts[$sub_id] = $sub_type;} } if (empty($partDisposition) && $partPrimaryType != 'multipart' && $partPrimaryType != 'text') { @@ -5308,7 +5307,7 @@ class emailadmin_imapbase * @param string|int $_uid * @param string $_cid * @param string $_part - * @param boolean $_stream=null null do NOT fetch content, use fetchPartContents later + * @param boolean $_stream = null null do NOT fetch content, use fetchPartContents later * true: * @return Horde_Mime_Part */ @@ -5373,7 +5372,7 @@ class emailadmin_imapbase * * @param int $_uid * @param Horde_Mime_Part $part - * @param boolean $_stream=false true return a stream, false a string + * @param boolean $_stream = false true return a stream, false a string * @param boolean $_preserveSeen flag to preserve the seenflag by using body.peek * @param string $_mimetype to decide wether to try to fetch part as binary or not * @return Horde_Mime_Part @@ -5444,7 +5443,7 @@ class emailadmin_imapbase //$messageid = true; // for debug reasons only if ($messageid === true || empty($messageid)) // try to figure out the message uid { - $list = $this->getHeaders($_folderName, $_startMessage=1, $_numberOfMessages=1, $_sort='INTERNALDATE', $_reverse=true, $_filter=array(),$_thisUIDOnly=null, $_cacheResult=false); + $list = $this->getHeaders($_folderName, $_startMessage=1, 1, 'INTERNALDATE', true, array(),null, false); if ($list) { if (self::$debug) error_log(__METHOD__.' ('.__LINE__.') '.' MessageUid:'.$messageid.' but found:'.array2string($list)); @@ -5546,7 +5545,7 @@ class emailadmin_imapbase fwrite($tmpfile,$headdata.$mailcontent['message']); fclose($tmpfile); } - foreach($mailcontent['attachments'] as $tmpattach => $tmpval) + foreach($mailcontent['attachments'] as &$tmpval) { $attachedMessages[] = $tmpval; } @@ -5657,7 +5656,7 @@ class emailadmin_imapbase * @param array $rfcAddressArray an addressarray as provided by mail retieved via egw_pear.... * @return string a comma separated string with the mailaddress(es) converted to text */ - static function convertAddressArrayToString($rfcAddressArray, $createHTML = false) + static function convertAddressArrayToString($rfcAddressArray) { //error_log(__METHOD__.' ('.__LINE__.') '.array2string($rfcAddressArray)); $returnAddr =''; @@ -5714,11 +5713,10 @@ class emailadmin_imapbase */ function merge($content,$ids,$mimetype='') { - $contacts = new addressbook_bo(); $mergeobj = new addressbook_merge(); if (empty($mimetype)) $mimetype = (strlen(strip_tags($content)) == strlen($content) ?'text/plain':'text/html'); - $rv = $mergeobj->merge_string($content,$ids,$err,$mimetype, array(), self::$displayCharset); + $rv = $mergeobj->merge_string($content,$ids,$err='',$mimetype, array(), self::$displayCharset); if (empty($rv) && !empty($content) && !empty($err)) $rv = $content; if (!empty($err) && !empty($content) && !empty($ids)) error_log(__METHOD__.' ('.__LINE__.') '.' Merge failed for Ids:'.array2string($ids).' ContentType:'.$mimetype.' Content:'.$content.' Reason:'.array2string($err)); return $rv; @@ -6312,7 +6310,7 @@ class emailadmin_imapbase $matches = array(); preg_match_all("/[\w\.,-.,_.,0-9.]+@[\w\.,-.,_.,0-9.]+/",$addresses,$matches); //error_log(__METHOD__.__LINE__.array2string($matches)); - foreach ($matches[0] as &$match) $match = trim($match,', '); + foreach ($matches[0] as &$match) {$match = trim($match,', ');} $addresses = implode(',',$matches[0]); //error_log(__METHOD__.__LINE__.array2string($addresses)); $ret = $rfc822->parseAddressList($addresses, $default_domain ? array('default_domain' => $default_domain) : array()); @@ -6359,22 +6357,8 @@ class emailadmin_imapbase */ function addAccount($_hookValues) { - error_log(__METHOD__.' ('.__LINE__.') '.' NOT DONE JET!'); - //$_profile_id=???? - //$icServer = emailadmin_account::read($_profile_id)->imapServer(); - //$ogServer = emailadmin_account::read($_profile_id)->smtpServer(); - -/* - if(($icServer instanceof defaultimap)) { - // if not connected, try opening an admin connection - if (!$icServer->_connected) $this->openConnection($this->profileID,true); - $icServer->addAccount($_hookValues); - if ($icServer->_connected) $this->closeConnection(); // close connection afterwards - } - if(($ogServer instanceof emailadmin_smtp)) { - $ogServer->addAccount($_hookValues); - } -*/ + error_log(__METHOD__.' ('.__LINE__.') '.' NOT DONE YET!' . ' hookValue = '. $_hookValues); + } /** @@ -6387,22 +6371,8 @@ class emailadmin_imapbase */ function deleteAccount($_hookValues) { - error_log(__METHOD__.' ('.__LINE__.') '.' NOT DONE JET!'); - //$_profile_id=???? - //$icServer = emailadmin_account::read($_profile_id)->imapServer(); - //$ogServer = emailadmin_account::read($_profile_id)->smtpServer(); -/* - if(($icServer instanceof defaultimap)) { - //try to connect with admin rights, when not connected - if (!$icServer->_connected) $this->openConnection($this->profileID,true); - $icServer->deleteAccount($_hookValues); - if ($icServer->_connected) $this->closeConnection(); // close connection - } - - if(($ogServer instanceof emailadmin_smtp)) { - $ogServer->deleteAccount($_hookValues); - } -*/ + error_log(__METHOD__.' ('.__LINE__.') '.' NOT DONE YET!' . ' hookValue = '. $_hookValues); + } /** @@ -6415,18 +6385,7 @@ class emailadmin_imapbase */ function updateAccount($_hookValues) { - error_log(__METHOD__.' ('.__LINE__.') '.' NOT DONE JET!'); - //$_profile_id=???? - //$icServer = emailadmin_account::read($_profile_id)->imapServer(); - //$ogServer = emailadmin_account::read($_profile_id)->smtpServer(); -/* - if(($icServer instanceof defaultimap)) { - $icServer->updateAccount($_hookValues); - } - - if(($ogServer instanceof emailadmin_smtp)) { - $ogServer->updateAccount($_hookValues); - } -*/ + error_log(__METHOD__.' ('.__LINE__.') '.' NOT DONE YET!' . ' hookValue = '. $_hookValues); + } } diff --git a/etemplate/js/et2_widget_link.js b/etemplate/js/et2_widget_link.js index ed5ed5175f..3891409f94 100644 --- a/etemplate/js/et2_widget_link.js +++ b/etemplate/js/et2_widget_link.js @@ -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 || ''; } diff --git a/infolog/inc/class.infolog_bo.inc.php b/infolog/inc/class.infolog_bo.inc.php index 89104cc895..dc83ef1f38 100644 --- a/infolog/inc/class.infolog_bo.inc.php +++ b/infolog/inc/class.infolog_bo.inc.php @@ -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 * @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 */ diff --git a/infolog/inc/class.infolog_hooks.inc.php b/infolog/inc/class.infolog_hooks.inc.php index e6dfcfea07..ece94544da 100644 --- a/infolog/inc/class.infolog_hooks.inc.php +++ b/infolog/inc/class.infolog_hooks.inc.php @@ -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') + ); + } } diff --git a/infolog/inc/class.infolog_ui.inc.php b/infolog/inc/class.infolog_ui.inc.php index 44f31a97f9..8dbe7306f6 100644 --- a/infolog/inc/class.infolog_ui.inc.php +++ b/infolog/inc/class.infolog_ui.inc.php @@ -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 - * @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__.'
'; - //_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'])); } /** diff --git a/infolog/setup/setup.inc.php b/infolog/setup/setup.inc.php index 9c07a0f9b1..fff3c3aa34 100755 --- a/infolog/setup/setup.inc.php +++ b/infolog/setup/setup.inc.php @@ -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( diff --git a/mail/inc/class.mail_compose.inc.php b/mail/inc/class.mail_compose.inc.php index 34b6569f8b..512707ca28 100644 --- a/mail/inc/class.mail_compose.inc.php +++ b/mail/inc/class.mail_compose.inc.php @@ -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) { diff --git a/mail/inc/class.mail_integration.inc.php b/mail/inc/class.mail_integration.inc.php new file mode 100644 index 0000000000..2ad5559529 --- /dev/null +++ b/mail/inc/class.mail_integration.inc.php @@ -0,0 +1,288 @@ + + * @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 + )); + } +} + diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index d433e3c04c..7cc6cfd855 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -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); } } } diff --git a/mail/js/app.js b/mail/js/app.js index 215f6bab25..41a6d6b49f 100644 --- a/mail/js/app.js +++ b/mail/js/app.js @@ -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 * diff --git a/mail/lang/egw_de.lang b/mail/lang/egw_de.lang index a4bd364038..c85d2f6831 100644 --- a/mail/lang/egw_de.lang +++ b/mail/lang/egw_de.lang @@ -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. diff --git a/mail/lang/egw_en.lang b/mail/lang/egw_en.lang index 5c8f9e91c2..9922fc8d2d 100644 --- a/mail/lang/egw_en.lang +++ b/mail/lang/egw_en.lang @@ -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 diff --git a/mail/templates/default/compose.xet b/mail/templates/default/compose.xet index f8eddf225f..2be62e97f8 100644 --- a/mail/templates/default/compose.xet +++ b/mail/templates/default/compose.xet @@ -10,6 +10,7 @@ + diff --git a/mail/templates/default/integration_to_entry_dialog.xet b/mail/templates/default/integration_to_entry_dialog.xet new file mode 100644 index 0000000000..ca05c67523 --- /dev/null +++ b/mail/templates/default/integration_to_entry_dialog.xet @@ -0,0 +1,12 @@ + + + + + + diff --git a/phpgwapi/inc/class.egw_link.inc.php b/phpgwapi/inc/class.egw_link.inc.php index 9611f3d082..a4ce27ac6b 100644 --- a/phpgwapi/inc/class.egw_link.inc.php +++ b/phpgwapi/inc/class.egw_link.inc.php @@ -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)
- * $file array with 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 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); diff --git a/pixelegg/images/to_calendar.png b/pixelegg/images/to_calendar.png new file mode 100644 index 0000000000..50243d717a Binary files /dev/null and b/pixelegg/images/to_calendar.png differ