1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
15: class Horde_Core_Mime_Viewer_Vcard extends Horde_Mime_Viewer_Base
16: {
17: 18: 19: 20: 21:
22: protected $_capability = array(
23: 'full' => true,
24: 'info' => false,
25: 'inline' => true,
26: 'raw' => false
27: );
28:
29: 30: 31: 32: 33:
34: protected $_imageUrl;
35:
36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50:
51: public function __construct(Horde_Mime_Part $part, array $conf = array())
52: {
53: $this->_required = array_merge($this->_required, array(
54: 'browser',
55: 'notification',
56: 'prefs',
57: 'registry'
58: ));
59:
60: parent::__construct($part, $conf);
61: }
62:
63: 64: 65: 66: 67:
68: protected function _render()
69: {
70: $ret = $this->_renderInline();
71:
72: if (!empty($ret)) {
73: $templates = $this->getConfigParam('registry')->get('templates', 'horde');
74:
75: reset($ret);
76: Horde::startBuffer();
77: include $templates . '/common-header.inc';
78: echo $ret[key($ret)]['data'];
79: include $templates . '/common-footer.inc';
80: $ret[key($ret)]['data'] = Horde::endBuffer();
81: }
82:
83: return $ret;
84: }
85:
86: 87: 88: 89: 90:
91: protected function _renderInline()
92: {
93: $browser = $this->getConfigParam('browser');
94: $notification = $this->getConfigParam('notification');
95: $prefs = $this->getConfigParam('prefs');
96: $registry = $this->getConfigParam('registry');
97:
98: $app = false;
99: $data = $this->_mimepart->getContents();
100: $html = '';
101: $import_msg = null;
102: $title = Horde_Core_Translation::t("vCard");
103:
104: $iCal = new Horde_Icalendar();
105: if (!$iCal->parsevCalendar($data, 'VCALENDAR', $this->_mimepart->getCharset())) {
106: $notification->push(Horde_Core_Translation::t("There was an error reading the contact data."), 'horde.error');
107: }
108:
109: if (Horde_Util::getFormData('import') &&
110: Horde_Util::getFormData('source') &&
111: $registry->hasMethod('contacts/import')) {
112: $source = Horde_Util::getFormData('source');
113: $count = 0;
114: foreach ($iCal->getComponents() as $c) {
115: if ($c->getType() == 'vcard') {
116: try {
117: $contacts = $registry->call('contacts/import', array($c, null, $source));
118: ++$count;
119: } catch (Horde_Exception $e) {
120: $notification->push(Horde_Core_Translation::t("There was an error importing the contact data:") . ' ' . $e->getMessage(), 'horde.error');
121: }
122: }
123: }
124: $notification->push(sprintf(Horde_Core_Translation::ngettext(
125: "%d contact was successfully added to your address book.",
126: "%d contacts were successfully added to your address book.",
127: $count),
128: $count),
129: 'horde.success');
130: }
131:
132: $html .= '<table cellspacing="1" border="0" cellpadding="1">';
133:
134: foreach ($iCal->getComponents() as $i => $vc) {
135: if ($i > 0) {
136: $html .= '<tr><td colspan="2"> </td></tr>';
137: }
138:
139: $addresses = $vc->getAllAttributes('EMAIL');
140:
141: $html .= '<tr><td colspan="2" class="header">';
142: if (($fullname = $vc->getAttributeDefault('FN', false)) === false) {
143: $fullname = count($addresses)
144: ? $addresses[0]['value']
145: : Horde_Core_Translation::t("[No Label]");
146: }
147: $html .= htmlspecialchars($fullname) . '</td></tr>';
148:
149: $n = $vc->printableName();
150: if (!empty($n)) {
151: $html .= $this->_row(Horde_Core_Translation::t("Name"), $n);
152: }
153:
154: try {
155: $html .= $this->_row(Horde_Core_Translation::t("Alias"), implode("\n", $vc->getAttributeValues('ALIAS')));
156: } catch (Horde_Icalendar_Exception $e) {}
157:
158: try {
159: $birthdays = $vc->getAttributeValues('BDAY');
160: $birthday = new Horde_Date($birthdays[0]);
161: $html .= $this->_row(
162: Horde_Core_Translation::t("Birthday"),
163: $birthday->strftime($prefs->getValue('date_format')));
164: } catch (Horde_Icalendar_Exception $e) {}
165:
166: $photos = $vc->getAllAttributes('PHOTO');
167: foreach ($photos as $p => $photo) {
168: if (isset($photo['params']['VALUE']) &&
169: Horde_String::upper($photo['params']['VALUE']) == 'URI') {
170: $html .= $this->_row(Horde_Core_Translation::t("Photo"),
171: '<img src="' . htmlspecialchars($photo['value']) . '" />',
172: false);
173: } elseif (isset($photo['params']['ENCODING']) &&
174: Horde_String::upper($photo['params']['ENCODING']) == 'B' &&
175: isset($photo['params']['TYPE'])) {
176: if ($browser->hasFeature('datauri') === true ||
177: $browser->hasFeature('datauri') >= strlen($photo['value'])) {
178: $html .= $this->_row(Horde_Core_Translation::t("Photo"),
179: '<img src="data:' . htmlspecialchars($photo['params']['TYPE'] . ';base64,' . $photo['value']) . '" />',
180: false);
181: } elseif ($this->_imageUrl) {
182: $html .= $this->_row(Horde_Core_Translation::t("Photo"),
183: '<img src="' . htmlspecialchars($this->_imageUrl->add(array('c' => $i, 'p' => $p))) . '" />',
184: false);
185: }
186: }
187: }
188:
189: $labels = $vc->getAllAttributes('LABEL');
190: foreach ($labels as $label) {
191: if (isset($label['params']['TYPE'])) {
192: if (!is_array($label['params']['TYPE'])) {
193: $label['params']['TYPE'] = array($label['params']['TYPE']);
194: }
195: } else {
196: $label['params']['TYPE'] = array_keys($label['params']);
197: }
198: $types = array();
199: foreach ($label['params']['TYPE'] as $type) {
200: switch(Horde_String::upper($type)) {
201: case 'HOME':
202: $types[] = Horde_Core_Translation::t("Home Address");
203: break;
204:
205: case 'WORK':
206: $types[] = Horde_Core_Translation::t("Work Address");
207: break;
208:
209: case 'DOM':
210: $types[] = Horde_Core_Translation::t("Domestic Address");
211: break;
212:
213: case 'INTL':
214: $types[] = Horde_Core_Translation::t("International Address");
215: break;
216:
217: case 'POSTAL':
218: $types[] = Horde_Core_Translation::t("Postal Address");
219: break;
220:
221: case 'PARCEL':
222: $types[] = Horde_Core_Translation::t("Parcel Address");
223: break;
224:
225: case 'PREF':
226: $types[] = Horde_Core_Translation::t("Preferred Address");
227: break;
228: }
229: }
230: if (!count($types)) {
231: $types = array(Horde_Core_Translation::t("Address"));
232: }
233: $html .= $this->_row(implode('/', $types), $label['value']);
234: }
235:
236: $adrs = $vc->getAllAttributes('ADR');
237: foreach ($adrs as $item) {
238: if (isset($item['params']['TYPE'])) {
239: if (!is_array($item['params']['TYPE'])) {
240: $item['params']['TYPE'] = array($item['params']['TYPE']);
241: }
242: } else {
243: $item['params']['TYPE'] = array_keys($item['params']);
244: }
245:
246: $address = $item['values'];
247: $a = array();
248: $a_list = array(
249: Horde_Icalendar_Vcard::ADR_STREET,
250: Horde_Icalendar_Vcard::ADR_LOCALITY,
251: Horde_Icalendar_Vcard::ADR_REGION,
252: Horde_Icalendar_Vcard::ADR_POSTCODE,
253: Horde_Icalendar_Vcard::ADR_COUNTRY
254: );
255:
256: foreach ($a_list as $val) {
257: if (isset($address[$val])) {
258: $a[] = $address[$val];
259: }
260: }
261:
262: $types = array();
263: foreach ($item['params']['TYPE'] as $type) {
264: switch(Horde_String::upper($type)) {
265: case 'HOME':
266: $types[] = Horde_Core_Translation::t("Home Address");
267: break;
268:
269: case 'WORK':
270: $types[] = Horde_Core_Translation::t("Work Address");
271: break;
272:
273: case 'DOM':
274: $types[] = Horde_Core_Translation::t("Domestic Address");
275: break;
276:
277: case 'INTL':
278: $types[] = Horde_Core_Translation::t("International Address");
279: break;
280:
281: case 'POSTAL':
282: $types[] = Horde_Core_Translation::t("Postal Address");
283: break;
284:
285: case 'PARCEL':
286: $types[] = Horde_Core_Translation::t("Parcel Address");
287: break;
288:
289: case 'PREF':
290: $types[] = Horde_Core_Translation::t("Preferred Address");
291: break;
292: }
293: }
294: if (!count($types)) {
295: $types = array(Horde_Core_Translation::t("Address"));
296: }
297: $html .= $this->_row(implode('/', $types), implode("\n", $a));
298: }
299:
300: $numbers = $vc->getAllAttributes('TEL');
301:
302: foreach ($numbers as $number) {
303: if (isset($number['params']['TYPE'])) {
304: if (!is_array($number['params']['TYPE'])) {
305: $number['params']['TYPE'] = array($number['params']['TYPE']);
306: }
307: foreach ($number['params']['TYPE'] as $type) {
308: $number['params'][Horde_String::upper($type)] = true;
309: }
310: }
311: if (isset($number['params']['FAX'])) {
312: $html .= $this->_row(Horde_Core_Translation::t("Fax"), $number['value']);
313: } else {
314: if (isset($number['params']['HOME'])) {
315: $html .= $this->_row(Horde_Core_Translation::t("Home Phone"),
316: $number['value']);
317: } elseif (isset($number['params']['WORK'])) {
318: $html .= $this->_row(Horde_Core_Translation::t("Work Phone"),
319: $number['value']);
320: } elseif (isset($number['params']['CELL'])) {
321: $html .= $this->_row(Horde_Core_Translation::t("Cell Phone"),
322: $number['value']);
323: } else {
324: $html .= $this->_row(Horde_Core_Translation::t("Phone"),
325: $number['value']);
326: }
327: }
328: }
329:
330: $emails = array();
331: foreach ($addresses as $address) {
332: if (isset($address['params']['TYPE'])) {
333: if (!is_array($address['params']['TYPE'])) {
334: $address['params']['TYPE'] = array($address['params']['TYPE']);
335: }
336: foreach ($address['params']['TYPE'] as $type) {
337: $address['params'][Horde_String::upper($type)] = true;
338: }
339: }
340: $email = '<a href="';
341: if ($registry->hasMethod('mail/compose')) {
342: $email .= $registry->call(
343: 'mail/compose',
344: array(array('to' => $address['value'])));
345: } else {
346: $email .= 'mailto:' . htmlspecialchars($address['value']);
347: }
348: $email .= '">' . htmlspecialchars($address['value']) . '</a>';
349: if (isset($address['params']['PREF'])) {
350: array_unshift($emails, $email);
351: } else {
352: $emails[] = $email;
353: }
354: }
355:
356: if (count($emails)) {
357: $html .= $this->_row(Horde_Core_Translation::t("Email"), implode("\n", $emails), false);
358: }
359:
360: try {
361: $title = $vc->getAttributeValues('TITLE');
362: $html .= $this->_row(Horde_Core_Translation::t("Title"), $title[0]);
363: } catch (Horde_Icalendar_Exception $e) {}
364:
365: try {
366: $role = $vc->getAttributeValues('ROLE');
367: $html .= $this->_row(Horde_Core_Translation::t("Role"), $role[0]);
368: } catch (Horde_Icalendar_Exception $e) {}
369:
370: try {
371: $org = $vc->getAttributeValues('ORG');
372: $html .= $this->_row(Horde_Core_Translation::t("Company"), $org[0]);
373: if (isset($org[1])) {
374: $html .= $this->_row(Horde_Core_Translation::t("Department"), $org[1]);
375: }
376: } catch (Horde_Icalendar_Exception $e) {}
377:
378: try {
379: $notes = $vc->getAttributeValues('NOTE');
380: $html .= $this->_row(Horde_Core_Translation::t("Notes"), $notes[0]);
381: } catch (Horde_Icalendar_Exception $e) {}
382:
383: try {
384: $url = $vc->getAttributeValues('URL');
385: $html .= $this->_row(
386: Horde_Core_Translation::t("URL"),
387: '<a href="' . htmlspecialchars($url[0])
388: . '" target="_blank">' . htmlspecialchars($url[0])
389: . '</a>',
390: false);
391: } catch (Horde_Icalendar_Exception $e) {}
392: }
393:
394: if ($registry->hasMethod('contacts/import') &&
395: $registry->hasMethod('contacts/sources')) {
396: $html .= '<tr><td colspan="2" class="smallheader"><form action="'
397: . Horde::selfUrl() . '" method="get" name="vcard_import">'
398: . Horde_Util::formInput();
399: foreach ($_GET as $key => $val) {
400: $html .= '<input type="hidden" name="' . htmlspecialchars($key)
401: . '" value="' . htmlspecialchars($val) . '" />';
402: }
403:
404: $sources = $registry->call('contacts/sources', array(true));
405: if (count($sources) > 1) {
406: $html .=
407: '<input type="submit" class="button" name="import" value="'
408: . Horde_Core_Translation::t("Add to address book:") . '" />'
409: . '<label for="add_source" class="hidden">'
410: . Horde_Core_Translation::t("Address Book") . '</label>'
411: . '<select id="add_source" name="source">';
412: foreach ($sources as $key => $label) {
413: $selected = ($key == $prefs->getValue('add_source'))
414: ? ' selected="selected"' : '';
415: $html .= '<option value="' . htmlspecialchars($key) . '"'
416: . $selected . '>' . htmlspecialchars($label)
417: . '</option>';
418: }
419: } else {
420: reset($sources);
421: $html .=
422: '<input type="submit" class="button" name="import" value="'
423: . Horde_Core_Translation::t("Add to my address book") . '" />'
424: . '<input type="hidden" name="source" value="'
425: . htmlspecialchars(key($sources)) . '" />';
426: }
427:
428: $html .= '</form></td></tr><tr><td> </td></tr>';
429: }
430:
431: $html .= '</table>';
432:
433: Horde::startBuffer();
434: $notification->notify(array('listeners' => 'status'));
435:
436: return $this->_renderReturn(
437: Horde::endBuffer() . $html,
438: 'text/html; charset=' . $this->getConfigParam('charset')
439: );
440: }
441:
442: 443: 444:
445: protected function _row($label, $value, $encode = true)
446: {
447: if ($encode) {
448: $label = htmlspecialchars($label);
449: $value = htmlspecialchars($value);
450: }
451: return '<tr><td class="item" valign="top">' . $label .
452: '</td><td class="item" valign="top">' . nl2br($value) .
453: "</td></tr>\n";
454: }
455:
456: }
457: