1: <?php
2: 3: 4: 5: 6: 7:
8: class Kronolith_FreeBusy
9: {
10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
24: public static function generate($calendars, $startstamp = null,
25: $endstamp = null, $returnObj = false,
26: $user = null)
27: {
28: global $kronolith_shares;
29:
30: if (!is_array($calendars)) {
31: $calendars = array($calendars);
32: }
33:
34: if (!$user) {
35:
36: foreach ($calendars as $calendar) {
37: if (strpos($calendar, 'internal_') !== 0) {
38: continue;
39: }
40: $calendar = substr($calendar, 9);
41: try {
42: $share = $kronolith_shares->getShare($calendar);
43: $user = $share->get('owner');
44: break;
45: } catch (Horde_Exception $e) {
46: }
47: }
48: }
49:
50:
51: if (is_null($startstamp)) {
52: $startstamp = mktime(0, 0, 0);
53: }
54:
55:
56: if (is_null($endstamp) || $endstamp < $startstamp) {
57: $enddate = new Horde_Date($startstamp);
58: $enddate->mday += $GLOBALS['prefs']->getValue('freebusy_days');
59: $endstamp = $enddate->timestamp();
60: } else {
61: $enddate = new Horde_Date($endstamp);
62: }
63:
64:
65: $identity = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($user);
66: $email = $identity->getValue('from_addr');
67: $cn = $identity->getValue('fullname');
68: if (empty($email) && empty($cn)) {
69: $cn = $user;
70: }
71:
72:
73: $busy = array();
74: foreach ($calendars as $calendar) {
75: if (strpos($calendar, '_')) {
76: @list($type, $calendar) = explode('_', $calendar, 2);
77: } else {
78: $type = 'internal';
79: }
80: try {
81: $driver = Kronolith::getDriver($type, $calendar);
82: $events = $driver->listEvents(new Horde_Date($startstamp),
83: $enddate, true);
84: Kronolith::mergeEvents($busy, $events);
85: } catch (Exception $e) {
86: }
87: }
88:
89:
90: $vCal = new Horde_Icalendar();
91: $vCal->setAttribute('PRODID', '-//The Horde Project//Kronolith ' . $GLOBALS['registry']->getVersion() . '//EN');
92: $vCal->setAttribute('METHOD', 'PUBLISH');
93:
94:
95: $vFb = Horde_Icalendar::newComponent('vfreebusy', $vCal);
96: $params = array();
97: if (!empty($cn)) {
98: $params['CN'] = $cn;
99: }
100: if (!empty($email)) {
101: $vFb->setAttribute('ORGANIZER', 'mailto:' . $email, $params);
102: } else {
103: $vFb->setAttribute('ORGANIZER', '', $params);
104: }
105:
106: $vFb->setAttribute('DTSTAMP', $_SERVER['REQUEST_TIME']);
107: $vFb->setAttribute('DTSTART', $startstamp);
108: $vFb->setAttribute('DTEND', $endstamp);
109: $vFb->setAttribute('URL', Horde::url('fb.php?u=' . $user, true, -1));
110:
111:
112: foreach ($busy as $events) {
113: foreach ($events as $event) {
114: if ($event->status == Kronolith::STATUS_FREE) {
115: continue;
116: }
117: if ($event->status == Kronolith::STATUS_CANCELLED) {
118: continue;
119: }
120:
121: 122:
123: $vFb->addBusyPeriod('BUSY', $event->start->timestamp(), null,
124: $event->end->timestamp() - $event->start->timestamp());
125: }
126: }
127:
128:
129: $vFb->simplify();
130: $vCal->addComponent($vFb);
131:
132:
133: if ($returnObj) {
134: return $vFb;
135: }
136:
137:
138: return $vCal->exportvCalendar();
139: }
140:
141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151:
152: public static function get($email, $json = false)
153: {
154: $default_domain = empty($GLOBALS['conf']['storage']['default_domain']) ? null : $GLOBALS['conf']['storage']['default_domain'];
155: $rfc822 = new Horde_Mail_Rfc822();
156:
157: try {
158: $res = $rfc822->parseAddressList($email, array(
159: 'default_domain' => $default_domain
160: ));
161: } catch (Horde_Mail_Exception $e) {
162: throw new Kronolith_Exception($e);
163: }
164:
165: if (!count($res)) {
166: throw new Kronolith_Exception(_("No valid email address found"));
167: }
168:
169: $email = Horde_Mime_Address::writeAddress($res[0]->mailbox, $res[0]->host);
170:
171: 172:
173: $url = self::getUrl($email);
174: if ($url) {
175: $url = trim($url);
176: $http = $GLOBALS['injector']->getInstance('Horde_Core_Factory_HttpClient')->create();
177: try {
178: $response = $http->get($url);
179: } catch (Horde_Http_Client_Exception $e) {
180: throw new Kronolith_Exception(sprintf(_("The free/busy url for %s cannot be retrieved."), $email));
181: }
182: if ($response->code == 200 && $data = $response->getBody()) {
183:
184: $contentType = $response->getHeader('Content-Type');
185: if ($contentType && strpos($contentType, ';') !== false) {
186: list(,$charset,) = explode(';', $contentType);
187: $data = Horde_String::convertCharset($data, trim(str_replace('charset=', '', $charset)), 'UTF-8');
188: }
189:
190: $vCal = new Horde_Icalendar();
191: $vCal->parsevCalendar($data, 'VCALENDAR');
192: $components = $vCal->getComponents();
193:
194: $vCal = new Horde_Icalendar();
195: $vFb = Horde_Icalendar::newComponent('vfreebusy', $vCal);
196: $vFb->setAttribute('ORGANIZER', $email);
197: $found = false;
198: foreach ($components as $component) {
199: if ($component instanceof Horde_Icalendar_Vfreebusy) {
200: $found = true;
201: $vFb->merge($component);
202: }
203: }
204:
205: if ($found) {
206:
207:
208:
209:
210: return $json ? self::toJson($vFb) : $vFb;
211: }
212: }
213: }
214:
215:
216: $storage = $GLOBALS['injector']->getInstance('Kronolith_Factory_Storage')->create();
217:
218: try {
219: $fb = $storage->search($email);
220: return $json ? self::toJson($fb) : $fb;
221: } catch (Horde_Exception_NotFound $e) {
222: if ($url) {
223: throw new Kronolith_Exception(sprintf(_("No free/busy information found at the free/busy url of %s."), $email));
224: }
225: throw new Kronolith_Exception(sprintf(_("No free/busy url found for %s."), $email));
226: }
227:
228:
229: $vCal = new Horde_Icalendar();
230: $vFb = Horde_Icalendar::newComponent('vfreebusy', $vCal);
231: $vFb->setAttribute('ORGANIZER', $email);
232:
233: return $json ? self::toJson($vFb) : $vFb;
234: }
235:
236: 237: 238: 239: 240: 241: 242:
243: public static function getUrl($email)
244: {
245: $sources = json_decode($GLOBALS['prefs']->getValue('search_sources'));
246: if (empty($sources)) {
247: $sources = array();
248: }
249:
250: try {
251: $result = $GLOBALS['registry']->call('contacts/getField',
252: array($email, 'freebusyUrl', $sources, true, true));
253: } catch (Horde_Exception $e) {
254: return false;
255: }
256: if (is_array($result)) {
257: return array_shift($result);
258: }
259:
260: return $result;
261: }
262:
263: 264: 265: 266: 267: 268: 269: 270:
271: function toJson(Horde_Icalendar_Vfreebusy $fb)
272: {
273: $json = new stdClass;
274: $start = $fb->getStart();
275: if ($start) {
276: $start = new Horde_Date($start);
277: $json->s = $start->dateString();
278: }
279: $end = $fb->getEnd();
280: if ($end) {
281: $end = new Horde_Date($end);
282: $json->e = $end->dateString();
283: }
284: $b = $fb->getBusyPeriods();
285: if (empty($b)) {
286: $b = new StdClass();
287: }
288: $json->b = $b;
289: return $json;
290: }
291:
292: }
293: