Overview

Packages

  • IMP

Classes

  • IMP
  • IMP_Ajax_Addresses
  • IMP_Ajax_Application
  • IMP_Ajax_Application_Compose
  • IMP_Ajax_Application_Handler_Common
  • IMP_Ajax_Application_Handler_ComposeAttach
  • IMP_Ajax_Application_Handler_Draft
  • IMP_Ajax_Application_Handler_Dynamic
  • IMP_Ajax_Application_Handler_ImageUnblock
  • IMP_Ajax_Application_Handler_Mboxtoggle
  • IMP_Ajax_Application_Handler_Passphrase
  • IMP_Ajax_Application_Handler_Remote
  • IMP_Ajax_Application_Handler_RemotePrefs
  • IMP_Ajax_Application_Handler_Search
  • IMP_Ajax_Application_Handler_Smartmobile
  • IMP_Ajax_Application_ListMessages
  • IMP_Ajax_Application_ShowMessage
  • IMP_Ajax_Application_Viewport
  • IMP_Ajax_Application_Viewport_Error
  • IMP_Ajax_Imple_ImportEncryptKey
  • IMP_Ajax_Imple_ItipRequest
  • IMP_Ajax_Imple_PassphraseDialog
  • IMP_Ajax_Imple_VcardImport
  • IMP_Ajax_Queue
  • IMP_Api
  • IMP_Application
  • IMP_Auth
  • IMP_Basic_Base
  • IMP_Basic_Compose
  • IMP_Basic_Contacts
  • IMP_Basic_Error
  • IMP_Basic_Folders
  • IMP_Basic_Listinfo
  • IMP_Basic_Mailbox
  • IMP_Basic_Message
  • IMP_Basic_Pgp
  • IMP_Basic_Saveimage
  • IMP_Basic_Search
  • IMP_Basic_Searchbasic
  • IMP_Basic_Smime
  • IMP_Basic_Thread
  • IMP_Block_Newmail
  • IMP_Block_Summary
  • IMP_Compose
  • IMP_Compose_Attachment
  • IMP_Compose_Attachment_Linked_Metadata
  • IMP_Compose_Attachment_Metadata
  • IMP_Compose_Attachment_Storage
  • IMP_Compose_Attachment_Storage_AutoDetermine
  • IMP_Compose_Attachment_Storage_Temp
  • IMP_Compose_Attachment_Storage_VfsLinked
  • IMP_Compose_Exception
  • IMP_Compose_Exception_Address
  • IMP_Compose_HtmlSignature
  • IMP_Compose_Link
  • IMP_Compose_LinkedAttachment
  • IMP_Compose_Ui
  • IMP_Compose_View
  • IMP_Contacts
  • IMP_Contacts_Avatar_Addressbook
  • IMP_Contacts_Avatar_Gravatar
  • IMP_Contacts_Avatar_Unknown
  • IMP_Contacts_Flag_Host
  • IMP_Contacts_Image
  • IMP_Contents
  • IMP_Contents_InlineOutput
  • IMP_Contents_View
  • IMP_Crypt_Pgp
  • IMP_Crypt_Smime
  • IMP_Dynamic_AddressList
  • IMP_Dynamic_Base
  • IMP_Dynamic_Compose
  • IMP_Dynamic_Compose_Common
  • IMP_Dynamic_Helper_Base
  • IMP_Dynamic_Mailbox
  • IMP_Dynamic_Message
  • IMP_Exception
  • IMP_Factory_AuthImap
  • IMP_Factory_Compose
  • IMP_Factory_ComposeAtc
  • IMP_Factory_Contacts
  • IMP_Factory_Contents
  • IMP_Factory_Flags
  • IMP_Factory_Ftree
  • IMP_Factory_Identity
  • IMP_Factory_Imap
  • IMP_Factory_Mail
  • IMP_Factory_MailAutoconfig
  • IMP_Factory_Mailbox
  • IMP_Factory_MailboxCache
  • IMP_Factory_MailboxList
  • IMP_Factory_Maillog
  • IMP_Factory_MimeViewer
  • IMP_Factory_Pgp
  • IMP_Factory_PrefsSort
  • IMP_Factory_Quota
  • IMP_Factory_Search
  • IMP_Factory_Sentmail
  • IMP_Factory_Smime
  • IMP_Factory_Spam
  • IMP_Filter
  • IMP_Flag_Base
  • IMP_Flag_Imap
  • IMP_Flag_Imap_Answered
  • IMP_Flag_Imap_Deleted
  • IMP_Flag_Imap_Draft
  • IMP_Flag_Imap_Flagged
  • IMP_Flag_Imap_Forwarded
  • IMP_Flag_Imap_Junk
  • IMP_Flag_Imap_NotJunk
  • IMP_Flag_Imap_Seen
  • IMP_Flag_System_Attachment
  • IMP_Flag_System_Encrypted
  • IMP_Flag_System_HighPriority
  • IMP_Flag_System_List
  • IMP_Flag_System_LowPriority
  • IMP_Flag_System_Match_Address
  • IMP_Flag_System_Match_Flag
  • IMP_Flag_System_Match_Header
  • IMP_Flag_System_Personal
  • IMP_Flag_System_Signed
  • IMP_Flag_System_Unseen
  • IMP_Flag_User
  • IMP_Flags
  • IMP_Ftree
  • IMP_Ftree_Account
  • IMP_Ftree_Account_Imap
  • IMP_Ftree_Account_Inboxonly
  • IMP_Ftree_Account_Remote
  • IMP_Ftree_Account_Vfolder
  • IMP_Ftree_Element
  • IMP_Ftree_Eltdiff
  • IMP_Ftree_Iterator
  • IMP_Ftree_Iterator_Ancestors
  • IMP_Ftree_IteratorFilter
  • IMP_Ftree_IteratorFilter_Children
  • IMP_Ftree_IteratorFilter_Containers
  • IMP_Ftree_IteratorFilter_Expanded
  • IMP_Ftree_IteratorFilter_Invisible
  • IMP_Ftree_IteratorFilter_Mailboxes
  • IMP_Ftree_IteratorFilter_Nonimap
  • IMP_Ftree_IteratorFilter_Polled
  • IMP_Ftree_IteratorFilter_Remote
  • IMP_Ftree_IteratorFilter_Special
  • IMP_Ftree_IteratorFilter_Subscribed
  • IMP_Ftree_IteratorFilter_Vfolder
  • IMP_Ftree_Prefs
  • IMP_Ftree_Prefs_Expanded
  • IMP_Ftree_Prefs_Poll
  • IMP_Ftree_Select
  • IMP_Images
  • IMP_Imap
  • IMP_Imap_Acl
  • IMP_Imap_Cache_Wrapper
  • IMP_Imap_Config
  • IMP_Imap_Exception
  • IMP_Imap_Password
  • IMP_Imap_PermanentFlags
  • IMP_Imap_Remote
  • IMP_Indices
  • IMP_Indices_Mailbox
  • IMP_LoginTasks_SystemTask_GarbageCollection
  • IMP_LoginTasks_SystemTask_Upgrade
  • IMP_LoginTasks_SystemTask_UpgradeAuth
  • IMP_LoginTasks_Task_Autocreate
  • IMP_LoginTasks_Task_DeleteAttachmentsMonthly
  • IMP_LoginTasks_Task_DeleteSentmailMonthly
  • IMP_LoginTasks_Task_FilterOnLogin
  • IMP_LoginTasks_Task_PurgeSentmail
  • IMP_LoginTasks_Task_PurgeSpam
  • IMP_LoginTasks_Task_PurgeTrash
  • IMP_LoginTasks_Task_RecoverDraft
  • IMP_LoginTasks_Task_RenameSentmailMonthly
  • IMP_Mailbox
  • IMP_Mailbox_List
  • IMP_Mailbox_List_Pop3
  • IMP_Mailbox_List_Thread
  • IMP_Mailbox_List_Virtual
  • IMP_Mailbox_SessionCache
  • IMP_Mailbox_Ui
  • IMP_Maillog
  • IMP_Maillog_Log_Base
  • IMP_Maillog_Log_Forward
  • IMP_Maillog_Log_Mdn
  • IMP_Maillog_Log_Redirect
  • IMP_Maillog_Log_Reply
  • IMP_Maillog_Log_Replyall
  • IMP_Maillog_Log_Replylist
  • IMP_Maillog_Message
  • IMP_Maillog_Storage_Base
  • IMP_Maillog_Storage_Composite
  • IMP_Maillog_Storage_History
  • IMP_Maillog_Storage_Mdnsent
  • IMP_Maillog_Storage_Null
  • IMP_Mbox_Generate
  • IMP_Mbox_Import
  • IMP_Mbox_Size
  • IMP_Message
  • IMP_Message_Date
  • IMP_Message_Ui
  • IMP_Mime_Headers
  • IMP_Mime_Status
  • IMP_Mime_Status_RenderIssue
  • IMP_Mime_Status_RenderIssue_Display
  • IMP_Mime_Viewer_Alternative
  • IMP_Mime_Viewer_Appledouble
  • IMP_Mime_Viewer_Audio
  • IMP_Mime_Viewer_Enriched
  • IMP_Mime_Viewer_Externalbody
  • IMP_Mime_Viewer_Html
  • IMP_Mime_Viewer_Images
  • IMP_Mime_Viewer_Itip
  • IMP_Mime_Viewer_Mdn
  • IMP_Mime_Viewer_Partial
  • IMP_Mime_Viewer_Pdf
  • IMP_Mime_Viewer_Pgp
  • IMP_Mime_Viewer_Plain
  • IMP_Mime_Viewer_Related
  • IMP_Mime_Viewer_Rfc822
  • IMP_Mime_Viewer_Smil
  • IMP_Mime_Viewer_Smime
  • IMP_Mime_Viewer_Status
  • IMP_Mime_Viewer_Vcard
  • IMP_Mime_Viewer_Video
  • IMP_Mime_Viewer_Zip
  • IMP_Minimal_Base
  • IMP_Minimal_Compose
  • IMP_Minimal_Error
  • IMP_Minimal_Folders
  • IMP_Minimal_Mailbox
  • IMP_Minimal_Message
  • IMP_Minimal_Messagepart
  • IMP_Minimal_Search
  • IMP_Notification_Event_Status
  • IMP_Notification_Handler_Decorator_ImapAlerts
  • IMP_Notification_Handler_Decorator_NewmailNotify
  • IMP_Perms
  • IMP_Prefs_AttribText
  • IMP_Prefs_Identity
  • IMP_Prefs_Sort
  • IMP_Prefs_Sort_FixedDate
  • IMP_Prefs_Sort_None
  • IMP_Prefs_Sort_Sortpref
  • IMP_Prefs_Sort_Sortpref_Locked
  • IMP_Prefs_Special_Acl
  • IMP_Prefs_Special_ComposeTemplates
  • IMP_Prefs_Special_Drafts
  • IMP_Prefs_Special_Encrypt
  • IMP_Prefs_Special_Flag
  • IMP_Prefs_Special_HtmlSignature
  • IMP_Prefs_Special_ImageReplacement
  • IMP_Prefs_Special_InitialPage
  • IMP_Prefs_Special_Mailto
  • IMP_Prefs_Special_NewmailSound
  • IMP_Prefs_Special_PgpPrivateKey
  • IMP_Prefs_Special_PgpPublicKey
  • IMP_Prefs_Special_Remote
  • IMP_Prefs_Special_Searches
  • IMP_Prefs_Special_Sentmail
  • IMP_Prefs_Special_SmimePrivateKey
  • IMP_Prefs_Special_SmimePublicKey
  • IMP_Prefs_Special_Sourceselect
  • IMP_Prefs_Special_Spam
  • IMP_Prefs_Special_SpecialMboxes
  • IMP_Prefs_Special_Trash
  • IMP_Quota
  • IMP_Quota_Hook
  • IMP_Quota_Imap
  • IMP_Quota_Null
  • IMP_Quota_Ui
  • IMP_Remote
  • IMP_Remote_Account
  • IMP_Script_Package_Autocomplete
  • IMP_Script_Package_ComposeBase
  • IMP_Script_Package_DynamicBase
  • IMP_Script_Package_Editor
  • IMP_Script_Package_Imp
  • IMP_Search
  • IMP_Search_Element
  • IMP_Search_Element_Attachment
  • IMP_Search_Element_Autogenerated
  • IMP_Search_Element_Bulk
  • IMP_Search_Element_Contacts
  • IMP_Search_Element_Daterange
  • IMP_Search_Element_Flag
  • IMP_Search_Element_Header
  • IMP_Search_Element_Mailinglist
  • IMP_Search_Element_Or
  • IMP_Search_Element_Personal
  • IMP_Search_Element_Recipient
  • IMP_Search_Element_Size
  • IMP_Search_Element_Text
  • IMP_Search_Element_Within
  • IMP_Search_Filter
  • IMP_Search_Filter_Attachment
  • IMP_Search_Filter_Autogenerated
  • IMP_Search_Filter_Builtin
  • IMP_Search_Filter_Bulk
  • IMP_Search_Filter_Contacts
  • IMP_Search_Filter_Mailinglist
  • IMP_Search_Filter_Personal
  • IMP_Search_IteratorFilter
  • IMP_Search_Query
  • IMP_Search_Ui
  • IMP_Search_Vfolder
  • IMP_Search_Vfolder_Builtin
  • IMP_Search_Vfolder_Vinbox
  • IMP_Search_Vfolder_Vtrash
  • IMP_Sentmail
  • IMP_Sentmail_Mongo
  • IMP_Sentmail_Null
  • IMP_Sentmail_Sql
  • IMP_Smartmobile
  • IMP_Spam
  • IMP_Spam_Email
  • IMP_Spam_Null
  • IMP_Spam_Program
  • IMP_Test
  • IMP_Tree_Flist
  • IMP_Tree_Jquerymobile
  • IMP_Tree_Simplehtml
  • IMP_View_Subinfo

Interfaces

  • IMP_Compose_Attachment_Linked
  • IMP_Contacts_Avatar_Backend
  • IMP_Contacts_Flag_Backend
  • IMP_Spam_Base
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Copyright 2002-2014 Horde LLC (http://www.horde.org/)
  4:  *
  5:  * See the enclosed file COPYING for license information (GPL). If you
  6:  * did not receive this file, see http://www.horde.org/licenses/gpl.
  7:  *
  8:  * @category  Horde
  9:  * @copyright 2002-2014 Horde LLC
 10:  * @license   http://www.horde.org/licenses/gpl GPL
 11:  * @package   IMP
 12:  */
 13: 
 14: /**
 15:  * Displays vCalendar/iCalendar data and provides an option to import the data
 16:  * into a calendar source, if available.
 17:  *
 18:  * @author    Mike Cochrane <mike@graftonhall.co.nz>
 19:  * @author    Chuck Hagenbuch <chuck@horde.org>
 20:  * @author    Michael Slusarz <slusarz@horde.org>
 21:  * @author    Gunnar Wrobel <wrobel@pardus.de>
 22:  * @category  Horde
 23:  * @copyright 2002-2014 Horde LLC
 24:  * @license   http://www.horde.org/licenses/gpl GPL
 25:  * @package   IMP
 26:  */
 27: class IMP_Mime_Viewer_Itip extends Horde_Mime_Viewer_Base
 28: {
 29:     /**
 30:      * This driver's display capabilities.
 31:      *
 32:      * @var array
 33:      */
 34:     protected $_capability = array(
 35:         'full' => true,
 36:         'info' => false,
 37:         'inline' => true,
 38:         'raw' => false
 39:     );
 40: 
 41:     /**
 42:      * Metadata for the current viewer/data.
 43:      *
 44:      * @var array
 45:      */
 46:     protected $_metadata = array(
 47:         'compressed' => false,
 48:         'embedded' => false,
 49:         'forceinline' => true
 50:     );
 51: 
 52:     /**
 53:      * Return the full rendered version of the Horde_Mime_Part object.
 54:      *
 55:      * @return array  See parent::render().
 56:      */
 57:     protected function _render()
 58:     {
 59:         global $page_output;
 60: 
 61:         $ret = $this->_renderInline();
 62: 
 63:         if (!empty($ret)) {
 64:             reset($ret);
 65:             $page_output->topbar = $page_output->sidebar = false;
 66:             $mimecss = new Horde_Themes_Element('mime.css');
 67:             $page_output->addStylesheet($mimecss->fs, $mimecss->uri);
 68:             Horde::startBuffer();
 69:             $page_output->header(array(
 70:                 'html_id' => 'htmlAllowScroll'
 71:             ));
 72:             echo $ret[key($ret)]['data'];
 73:             $page_output->footer();
 74:             $ret[key($ret)]['data'] = Horde::endBuffer();
 75:         }
 76: 
 77:         return $ret;
 78:     }
 79: 
 80:     /**
 81:      * Return the rendered inline version of the Horde_Mime_Part object.
 82:      *
 83:      * @return array  See parent::render().
 84:      */
 85:     protected function _renderInline()
 86:     {
 87:         $GLOBALS['page_output']->growler = true;
 88:         $data = $this->_mimepart->getContents();
 89:         $mime_id = $this->_mimepart->getMimeId();
 90: 
 91:         // Parse the iCal file.
 92:         $vCal = new Horde_Icalendar();
 93:         if (!$vCal->parsevCalendar($data, 'VCALENDAR', $this->_mimepart->getCharset())) {
 94:             $status = new IMP_Mime_Status(_("The calendar data is invalid"));
 95:             $status->action(IMP_Mime_Status::ERROR);
 96:             return array(
 97:                 $mime_id => array(
 98:                     'data' => '',
 99:                     'status' => $status,
100:                     'type' => 'text/html; charset=UTF-8'
101:                 )
102:             );
103:         }
104: 
105:         // Check if we got vcard data with the wrong vcalendar mime type.
106:         $imp_contents = $this->getConfigParam('imp_contents');
107:         $c = $vCal->getComponentClasses();
108:         if ((count($c) == 1) && !empty($c['horde_icalendar_vcard'])) {
109:             return $imp_contents->renderMIMEPart($mime_id, IMP_Contents::RENDER_INLINE, array('type' => 'text/x-vcard'));
110:         }
111: 
112:         $imple = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Imple')->create('IMP_Ajax_Imple_ItipRequest', array(
113:             'mime_id' => $mime_id,
114:             'muid' => strval($imp_contents->getIndicesOb())
115:         ));
116: 
117:         // Get the method type.
118:         try {
119:             $method = $vCal->getAttribute('METHOD');
120:         } catch (Horde_Icalendar_Exception $e) {
121:             $method = '';
122:         }
123: 
124:         $out = array();
125:         $components = $vCal->getComponents();
126:         foreach ($components as $key => $component) {
127:             switch ($component->getType()) {
128:             case 'vEvent':
129:                 try {
130:                     if ($component->getAttribute('RECURRENCE-ID')) {
131:                         break;
132:                     }
133:                 } catch (Horde_ICalendar_Exception $e) {}
134:                 $out[] = $this->_vEvent($component, $key, $method, $components);
135:                 break;
136: 
137:             case 'vTodo':
138:                 $out[] = $this->_vTodo($component, $key, $method);
139:                 break;
140: 
141:             case 'vTimeZone':
142:                 // Ignore them.
143:                 break;
144: 
145:             case 'vFreebusy':
146:                 $out[] = $this->_vFreebusy($component, $key, $method);
147:                 break;
148: 
149:             // @todo: handle stray vcards here as well.
150:             default:
151:                 $out[] = sprintf(_("Unhandled component of type: %s"), $component->getType());
152:                 break;
153:             }
154:         }
155: 
156:         $view = $this->_getViewOb();
157:         $view->formid = $imple->getDomId();
158:         $view->out = implode('', $out);
159: 
160:         return array(
161:             $mime_id => array(
162:                 'data' => $view->render('base'),
163:                 'type' => 'text/html; charset=UTF-8'
164:             )
165:         );
166:     }
167: 
168:     /**
169:      * Generate the html for a vFreebusy.
170:      */
171:     protected function _vFreebusy($vfb, $id, $method)
172:     {
173:         global $notification, $prefs, $registry;
174: 
175:         $desc = '';
176:         $sender = $vfb->getName();
177: 
178:         switch ($method) {
179:         case 'PUBLISH':
180:             $desc = _("%s has sent you free/busy information.");
181:             break;
182: 
183:         case 'REQUEST':
184:             $sender = $this->getConfigParam('imp_contents')->getHeader()->getValue('From');
185:             $desc = _("%s requests your free/busy information.");
186:             break;
187: 
188:         case 'REPLY':
189:             $desc = _("%s has replied to a free/busy request.");
190:             break;
191:         }
192: 
193:         $view = $this->_getViewOb();
194:         $view->desc = sprintf($desc, $sender);
195: 
196:         try {
197:             $start = $vfb->getAttribute('DTSTART');
198:             $view->start = is_array($start)
199:                 ? strftime($prefs->getValue('date_format'), mktime(0, 0, 0, $start['month'], $start['mday'], $start['year']))
200:                 : strftime($prefs->getValue('date_format'), $start) . ' ' . date($prefs->getValue('twentyFour') ? ' G:i' : ' g:i a', $start);
201:         } catch (Horde_Icalendar_Exception $e) {}
202: 
203:         try {
204:             $end = $vfb->getAttribute('DTEND');
205:             $view->end = is_array($end)
206:                 ? strftime($prefs->getValue('date_format'), mktime(0, 0, 0, $end['month'], $end['mday'], $end['year']))
207:                 : strftime($prefs->getValue('date_format'), $end) . ' ' . date($prefs->getValue('twentyFour') ? ' G:i' : ' g:i a', $end);
208:         } catch (Horde_Icalendar_Exception $e) {}
209: 
210:         $options = array();
211:         switch ($method) {
212:         case 'PUBLISH':
213:         case 'REPLY':
214:             if ($registry->hasMethod('calendar/import_vfreebusy')) {
215:                 if ($this->_autoUpdateReply(($method == 'PUBLISH') ? 'auto_update_fbpublish' : 'auto_update_fbreply', $sender)) {
216:                     try {
217:                         $registry->call('calendar/import_vfreebusy', array($vfb));
218:                         $notification->push(_("The user's free/busy information was sucessfully stored."), 'horde.success');
219:                     } catch (Horde_Exception $e) {
220:                         $notification->push(sprintf(_("There was an error importing user's free/busy information: %s"), $e->getMessage()), 'horde.error');
221:                     }
222:                 } else {
223:                     $options['import'] = _("Remember the free/busy information.");
224:                 }
225:             } else {
226:                 $options['nosup'] = _("Reply with Not Supported Message");
227:             }
228:             break;
229: 
230:         case 'REQUEST':
231:             if ($registry->hasMethod('calendar/getFreeBusy')) {
232:                 $options['reply'] = _("Reply with requested free/busy information.");
233:                 $options['reply2m'] = _("Reply with free/busy for next 2 months.");
234:             } else {
235:                 $options['nosup'] = _("Reply with Not Supported Message");
236:             }
237: 
238:             $options['deny'] = _("Deny request for free/busy information");
239:             break;
240:         }
241: 
242:         if (!empty($options)) {
243:             reset($options);
244:             $view->options = $options;
245:             $view->options_id = $id;
246:         }
247: 
248:         return $view->render('action');
249:     }
250: 
251:     /**
252:      * Generate the HTML for a vEvent.
253:      */
254:     protected function _vEvent($vevent, $id, $method = 'PUBLISH', $components = array())
255:     {
256:         global $injector, $prefs, $registry, $notification;
257: 
258:         $attendees = null;
259:         $desc = '';
260:         $sender = $vevent->organizerName();
261:         $options = array();
262: 
263:         try {
264:             if (($attendees = $vevent->getAttribute('ATTENDEE')) &&
265:                 !is_array($attendees)) {
266:                 $attendees = array($attendees);
267:             }
268:         } catch (Horde_Icalendar_Exception $e) {}
269: 
270:         switch ($method) {
271:         case 'PUBLISH':
272:             $desc = _("%s wishes to make you aware of \"%s\".");
273:             if ($registry->hasMethod('calendar/import')) {
274:                 $options['import'] = _("Add this to my calendar");
275:             }
276:             break;
277: 
278:         case 'REQUEST':
279:             // Check if this is an update.
280:             try {
281:                 $registry->call('calendar/export', array($vevent->getAttribute('UID'), 'text/calendar'));
282:                 $desc = _("%s wants to notify you about changes in \"%s\".");
283:                 $is_update = true;
284:             } catch (Horde_Exception $e) {
285:                 $desc = _("%s wishes to make you aware of \"%s\".");
286:                 $is_update = false;
287: 
288:                 // Check that you are one of the attendees here.
289:                 if (!empty($attendees)) {
290:                     $identity = $injector->getInstance('IMP_Identity');
291:                     for ($i = 0, $c = count($attendees); $i < $c; ++$i) {
292:                         $attendee = parse_url($attendees[$i]);
293:                         if (!empty($attendee['path']) &&
294:                             $identity->hasAddress($attendee['path'])) {
295:                             $desc = _("%s requests your presence at \"%s\".");
296:                             break;
297:                         }
298:                     }
299:                 }
300:             }
301: 
302:             if ($is_update && $registry->hasMethod('calendar/replace')) {
303:                 $options['accept-import'] = _("Accept and update in my calendar");
304:                 $options['import'] = _("Update in my calendar");
305:             } elseif ($registry->hasMethod('calendar/import')) {
306:                 $options['accept-import'] = _("Accept and add to my calendar");
307:                 $options['import'] = _("Add to my calendar");
308:             }
309: 
310:             $options['accept'] = _("Accept request");
311:             $options['tentative'] = _("Tentatively Accept request");
312:             $options['deny'] = _("Deny request");
313:             // $options['delegate'] = _("Delegate position");
314:             break;
315: 
316:         case 'ADD':
317:             $desc = _("%s wishes to amend \"%s\".");
318:             if ($registry->hasMethod('calendar/import')) {
319:                 $options['import'] = _("Update this event on my calendar");
320:             }
321:             break;
322: 
323:         case 'REFRESH':
324:             $desc = _("%s wishes to receive the latest information about \"%s\".");
325:             $options['send'] = _("Send Latest Information");
326:             break;
327: 
328:         case 'REPLY':
329:             $desc = _("%s has replied to the invitation to \"%s\".");
330:             $sender_ob = $this->getConfigParam('imp_contents')->getHeader()->getOb('From');
331:             $sender = $sender_ob[0]->bare_address;
332:             if ($registry->hasMethod('calendar/updateAttendee') &&
333:                 $this->_autoUpdateReply('auto_update_eventreply', $sender)) {
334:                 try {
335:                     $registry->call('calendar/updateAttendee', array(
336:                         $vevent,
337:                         $sender
338:                     ));
339:                     $notification->push(_("Respondent Status Updated."), 'horde.success');
340:                 } catch (Horde_Exception $e) {
341:                     $notification->push(sprintf(_("There was an error updating the event: %s"), $e->getMessage()), 'horde.error');
342:                 }
343:             } else {
344:                 $options['update'] = _("Update respondent status");
345:             }
346:             break;
347: 
348:         case 'CANCEL':
349:             try {
350:                 $vevent->getAttribute('RECURRENCE-ID');
351:                 $params = $vevent->getAttribute('RECURRENCE-ID', true);
352:                 foreach ($params as $param) {
353:                     if (array_key_exists('RANGE', $param)) {
354:                         $desc = _("%s has cancelled multiple instances of the recurring \"%s\".");
355:                     }
356:                     break;
357:                 }
358:                 if (empty($desc)) {
359:                     $desc = _("%s has cancelled an instance of the recurring \"%s\".");
360:                 }
361:                 if ($registry->hasMethod('calendar/replace')) {
362:                     $options['delete'] = _("Update in my calendar");
363:                 }
364:             } catch (Horde_Icalendar_Exception $e) {
365:                 $desc = _("%s has cancelled \"%s\".");
366:                 if ($registry->hasMethod('calendar/delete')) {
367:                     $options['delete'] = _("Delete from my calendar");
368:                 }
369:             }
370:             break;
371:         }
372: 
373:         $view = $this->_getViewOb();
374: 
375:         try {
376:             $start = $vevent->getAttribute('DTSTART');
377:             $view->start = is_array($start)
378:                 ? strftime($prefs->getValue('date_format'), mktime(0, 0, 0, $start['month'], $start['mday'], $start['year']))
379:                 : strftime($prefs->getValue('date_format'), $start) . ' ' . date($prefs->getValue('twentyFour') ? ' G:i' : ' g:i a', $start);
380:         } catch (Horde_Icalendar_Exception $e) {
381:             $start = null;
382:         }
383: 
384:         try {
385:             $end = $vevent->getAttribute('DTEND');
386:             $view->end = is_array($end)
387:                 ? strftime($prefs->getValue('date_format'), mktime(0, 0, 0, $end['month'], $end['mday'], $end['year']))
388:                 : strftime($prefs->getValue('date_format'), $end) . ' ' . date($prefs->getValue('twentyFour') ? ' G:i' : ' g:i a', $end);
389:         } catch (Horde_Icalendar_Exception $e) {
390:             $end = null;
391:         }
392: 
393:         try {
394:             $summary = $vevent->getAttribute('SUMMARY');
395:             $view->summary = $summary;
396:         } catch (Horde_Icalendar_Exception $e) {
397:             $summary = _("Unknown Meeting");
398:             $view->summary_error = _("None");
399:         }
400: 
401:         $view->desc = sprintf($desc, $sender, $summary);
402: 
403:         try {
404:             $view->desc2 = $vevent->getAttribute('DESCRIPTION');
405:         } catch (Horde_Icalendar_Exception $e) {}
406: 
407:         try {
408:             $view->loc = $vevent->getAttribute('LOCATION');
409:         } catch (Horde_Icalendar_Exception $e) {}
410: 
411:         try {
412:             $rrule = $vevent->getAttribute('RRULE');
413:         } catch (Horde_Icalendar_Exception $e) {
414:             $rrule = array();
415:         }
416:         if (!is_array($rrule)) {
417:             $recurrence = new Horde_Date_Recurrence(new Horde_Date($view->start));
418:             if (strpos($rrule, '=') !== false) {
419:                 $recurrence->fromRRule20($rrule);
420:             } else {
421:                 $recurrence->fromRRule10($rrule);
422:             }
423: 
424:             // Add exceptions
425:             try {
426:                 $exdates = $vevent->getAttributeValues('EXDATE');
427:                 if (is_array($exdates)) {
428:                     foreach ($exdates as $exdate) {
429:                         if (is_array($exdate)) {
430:                             $recurrence->addException(
431:                                 (int)$exdate['year'],
432:                                 (int)$exdate['month'],
433:                                 (int)$exdate['mday']);
434:                         }
435:                     }
436:                 }
437:             } catch (Horde_ICalendar_Exception $e) {}
438: 
439:             $view->recurrence = $recurrence->toString($prefs->getValue('date_format'));
440:             $view->exceptions = array();
441:             foreach ($components as $key => $component) {
442:                 try {
443:                     if ($component->getAttribute('RECURRENCE-ID') && $component->getAttribute('UID') == $vevent->getAttribute('UID')) {
444:                         if ($ex = $this->_vEventException($component, $key, $method)) {
445:                             $view->exceptions[] = $ex;
446:                         }
447:                     }
448:                 } catch (Horde_Icalendar_Exception $e) {}
449:             }
450:         }
451: 
452:         if (!empty($attendees)) {
453:             $view->attendees = $this->_parseAttendees($vevent, $attendees);
454:         }
455: 
456:         if (!is_null($start) &&
457:             !is_null($end) &&
458:             in_array($method, array('PUBLISH', 'REQUEST', 'ADD')) &&
459:             $registry->hasMethod('calendar/getFbCalendars') &&
460:             $registry->hasMethod('calendar/listEvents')) {
461:             try {
462:                 $calendars = $registry->call('calendar/getFbCalendars');
463: 
464:                 $vevent_start = new Horde_Date($start);
465:                 $vevent_end = new Horde_Date($end);
466: 
467:                 // Check if it's an all-day event.
468:                 if (is_array($start)) {
469:                     $vevent_allDay = true;
470:                     $vevent_end = $vevent_end->sub(1);
471:                 } else {
472:                     $vevent_allDay = false;
473:                     $time_span_start = $vevent_start->sub($prefs->getValue('conflict_interval') * 60);
474:                     $time_span_end = $vevent_end->add($prefs->getValue('conflict_interval') * 60);
475:                 }
476: 
477:                 $events = $registry->call('calendar/listEvents', array($start, $vevent_end, $calendars, false));
478: 
479:                 // TODO: Check if there are too many events to show.
480:                 $conflicts = array();
481:                 foreach ($events as $calendar) {
482:                     foreach ($calendar as $event) {
483:                         // TODO: WTF? Why are we using Kronolith constants
484:                         // here?
485:                         if (in_array($event->status, array(Kronolith::STATUS_CANCELLED, Kronolith::STATUS_FREE))) {
486:                             continue;
487:                         }
488: 
489:                         if ($vevent_allDay || $event->isAllDay()) {
490:                             $type = 'collision';
491:                         } elseif (($event->end->compareDateTime($time_span_start) <= -1) ||
492:                                 ($event->start->compareDateTime($time_span_end) >= 1)) {
493:                             continue;
494:                         } elseif (($event->end->compareDateTime($vevent_start) <= -1) ||
495:                                   ($event->start->compareDateTime($vevent_end) >= 1)) {
496:                             $type = 'nearcollision';
497:                         } else {
498:                             $type = 'collision';
499:                         }
500: 
501:                         $conflicts[] = array(
502:                             'collision' => ($type == 'collision'),
503:                             'range' => $event->getTimeRange(),
504:                             'title' => $event->getTitle()
505:                         );
506:                     }
507:                 }
508: 
509:                 if (!empty($conflicts)) {
510:                     $view->conflicts = $conflicts;
511:                 }
512:             } catch (Horde_Exception $e) {}
513:         }
514: 
515:         if (!empty($options)) {
516:             reset($options);
517:             $view->options = $options;
518:             $view->options_id = $id;
519:         }
520: 
521:         return $view->render('action');
522:     }
523: 
524:     /**
525:      * Generate the HTML for a vEvent.
526:      */
527:     protected function _vEventException($vevent, $id, $method = 'PUBLISH')
528:     {
529:         global $prefs, $registry;
530: 
531:         $attendees = null;
532:         $options = array();
533: 
534:         try {
535:             if (($attendees = $vevent->getAttribute('ATTENDEE')) &&
536:                 !is_array($attendees)) {
537:                 $attendees = array($attendees);
538:             }
539:         } catch (Horde_Icalendar_Exception $e) {}
540: 
541:         $view = $this->_getViewOb();
542: 
543:         try {
544:             $start = $vevent->getAttribute('DTSTART');
545:             $view->start = is_array($start)
546:                 ? strftime($prefs->getValue('date_format'), mktime(0, 0, 0, $start['month'], $start['mday'], $start['year']))
547:                 : strftime($prefs->getValue('date_format'), $start) . ' ' . date($prefs->getValue('twentyFour') ? ' G:i' : ' g:i a', $start);
548:         } catch (Horde_Icalendar_Exception $e) {
549:             $start = null;
550:         }
551: 
552:         try {
553:             $end = $vevent->getAttribute('DTEND');
554:             // Check for exceptions that are over and done with.
555:             $d = new Horde_Date($end);
556:             if ($d->timestamp() < time()) {
557:                 return false;
558:             }
559:             $view->end = is_array($end)
560:                 ? strftime($prefs->getValue('date_format'), mktime(0, 0, 0, $end['month'], $end['mday'], $end['year']))
561:                 : strftime($prefs->getValue('date_format'), $end) . ' ' . date($prefs->getValue('twentyFour') ? ' G:i' : ' g:i a', $end);
562:         } catch (Horde_Icalendar_Exception $e) {
563:             $end = null;
564:         }
565: 
566:         try {
567:             $summary = $vevent->getAttribute('SUMMARY');
568:             $view->summary = $summary;
569:         } catch (Horde_Icalendar_Exception $e) {
570:             $summary = _("Unknown Meeting");
571:             $view->summary_error = _("None");
572:         }
573: 
574:         try {
575:             $view->desc2 = $vevent->getAttribute('DESCRIPTION');
576:         } catch (Horde_Icalendar_Exception $e) {}
577: 
578:         try {
579:             $view->loc = $vevent->getAttribute('LOCATION');
580:         } catch (Horde_Icalendar_Exception $e) {}
581: 
582:         if (!empty($attendees)) {
583:             $view->attendees = $this->_parseAttendees($vevent, $attendees);
584:         }
585: 
586:         if (!is_null($start) &&
587:             !is_null($end) &&
588:             in_array($method, array('PUBLISH', 'REQUEST', 'ADD')) &&
589:             $registry->hasMethod('calendar/getFbCalendars') &&
590:             $registry->hasMethod('calendar/listEvents')) {
591:             try {
592:                 $calendars = $registry->call('calendar/getFbCalendars');
593:                 $vevent_start = new Horde_Date($start);
594:                 $vevent_end = new Horde_Date($end);
595: 
596:                 // Check if it's an all-day event.
597:                 if (is_array($start)) {
598:                     $vevent_allDay = true;
599:                     $vevent_end = $vevent_end->sub(1);
600:                 } else {
601:                     $vevent_allDay = false;
602:                     $time_span_start = $vevent_start->sub($prefs->getValue('conflict_interval') * 60);
603:                     $time_span_end = $vevent_end->add($prefs->getValue('conflict_interval') * 60);
604:                 }
605: 
606:                 $events = $registry->call('calendar/listEvents', array($start, $vevent_end, $calendars, false));
607: 
608:                 // TODO: Check if there are too many events to show.
609:                 $conflicts = array();
610:                 foreach ($events as $calendar) {
611:                     foreach ($calendar as $event) {
612:                         // TODO: WTF? Why are we using Kronolith constants
613:                         // here?
614:                         if (in_array($event->status, array(Kronolith::STATUS_CANCELLED, Kronolith::STATUS_FREE))) {
615:                             continue;
616:                         }
617: 
618:                         if ($vevent_allDay || $event->isAllDay()) {
619:                             $type = 'collision';
620:                         } elseif (($event->end->compareDateTime($time_span_start) <= -1) ||
621:                                 ($event->start->compareDateTime($time_span_end) >= 1)) {
622:                             continue;
623:                         } elseif (($event->end->compareDateTime($vevent_start) <= -1) ||
624:                                   ($event->start->compareDateTime($vevent_end) >= 1)) {
625:                             $type = 'nearcollision';
626:                         } else {
627:                             $type = 'collision';
628:                         }
629: 
630:                         $conflicts[] = array(
631:                             'collision' => ($type == 'collision'),
632:                             'range' => $event->getTimeRange(),
633:                             'title' => $event->getTitle()
634:                         );
635:                     }
636:                 }
637: 
638:                 if (!empty($conflicts)) {
639:                     $view->conflicts = $conflicts;
640:                 }
641:             } catch (Horde_Exception $e) {}
642:         }
643: 
644:         if (!empty($options)) {
645:             reset($options);
646:             $view->options = $options;
647:             $view->options_id = $id;
648:         }
649: 
650:         return $view->render('action');
651:     }
652: 
653:     /**
654:      * Generate the html for a vEvent.
655:      */
656:     protected function _vTodo($vtodo, $id, $method)
657:     {
658:         global $registry;
659: 
660:         $desc = '';
661:         $options = array();
662: 
663:         try {
664:             $organizer = $vtodo->getAttribute('ORGANIZER', true);
665:             if (isset($organizer[0]['CN'])) {
666:                 $sender = $organizer[0]['CN'];
667:             } else {
668:                 $organizer = parse_url($vtodo->getAttribute('ORGANIZER'));
669:                 $sender = $organizer['path'];
670:             }
671:         } catch (Horde_Icalendar_Exception $e) {
672:             $sender = _("An unknown person");
673:         }
674: 
675:         switch ($method) {
676:         case 'PUBLISH':
677:             $desc = _("%s wishes to make you aware of \"%s\".");
678:             if ($registry->hasMethod('tasks/import')) {
679:                 $options['import'] = _("Add this to my tasklist");
680:             }
681:             break;
682:         }
683: 
684:         $view = $this->_getViewOb();
685: 
686:         try {
687:             $view->priority = intval($vtodo->getAttribute('PRIORITY'));
688:         } catch (Horde_Icalendar_Exception $e) {}
689: 
690:         try {
691:             $summary = $view->summary = $vtodo->getAttribute('SUMMARY');
692:         } catch (Horde_Icalendar_Exception $e) {
693:             $summary = _("Unknown Task");
694:             $view->summary_error = _("None");
695:         }
696: 
697:         $view->desc = sprintf($desc, $sender, $summary);
698: 
699:         try {
700:             $view->desc2 = $vtodo->getAttribute('DESCRIPTION');
701:         } catch (Horde_Icalendar_Exception $e) {}
702: 
703:         try {
704:             $attendees = $vtodo->getAttribute('ATTENDEE');
705:         } catch (Horde_Icalendar_Exception $e) {
706:             $attendees = null;
707:         }
708: 
709:         if (!empty($attendees)) {
710:             if (!is_array($attendees)) {
711:                 $attendees = array($attendees);
712:             }
713:             $view->attendees = $this->parseAttendees($vtodo, $attendees);
714:         }
715: 
716:         if (!empty($options)) {
717:             reset($options);
718:             $view->options = $options;
719:             $view->options_id = $id;
720:         }
721: 
722:         return $view->render('action');
723:     }
724: 
725:     /**
726:      * Translate the Participation status to string.
727:      *
728:      * @param string $value    The value of PARTSTAT.
729:      * @param string $default  The value to return as default.
730:      *
731:      * @return string   The translated string.
732:      */
733:     protected function _partstatToString($value, $default = null)
734:     {
735:         switch ($value) {
736:         case 'ACCEPTED':
737:             return _("Accepted");
738: 
739:         case 'DECLINED':
740:             return _("Declined");
741: 
742:         case 'TENTATIVE':
743:             return _("Tentatively Accepted");
744: 
745:         case 'DELEGATED':
746:             return _("Delegated");
747: 
748:         case 'COMPLETED':
749:             return _("Completed");
750: 
751:         case 'IN-PROCESS':
752:             return _("In Process");
753: 
754:         case 'NEEDS-ACTION':
755:         default:
756:             return is_null($default)
757:                 ? _("Needs Action")
758:                 : $default;
759:         }
760:     }
761: 
762:     /**
763:      * Get a Horde_View object.
764:      *
765:      * @return Horde_View  View object.
766:      */
767:     protected function _getViewOb()
768:     {
769:         $view = new Horde_View(array(
770:             'templatePath' => IMP_TEMPLATES . '/itip'
771:         ));
772:         $view->addHelper('Text');
773: 
774:         return $view;
775:     }
776: 
777:     /**
778:      */
779:     protected function _parseAttendees($data, $attendees)
780:     {
781:         $params = $data->getAttribute('ATTENDEE', true);
782:         $tmp = array();
783: 
784:         foreach ($attendees as $key => $val) {
785:             if (!empty($params[$key]['CN'])) {
786:                 $attendee = $params[$key]['CN'];
787:             } else {
788:                 $val = parse_url($val);
789:                 $attendee = empty($val['path'])
790:                     ? _("Unknown")
791:                     : $val['path'];
792:             }
793: 
794:             $role = _("Required Participant");
795:             if (isset($params[$key]['ROLE'])) {
796:                 switch ($params[$key]['ROLE']) {
797:                 case 'CHAIR':
798:                     $role = _("Chair Person");
799:                     break;
800: 
801:                 case 'OPT-PARTICIPANT':
802:                     $role = _("Optional Participant");
803:                     break;
804: 
805:                 case 'NON-PARTICIPANT':
806:                     $role = _("Non Participant");
807:                     break;
808: 
809:                 case 'REQ-PARTICIPANT':
810:                 default:
811:                     // Already set above.
812:                     break;
813:                 }
814:             }
815: 
816:             $status = _("Awaiting Response");
817:             if (isset($params[$key]['PARTSTAT'])) {
818:                 $status = $this->_partstatToString($params[$key]['PARTSTAT'], $status);
819:             }
820: 
821:             $tmp[] = array(
822:                 'attendee' => $attendee,
823:                 'role' => $role,
824:                 'status' => $status
825:             );
826:         }
827: 
828:         return $tmp;
829:     }
830: 
831:     /**
832:      */
833:     protected function _autoUpdateReply($type, $sender)
834:     {
835:         if (!empty($this->_conf[$type])) {
836:             if (is_array($this->_conf[$type])) {
837:                 $ob = new Horde_Mail_Rfc822_Address($sender);
838:                 foreach ($this->_conf[$type] as $val) {
839:                     if ($ob->matchDomain($val)) {
840:                         return true;
841:                     }
842:                 }
843:             } else {
844:                 return true;
845:             }
846:         }
847: 
848:         return false;
849:     }
850: 
851: }
852: 
API documentation generated by ApiGen