1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
13:
14: 15: 16: 17: 18: 19: 20: 21: 22:
23: class IMP_Ajax_Imple_ItipRequest extends Horde_Core_Ajax_Imple
24: {
25: 26:
27: protected $_observe = 'submit';
28:
29: 30: 31: 32: 33:
34: public function __construct(array $params = array())
35: {
36: parent::__construct($params);
37: }
38:
39: 40:
41: protected function _attach($init)
42: {
43: return array(
44: 'mime_id' => $this->_params['mime_id'],
45: 'muid' => $this->_params['muid']
46: );
47: }
48:
49: 50: 51: 52: 53: 54: 55: 56: 57:
58: protected function _handle(Horde_Variables $vars)
59: {
60: global $conf, $injector, $notification, $registry;
61:
62: $actions = (array)$vars->imple_submit;
63: $result = false;
64: $vCal = new Horde_Icalendar();
65:
66:
67: try {
68: $contents = $injector->getInstance('IMP_Factory_Contents')->create(new IMP_Indices_Mailbox($vars));
69: $mime_part = $contents->getMIMEPart($vars->mime_id);
70: if (empty($mime_part)) {
71: throw new IMP_Exception(_("Cannot retrieve calendar data from message."));
72: } elseif (!$vCal->parsevCalendar($mime_part->getContents(), 'VCALENDAR', $mime_part->getCharset())) {
73: throw new IMP_Exception(_("The calendar data is invalid"));
74: }
75:
76: $components = $vCal->getComponents();
77: } catch (Exception $e) {
78: $notification->push($e, 'horde.error');
79: $actions = array();
80: }
81:
82: foreach ($actions as $key => $action) {
83: $pos = strpos($key, '[');
84: $key = substr($key, $pos + 1, strlen($key) - $pos - 2);
85:
86: switch ($action) {
87: case 'delete':
88:
89: if ($registry->hasMethod('calendar/delete')) {
90: $guid = $components[$key]->getAttribute('UID');
91: $recurrenceId = null;
92: try {
93:
94: $recurrenceId = $components[$key]->getAttribute('RECURRENCE-ID');
95: $atts = $components[$key]->getAttribute('RECURRENCE-ID', true);
96: $range = null;
97: foreach ($atts as $att) {
98: if (array_key_exists('RANGE', $att)) {
99: $range = $att['RANGE'];
100: }
101: }
102: } catch (Horde_Icalendar_Exception $e) {}
103:
104: try {
105: $registry->call('calendar/delete', array($guid, $recurrenceId, $range));
106: $notification->push(_("Event successfully deleted."), 'horde.success');
107: $result = true;
108: } catch (Horde_Exception $e) {
109: $notification->push(sprintf(_("There was an error deleting the event: %s"), $e->getMessage()), 'horde.error');
110: }
111: } else {
112: $notification->push(_("This action is not supported."), 'horde.warning');
113: }
114: break;
115:
116: case 'update':
117:
118: if ($registry->hasMethod('calendar/updateAttendee')) {
119: try {
120: $from = $contents->getHeader()->getOb('from');
121: $registry->call('calendar/updateAttendee', array(
122: $components[$key],
123: $from[0]->bare_address
124: ));
125: $notification->push(_("Respondent Status Updated."), 'horde.success');
126: $result = true;
127: } catch (Horde_Exception $e) {
128: $notification->push(sprintf(_("There was an error updating the event: %s"), $e->getMessage()), 'horde.error');
129: }
130: } else {
131: $notification->push(_("This action is not supported."), 'horde.warning');
132: }
133: break;
134:
135: case 'import':
136: case 'accept-import':
137:
138:
139:
140:
141:
142:
143: switch ($components[$key]->getType()) {
144: case 'vEvent':
145: $result = $this->_handlevEvent($key, $components, $mime_part);
146:
147: foreach ($components as $k => $component) {
148: try {
149: if ($component->getType() == 'vEvent' && $component->getAttribute('RECURRENCE-ID')) {
150: $uid = $component->getAttribute('UID');
151: if ($uid == $components[$key]->getAttribute('UID')) {
152: $this->_handlevEvent($k, $components, $mime_part);
153: }
154: }
155: } catch (Horde_Icalendar_Exception $e) {}
156: }
157:
158: break;
159: case 'vFreebusy':
160:
161: if ($registry->hasMethod('calendar/import_vfreebusy')) {
162: try {
163: $registry->call('calendar/import_vfreebusy', array($components[$key]));
164: $notification->push(_("The user's free/busy information was sucessfully stored."), 'horde.success');
165: $result = true;
166: } catch (Horde_Exception $e) {
167: $notification->push(sprintf(_("There was an error importing user's free/busy information: %s"), $e->getMessage()), 'horde.error');
168: }
169: } else {
170: $notification->push(_("This action is not supported."), 'horde.warning');
171: }
172: break;
173:
174: case 'vTodo':
175:
176: if ($registry->hasMethod('tasks/import')) {
177: try {
178: $guid = $registry->call('tasks/import', array(
179: $components[$key],
180: $mime_part->getType()
181: ));
182: $url = Horde::url($registry->link('tasks/show', array('uid' => $guid)));
183: $notification->push(
184: _("The task has been added to your tasklist.") . ' ' .
185: Horde::link($url, _("View task"), null, '_blank') .
186: Horde_Themes_Image::tag('mime/icalendar.png', array('alt' => _("View task"))) .
187: '</a>',
188: 'horde.success',
189: array('content.raw')
190: );
191: $result = true;
192: } catch (Horde_Exception $e) {
193: $notification->push(sprintf(_("There was an error importing the task: %s"), $e->getMessage()), 'horde.error');
194: }
195: } else {
196: $notification->push(_("This action is not supported."), 'horde.warning');
197: }
198: break;
199:
200: case 'vJournal':
201: default:
202: $notification->push(_("This action is not supported."), 'horde.warning');
203: }
204:
205: if ($action == 'import') {
206: break;
207: }
208:
209:
210: case 'accept':
211: case 'deny':
212: case 'tentative':
213:
214: if (isset($components[$key]) &&
215: ($components[$key]->getType() == 'vEvent')) {
216: $vEvent = $components[$key];
217:
218: $resource = new Horde_Itip_Resource_Identity(
219: $injector->getInstance('IMP_Identity'),
220: $vEvent->getAttribute('ATTENDEE'),
221: $vars->identity
222: );
223:
224: switch ($action) {
225: case 'accept':
226: case 'accept-import':
227: $type = new Horde_Itip_Response_Type_Accept($resource);
228: break;
229:
230: case 'deny':
231: $type = new Horde_Itip_Response_Type_Decline($resource);
232: break;
233:
234: case 'tentative':
235: $type = new Horde_Itip_Response_Type_Tentative($resource);
236: break;
237: }
238:
239: try {
240:
241: Horde_Itip::factory($vEvent, $resource)->sendMultiPartResponse(
242: $type,
243: new Horde_Itip_Response_Options_Horde(
244: 'UTF-8',
245: array(
246: 'dns' => $injector->getInstance('Net_DNS2_Resolver'),
247: 'server' => $conf['server']['name']
248: )
249: ),
250: $injector->getInstance('IMP_Mail')
251: );
252: $notification->push(_("Reply Sent."), 'horde.success');
253: $result = true;
254: } catch (Horde_Itip_Exception $e) {
255: $notification->push(sprintf(_("Error sending reply: %s."), $e->getMessage()), 'horde.error');
256: }
257: } else {
258: $notification->push(_("This action is not supported."), 'horde.warning');
259: }
260: break;
261:
262: case 'send':
263: case 'reply':
264: case 'reply2m':
265:
266: if (isset($components[$key]) &&
267: ($components[$key]->getType() == 'vFreebusy')) {
268: $vFb = $components[$key];
269:
270:
271: try {
272: $organizer = parse_url($vFb->getAttribute('ORGANIZER'));
273: } catch (Horde_Icalendar_Exception $e) {
274: break;
275: }
276:
277: $organizerEmail = $organizer['path'];
278:
279: $organizer = $vFb->getAttribute('ORGANIZER', true);
280: $organizerFullEmail = new Horde_Mail_Rfc822_Address($organizerEmail);
281: if (isset($organizer['cn'])) {
282: $organizerFullEmail->personal = $organizer['cn'];
283: }
284:
285: if ($action == 'reply2m') {
286: $startStamp = time();
287: $endStamp = $startStamp + (60 * 24 * 3600);
288: } else {
289: try {
290: $startStamp = $vFb->getAttribute('DTSTART');
291: } catch (Horde_Icalendar_Exception $e) {
292: $startStamp = time();
293: }
294:
295: try {
296: $endStamp = $vFb->getAttribute('DTEND');
297: } catch (Horde_Icalendar_Exception $e) {}
298:
299: if (!$endStamp) {
300: try {
301: $duration = $vFb->getAttribute('DURATION');
302: $endStamp = $startStamp + $duration;
303: } catch (Horde_Icalendar_Exception $e) {
304: $endStamp = $startStamp + (60 * 24 * 3600);
305: }
306: }
307: }
308:
309: $vfb_reply = $registry->call('calendar/getFreeBusy', array(
310: $startStamp,
311: $endStamp
312: ));
313:
314:
315: $identity = $injector->getInstance('IMP_Identity');
316: $email = $identity->getFromAddress();
317:
318:
319: $msg_headers = new Horde_Mime_Headers();
320:
321: $vCal = new Horde_Icalendar();
322: $vCal->setAttribute('PRODID', '-//The Horde Project//' . $msg_headers->getUserAgent() . '//EN');
323: $vCal->setAttribute('METHOD', 'REPLY');
324: $vCal->addComponent($vfb_reply);
325:
326: $message = _("Attached is a reply to a calendar request you sent.");
327: $body = new Horde_Mime_Part();
328: $body->setType('text/plain');
329: $body->setCharset('UTF-8');
330: $body->setContents(Horde_String::wrap($message, 76));
331:
332: $ics = new Horde_Mime_Part();
333: $ics->setType('text/calendar');
334: $ics->setCharset('UTF-8');
335: $ics->setContents($vCal->exportvCalendar());
336: $ics->setName('icalendar.ics');
337: $ics->setContentTypeParameter('METHOD', 'REPLY');
338:
339: $mime = new Horde_Mime_Part();
340: $mime->addPart($body);
341: $mime->addPart($ics);
342:
343:
344: $msg_headers->addReceivedHeader(array(
345: 'dns' => $injector->getInstance('Net_DNS2_Resolver'),
346: 'server' => $conf['server']['name']
347: ));
348: $msg_headers->addMessageIdHeader();
349: $msg_headers->addHeader('Date', date('r'));
350: $msg_headers->addHeader('From', $email);
351: $msg_headers->addHeader('To', $organizerFullEmail);
352:
353: $identity->setDefault($vars->identity);
354: $replyto = $identity->getValue('replyto_addr');
355: if (!empty($replyto) && !$email->match($replyto)) {
356: $msg_headers->addHeader('Reply-To', $replyto);
357: }
358: $msg_headers->addHeader('Subject', _("Free/Busy Request Response"));
359:
360:
361: try {
362: $mime->send($organizerEmail, $msg_headers, $injector->getInstance('IMP_Mail'));
363: $notification->push(_("Reply Sent."), 'horde.success');
364: $result = true;
365: } catch (Exception $e) {
366: $notification->push(sprintf(_("Error sending reply: %s."), $e->getMessage()), 'horde.error');
367: }
368: } else {
369: $notification->push(_("Invalid Action selected for this component."), 'horde.warning');
370: }
371: break;
372:
373: case 'nosup':
374:
375: default:
376: $notification->push(_("This action is not supported."), 'horde.warning');
377: break;
378: }
379: }
380:
381: return $result;
382: }
383:
384: protected function _handlevEvent($key, array $components, $mime_part)
385: {
386: global $notification, $registry;
387:
388: try {
389: $guid = $components[$key]->getAttribute('UID');
390: } catch (Horde_Icalendar_Exception $e) {
391: 392: 393:
394: $guid = strval(new Horde_Support_Guid());
395: }
396:
397:
398: try {
399: $registry->call('calendar/export', array($guid, 'text/calendar'));
400: $success = true;
401: } catch (Horde_Exception $e) {
402: $success = false;
403: }
404:
405:
406: if ($success && $registry->hasMethod('calendar/replace')) {
407: try {
408: $registry->call('calendar/replace', array(
409: $guid,
410: $components[$key],
411: $mime_part->getType()
412: ));
413: $url = Horde::url($registry->link('calendar/show', array('uid' => $guid)));
414: $notification->push(
415: _("The event was updated in your calendar.") . ' ' .
416: Horde::link($url, _("View event"), null, '_blank') .
417: Horde_Themes_Image::tag('mime/icalendar.png', array('alt' => _("View event"))) .
418: '</a>',
419: 'horde.success',
420: array('content.raw')
421: );
422: return true;
423: } catch (Horde_Exception $e) {
424:
425: $notification->push(sprintf(_("There was an error updating the event: %s Trying to import the event instead."), $e->getMessage()), 'horde.warning');
426: }
427: }
428:
429: if ($registry->hasMethod('calendar/import')) {
430:
431: try {
432: $guid = $registry->call('calendar/import', array(
433: $components[$key],
434: $mime_part->getType()
435: ));
436: $url = Horde::url($registry->link('calendar/show', array('uid' => $guid)));
437: $notification->push(
438: _("The event was added to your calendar.") . ' ' .
439: Horde::link($url, _("View event"), null, '_blank') .
440: Horde_Themes_Image::tag('mime/icalendar.png', array('alt' => _("View event"))) .
441: '</a>',
442: 'horde.success',
443: array('content.raw')
444: );
445: return true;
446:
447: } catch (Horde_Exception $e) {
448: $notification->push(sprintf(_("There was an error importing the event: %s"), $e->getMessage()), 'horde.error');
449: }
450: }
451:
452: $notification->push(_("This action is not supported."), 'horde.warning');
453:
454: return false;
455: }
456:
457: }
458: