]> git.mxchange.org Git - friendica.git/blob - include/Probe.php
New class to probe urls
[friendica.git] / include / Probe.php
1 <?php
2 /**
3  * @brief This class contain functions for probing URL
4  *
5  */
6
7 use \Friendica\Core\Config;
8 use \Friendica\Core\PConfig;
9
10 require_once("include/feed.php");
11
12 class Probe {
13
14         private function rearrange_data($data) {
15                 $fields = array("name", "nick", "guid", "url", "addr", "batch",
16                                 "notify", "poll", "request", "confirm", "poco",
17                                 "photo", "priority", "network", "alias", "pubkey", "baseurl");
18
19                 $newdata = array();
20                 foreach ($fields AS $field)
21                         if (isset($data[$field]))
22                                 $newdata[$field] = $data[$field];
23                         else
24                                 $newdata[$field] = "";
25
26                 // We don't use the "priority" field anymore and replace it with a dummy.
27                 $newdata["priority"] = 0;
28
29                 return $newdata;
30         }
31
32         /**
33          * @brief Probes for XRD data
34          *
35          * @return array
36          *      'lrdd' => Link to LRDD endpoint
37          *      'lrdd-xml' => Link to LRDD endpoint in XML format
38          *      'lrdd-json' => Link to LRDD endpoint in JSON format
39          */
40         private function xrd($host) {
41
42                 $ssl_url = "https://".$host."/.well-known/host-meta";
43                 $url = "http://".$host."/.well-known/host-meta";
44
45                 $xrd_timeout = Config::get('system','xrd_timeout', 20);
46                 $redirects = 0;
47
48                 $xml = fetch_url($ssl_url, false, $redirects, $xrd_timeout, "application/xrd+xml");
49                 $xrd = parse_xml_string($xml, false);
50
51                 if (!is_object($xrd)) {
52                         $xml = fetch_url($url, false, $redirects, $xrd_timeout, "application/xrd+xml");
53                         $xrd = parse_xml_string($xml, false);
54                 }
55                 if (!is_object($xrd))
56                         return false;
57
58                 $links = xml::element_to_array($xrd);
59                 if (!isset($links["xrd"]["link"]))
60                         return false;
61
62                 $xrd_data = array();
63                 foreach ($links["xrd"]["link"] AS $value => $link) {
64                         if (isset($link["@attributes"]))
65                                 $attributes = $link["@attributes"];
66                         elseif ($value == "@attributes")
67                                 $attributes = $link;
68                         else
69                                 continue;
70
71                         if (($attributes["rel"] == "lrdd") AND
72                                 ($attributes["type"] == "application/xrd+xml"))
73                                 $xrd_data["lrdd-xml"] = $attributes["template"];
74                         elseif (($attributes["rel"] == "lrdd") AND
75                                 ($attributes["type"] == "application/json"))
76                                 $xrd_data["lrdd-json"] = $attributes["template"];
77                         elseif ($attributes["rel"] == "lrdd")
78                                 $xrd_data["lrdd"] = $attributes["template"];
79                 }
80                 return $xrd_data;
81         }
82
83         public static function uri($uri) {
84                 $data = self::detect($uri);
85
86                 //if (!data)
87                 //      return false;
88
89                 if (!isset($data["url"]))
90                         $data["url"] = $uri;
91
92                 if ($data["photo"] != "")
93                         $data["baseurl"] = matching_url(normalise_link($data["baseurl"]), normalise_link($data["photo"]));
94                 else
95                         $data["photo"] = App::get_baseurl().'/images/person-175.jpg';
96
97                 if (!isset($data["name"]))
98                         $data["name"] = $data["url"];
99
100                 if (!isset($data["nick"]))
101                         $data["nick"] = strtolower($data["name"]);
102
103                 if (!isset($data["network"]))
104                         $data["network"] = NETWORK_PHANTOM;
105
106                 $data = self::rearrange_data($data);
107
108                 return $data;
109         }
110
111         private function detect($uri) {
112                 if (strstr($uri, '@')) {
113                         // If the URI starts with "mailto:" then jum directly to the mail detection
114                         if (strpos($url,'mailto:') !== false) {
115                                 $uri = str_replace('mailto:', '', $url);
116                                 return self::mail($uri);
117                         }
118
119                         // Remove "acct:" from the URI
120                         $uri = str_replace('acct:', '', $uri);
121
122                         $host = substr($uri,strpos($uri, '@') + 1);
123                         $nick = substr($uri,0, strpos($uri, '@'));
124
125                         $lrdd = self::xrd($host);
126                         if (!$lrdd)
127                                 return self::mail($uri);
128
129                         $addr = $uri;
130                 } else {
131                         $parts = parse_url($uri);
132                         if (!isset($parts["scheme"]) OR
133                                 !isset($parts["host"]) OR
134                                 !isset($parts["path"]))
135                                 return false;
136
137                         // todo: Ports?
138                         $host = $parts["host"];
139                         $lrdd = self::xrd($host);
140
141                         $path_parts = explode("/", trim($parts["path"], "/"));
142
143                         while (!$lrdd AND (sizeof($path_parts) > 1)) {
144                                 $host .= "/".array_shift($path_parts);
145                                 $lrdd = self::xrd($host);
146                         }
147                         if (!$lrdd)
148                                 return self::feed($uri);
149
150                         $nick = array_pop($path_parts);
151                         $addr = $nick."@".$host;
152                 }
153
154                 $webfinger = false;
155
156                 /// @todo Do we need the prefix "acct:" or "acct://"?
157
158                 foreach ($lrdd AS $key => $link) {
159                         if ($webfinger)
160                                 continue;
161
162                         if (!in_array($key, array("lrdd", "lrdd-xml", "lrdd-json")))
163                                 continue;
164
165                         $path = str_replace('{uri}', urlencode($addr), $link);
166
167                         $webfinger = self::webfinger($path);
168                 }
169                 if (!$webfinger)
170                         return self::feed($uri);
171
172                 $result = false;
173
174                 if (!$result)
175                         $result = self::dfrn($webfinger);
176                 if (!$result)
177                         $result = self::diaspora($webfinger);
178                 if (!$result)
179                         $result = self::ostatus($webfinger);
180                 if (!$result)
181                         $result = self::pumpio($webfinger);
182                 if (!$result)
183                         $result = self::feed($uri);
184                 else {
185                         // We overwrite the detected nick with our try if the previois routines hadn't detected it.
186                         // Additionally it is overwritten when the nickname doesn't make sense (contains spaces).
187                         if (!isset($result["nick"]) OR ($result["nick"] == "") OR (strstr($result["nick"], " ")))
188                                 $result["nick"] = $nick;
189
190                         if (!isset($result["addr"]) OR ($result["addr"] == ""))
191                                 $result["addr"] = $addr;
192                 }
193
194                 if (!isset($result["baseurl"]) OR ($result["baseurl"] == "")) {
195                         $pos = strpos($result["url"], $host);
196                         if ($pos)
197                                 $result["baseurl"] = substr($result["url"], 0, $pos).$host;
198                 }
199
200                 return $result;
201         }
202
203         private function webfinger($url) {
204
205                 $xrd_timeout = Config::get('system','xrd_timeout', 20);
206                 $redirects = 0;
207
208                 $data = fetch_url($url, false, $redirects, $xrd_timeout, "application/xrd+xml");
209                 $xrd = parse_xml_string($data, false);
210
211                 if (!is_object($xrd)) {
212                         // If it is not XML, maybe it is JSON
213                         $webfinger = json_decode($data, true);
214
215                         if (!isset($webfinger["links"]))
216                                 return false;
217
218                         return $webfinger;
219                 }
220
221                 $xrd_arr = xml::element_to_array($xrd);
222                 if (!isset($xrd_arr["xrd"]["link"]))
223                         return false;
224
225                 $webfinger = array();
226
227                 if (isset($xrd_arr["xrd"]["subject"]))
228                         $webfinger["subject"] = $xrd_arr["xrd"]["subject"];
229
230                 if (isset($xrd_arr["xrd"]["alias"]))
231                         $webfinger["aliases"] = $xrd_arr["xrd"]["alias"];
232
233                 $webfinger["links"] = array();
234
235                 foreach ($xrd_arr["xrd"]["link"] AS $value => $data) {
236                         if (isset($data["@attributes"]))
237                                 $attributes = $data["@attributes"];
238                         elseif ($value == "@attributes")
239                                 $attributes = $data;
240                         else
241                                 continue;
242
243                         $webfinger["links"][] = $attributes;
244                 }
245                 return $webfinger;
246         }
247
248         private function dfrn($webfinger) {
249
250                 $hcard = "";
251                 $data = array();
252                 foreach ($webfinger["links"] AS $link) {
253                         if (($link["rel"] == NAMESPACE_DFRN) AND ($link["href"] != ""))
254                                 $data["network"] = NETWORK_DFRN;
255                         elseif (($link["rel"] == NAMESPACE_FEED) AND ($link["href"] != ""))
256                                 $data["poll"] = $link["href"];
257                         elseif (($link["rel"] == "http://webfinger.net/rel/profile-page") AND
258                                 ($link["type"] == "text/html") AND ($link["href"] != ""))
259                                 $data["url"] = $link["href"];
260                         elseif (($link["rel"] == "http://microformats.org/profile/hcard") AND ($link["href"] != ""))
261                                 $hcard = $link["href"];
262                         elseif (($link["rel"] == NAMESPACE_POCO) AND ($link["href"] != ""))
263                                 $data["poco"] = $link["href"];
264                         elseif (($link["rel"] == "http://webfinger.net/rel/avatar") AND ($link["href"] != ""))
265                                 $data["photo"] = $link["href"];
266
267                         elseif (($link["rel"] == "http://joindiaspora.com/seed_location") AND ($link["href"] != ""))
268                                 $data["baseurl"] = trim($link["href"], '/');
269                         elseif (($link["rel"] == "http://joindiaspora.com/guid") AND ($link["href"] != ""))
270                                 $data["guid"] = $link["href"];
271                         elseif (($link["rel"] == "diaspora-public-key") AND ($link["href"] != "")) {
272                                 $data["pubkey"] = base64_decode($link["href"]);
273
274                                 if (strstr($data["pubkey"], 'RSA ') OR ($link["type"] == "RSA"))
275                                         $data["pubkey"] = rsatopem($data["pubkey"]);
276                         }
277                 }
278
279                 if (!isset($data["network"]) OR ($hcard == ""))
280                         return false;
281
282                 $data = self::poll_hcard($hcard, $data, true);
283
284                 return $data;
285         }
286
287         private function poll_hcard($hcard, $data, $dfrn = false) {
288
289                 $doc = new DOMDocument();
290                 if (!@$doc->loadHTMLFile($hcard))
291                         return false;
292
293                 $xpath = new DomXPath($doc);
294
295                 $vcards = $xpath->query("//div[contains(concat(' ', @class, ' '), ' vcard ')]");
296                 if (!is_object($vcards))
297                         return false;
298
299                 if ($vcards->length == 0)
300                         return false;
301
302                 $vcard = $vcards->item(0);
303
304                 // We have to discard the guid from the hcard in favour of the guid from lrdd
305                 // Reason: Hubzilla doesn't use the value "uid" in the hcard like Diaspora does.
306                 $search = $xpath->query("//*[contains(concat(' ', @class, ' '), ' uid ')]", $vcard); // */
307                 if (($search->length > 0) AND ($data["guid"] == ""))
308                         $data["guid"] = $search->item(0)->nodeValue;
309
310                 $search = $xpath->query("//*[contains(concat(' ', @class, ' '), ' nickname ')]", $vcard); // */
311                 if ($search->length > 0)
312                         $data["nick"] = $search->item(0)->nodeValue;
313
314                 $search = $xpath->query("//*[contains(concat(' ', @class, ' '), ' fn ')]", $vcard); // */
315                 if ($search->length > 0)
316                         $data["name"] = $search->item(0)->nodeValue;
317
318                 $search = $xpath->query("//*[contains(concat(' ', @class, ' '), ' searchable ')]", $vcard); // */
319                 if ($search->length > 0)
320                         $data["searchable"] = $search->item(0)->nodeValue;
321
322                 $search = $xpath->query("//*[contains(concat(' ', @class, ' '), ' key ')]", $vcard); // */
323                 if ($search->length > 0) {
324                         $data["pubkey"] = $search->item(0)->nodeValue;
325                         if (strstr($data["pubkey"], 'RSA '))
326                                 $data["pubkey"] = rsatopem($data["pubkey"]);
327                 }
328
329                 $search = $xpath->query("//*[@id='pod_location']", $vcard); // */
330                 if ($search->length > 0)
331                         $data["baseurl"] = trim($search->item(0)->nodeValue, "/");
332
333                 $avatar = array();
334                 $photos = $xpath->query("//*[contains(concat(' ', @class, ' '), ' photo ') or contains(concat(' ', @class, ' '), ' avatar ')]", $vcard); // */
335                 foreach ($photos AS $photo) {
336                         $attr = array();
337                         foreach ($photo->attributes as $attribute)
338                                 $attr[$attribute->name] = trim($attribute->value);
339
340                         if (isset($attr["src"]) AND isset($attr["width"]))
341                                 $avatar[$attr["width"]] = $attr["src"];
342                 }
343
344                 if (sizeof($avatar)) {
345                         ksort($avatar);
346                         $data["photo"] = array_pop($avatar);
347                 }
348
349                 if ($dfrn) {
350                         // Poll DFRN specific data
351                         $search = $xpath->query("//link[contains(concat(' ', @rel), ' dfrn-')]");
352                         if ($search->length > 0) {
353                                 foreach ($search AS $link) {
354                                         //$data["request"] = $search->item(0)->nodeValue;
355                                         $attr = array();
356                                         foreach ($link->attributes as $attribute)
357                                                 $attr[$attribute->name] = trim($attribute->value);
358
359                                         $data[substr($attr["rel"], 5)] = $attr["href"];
360                                 }
361                         }
362
363                         // Older Friendica versions had used the "uid" field differently than newer versions
364                         if ($data["nick"] == $data["guid"])
365                                 unset($data["guid"]);
366                 }
367
368
369                 return $data;
370         }
371
372         private function diaspora($webfinger) {
373
374                 $hcard = "";
375                 $data = array();
376                 foreach ($webfinger["links"] AS $link) {
377                         if (($link["rel"] == "http://microformats.org/profile/hcard") AND ($link["href"] != ""))
378                                 $hcard = $link["href"];
379                         elseif (($link["rel"] == "http://joindiaspora.com/seed_location") AND ($link["href"] != ""))
380                                 $data["baseurl"] = trim($link["href"], '/');
381                         elseif (($link["rel"] == "http://joindiaspora.com/guid") AND ($link["href"] != ""))
382                                 $data["guid"] = $link["href"];
383                         elseif (($link["rel"] == "http://webfinger.net/rel/profile-page") AND
384                                 ($link["type"] == "text/html") AND ($link["href"] != ""))
385                                 $data["url"] = $link["href"];
386                         elseif (($link["rel"] == NAMESPACE_FEED) AND ($link["href"] != ""))
387                                 $data["poll"] = $link["href"];
388                         elseif (($link["rel"] == NAMESPACE_POCO) AND ($link["href"] != ""))
389                                 $data["poco"] = $link["href"];
390                         elseif (($link["rel"] == "salmon") AND ($link["href"] != ""))
391                                 $data["notify"] = $link["href"];
392                         elseif (($link["rel"] == "diaspora-public-key") AND ($link["href"] != "")) {
393                                 $data["pubkey"] = base64_decode($link["href"]);
394
395                                 if (strstr($data["pubkey"], 'RSA ') OR ($link["type"] == "RSA"))
396                                         $data["pubkey"] = rsatopem($data["pubkey"]);
397                         }
398                 }
399
400                 if (!isset($data["url"]) OR ($hcard == ""))
401                         return false;
402
403                 if (isset($webfinger["aliases"]))
404                         foreach ($webfinger["aliases"] AS $alias)
405                                 if (normalise_link($alias) != normalise_link($data["url"]) AND !strstr($alias, "@"))
406                                         $data["alias"] = $alias;
407
408                 // Fetch further information from the hcard
409                 $data = self::poll_hcard($hcard, $data);
410
411                 if (!$data)
412                         return false;
413
414                 if (isset($data["url"]) AND isset($data["guid"]) AND isset($data["baseurl"]) AND
415                         isset($data["pubkey"]) AND ($hcard != "")) {
416                         $data["network"] = NETWORK_DIASPORA;
417
418                         // We have to overwrite the detected value for "notify" since Hubzilla doesn't send it
419                         $data["notify"] = $data["baseurl"]."/receive/users/".$data["guid"];
420                         $data["batch"] = $data["baseurl"]."/receive/public";
421                 } else
422                         return false;
423
424                 return $data;
425         }
426
427         private function ostatus($webfinger) {
428
429                 $pubkey = "";
430                 $data = array();
431                 foreach ($webfinger["links"] AS $link) {
432                         if (($link["rel"] == "http://webfinger.net/rel/profile-page") AND
433                                 ($link["type"] == "text/html") AND ($link["href"] != ""))
434                                 $data["url"] = $link["href"];
435                         elseif (($link["rel"] == "salmon") AND ($link["href"] != ""))
436                                 $data["notify"] = $link["href"];
437                         elseif (($link["rel"] == NAMESPACE_FEED) AND ($link["href"] != ""))
438                                 $data["poll"] = $link["href"];
439                         elseif (($link["rel"] == "magic-public-key") AND ($link["href"] != "")) {
440                                 $pubkey = $link["href"];
441
442                                 if (substr($pubkey, 0, 5) === 'data:') {
443                                         if (strstr($pubkey, ','))
444                                                 $pubkey = substr($pubkey, strpos($pubkey, ',') + 1);
445                                         else
446                                                 $pubkey = substr($pubkey, 5);
447                                 } else
448                                         $pubkey = fetch_url($pubkey);
449
450                                 $key = explode(".", $pubkey);
451
452                                 if (sizeof($key) >= 3) {
453                                         $m = base64url_decode($key[1]);
454                                         $e = base64url_decode($key[2]);
455                                         $data["pubkey"] = metopem($m,$e);
456                                 }
457
458                         }
459                 }
460
461                 if (isset($data["notify"]) AND isset($data["pubkey"]) AND
462                         isset($data["poll"]) AND isset($data["url"])) {
463                         $data["network"] = NETWORK_OSTATUS;
464                 } else
465                         return false;
466
467                 // Fetch all additional data from the feed
468                 $feed = fetch_url($data["poll"]);
469                 $feed_data = feed_import($feed,$dummy1,$dummy2, $dummy3, true);
470                 if (!$feed_data)
471                         return false;
472
473                 if ($feed_data["header"]["author-name"] != "")
474                         $data["name"] = $feed_data["header"]["author-name"];
475
476                 if ($feed_data["header"]["author-nick"] != "")
477                         $data["nick"] = $feed_data["header"]["author-nick"];
478
479                 if ($feed_data["header"]["author-avatar"] != "")
480                         $data["photo"] = $feed_data["header"]["author-avatar"];
481
482                 if ($feed_data["header"]["author-id"] != "")
483                         $data["alias"] = $feed_data["header"]["author-id"];
484
485                 // OStatus has serious issues when the the url doesn't fit (ssl vs. non ssl)
486                 // So we take the value that we just fetched, although the other one worked as well
487                 if ($feed_data["header"]["author-link"] != "")
488                         $data["url"] = $feed_data["header"]["author-link"];
489
490                 /// @todo Fetch location and "about" from the feed as well
491                 return $data;
492         }
493
494         private function pumpio_profile_data($profile) {
495
496                 $doc = new DOMDocument();
497                 if (!@$doc->loadHTMLFile($profile))
498                         return false;
499
500                 $xpath = new DomXPath($doc);
501
502                 $data = array();
503
504                 // This is ugly - but pump.io doesn't seem to know a better way for it
505                 $data["name"] = trim($xpath->query("//h1[@class='media-header']")->item(0)->nodeValue);
506                 $pos = strpos($data["name"], chr(10));
507                 if ($pos)
508                         $data["name"] = trim(substr($data["name"], 0, $pos));
509
510                 $avatar = $xpath->query("//img[@class='img-rounded media-object']")->item(0);
511                 if ($avatar)
512                         foreach ($avatar->attributes as $attribute)
513                                 if ($attribute->name == "src")
514                                         $data["photo"] = trim($attribute->value);
515
516                 $data["location"] = $xpath->query("//p[@class='location']")->item(0)->nodeValue;
517                 $data["about"] = $xpath->query("//p[@class='summary']")->item(0)->nodeValue;
518
519                 return $data;
520         }
521
522         private function pumpio($webfinger) {
523                 $data = array();
524                 foreach ($webfinger["links"] AS $link) {
525                         if (($link["rel"] == "http://webfinger.net/rel/profile-page") AND
526                                 ($link["type"] == "text/html") AND ($link["href"] != ""))
527                                 $data["url"] = $link["href"];
528                         elseif (($link["rel"] == "activity-inbox") AND ($link["href"] != ""))
529                                 $data["activity-inbox"] = $link["href"];
530                         elseif (($link["rel"] == "activity-outbox") AND ($link["href"] != ""))
531                                 $data["activity-outbox"] = $link["href"];
532                         elseif (($link["rel"] == "dialback") AND ($link["href"] != ""))
533                                 $data["dialback"] = $link["href"];
534                 }
535                 if (isset($data["activity-inbox"]) AND isset($data["activity-outbox"]) AND
536                         isset($data["dialback"]) AND isset($data["url"])) {
537
538                         // by now we use these fields only for the network type detection
539                         // So we unset all data that isn't used at the moment
540                         unset($data["activity-inbox"]);
541                         unset($data["activity-outbox"]);
542                         unset($data["dialback"]);
543
544                         $data["network"] = NETWORK_PUMPIO;
545                 } else
546                         return false;
547
548                 $profile_data = self::pumpio_profile_data($data["url"]);
549
550                 if (!$profile_data)
551                         return false;
552
553                 $data = array_merge($data, $profile_data);
554
555                 return $data;
556         }
557
558         private function feed($url) {
559                 $feed = fetch_url($url);
560                 $feed_data = feed_import($feed, $dummy1, $dummy2, $dummy3, true);
561
562                 if (!$feed_data)
563                         return false;
564
565                 if ($feed_data["header"]["author-name"] != "")
566                         $data["name"] = $feed_data["header"]["author-name"];
567
568                 if ($feed_data["header"]["author-nick"] != "")
569                         $data["nick"] = $feed_data["header"]["author-nick"];
570
571                 if ($feed_data["header"]["author-avatar"] != "")
572                         $data["photo"] = $feed_data["header"]["author-avatar"];
573
574                 if ($feed_data["header"]["author-id"] != "")
575                         $data["alias"] = $feed_data["header"]["author-id"];
576
577                 $data["url"] = $url;
578                 $data["poll"] = $url;
579
580                 if ($feed_data["header"]["author-link"] != "")
581                         $data["baseurl"] = $feed_data["header"]["author-link"];
582                 else
583                         $data["baseurl"] = $data["url"];
584
585                 $data["network"] = NETWORK_FEED;
586
587                 return $data;
588         }
589
590         private function mail($uri) {
591
592                 if (!validate_email($uri))
593                         return false;
594
595                 $uid = local_user();
596                 $uid = 1;
597
598                 $x = q("SELECT `prvkey` FROM `user` WHERE `uid` = %d LIMIT 1", intval($uid));
599
600                 $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1", intval($uid));
601
602                 if(count($x) && count($r)) {
603                         $mailbox = construct_mailbox_name($r[0]);
604                         $password = '';
605                         openssl_private_decrypt(hex2bin($r[0]['pass']), $password,$x[0]['prvkey']);
606                         $mbox = email_connect($mailbox,$r[0]['user'], $password);
607                         if(!mbox)
608                                 return false;
609                 }
610
611                 $msgs = email_poll($mbox, $uri);
612                 logger('searching '.$uri.', '.count($msgs).' messages found.', LOGGER_DEBUG);
613
614                 if (!count($msgs))
615                         return false;
616
617                 $data = array();
618
619                 $data["addr"] = $uri;
620                 $data["network"] = NETWORK_MAIL;
621                 $data["name"] = substr($uri, 0, strpos($uri,'@'));
622                 $data["nick"] = $data["name"];
623                 $data["photo"] = avatar_img($uri);
624
625                 $phost = substr($uri, strpos($uri,'@') + 1);
626                 $data["url"] = 'http://'.$phost."/".$data["nick"];
627                 $data["notify"] = 'smtp '.random_string();
628                 $data["poll"] = 'email '.random_string();
629
630                 $x = email_msg_meta($mbox, $msgs[0]);
631                 if(stristr($x[0]->from, $uri))
632                         $adr = imap_rfc822_parse_adrlist($x[0]->from, '');
633                 elseif(stristr($x[0]->to, $uri))
634                         $adr = imap_rfc822_parse_adrlist($x[0]->to, '');
635                 if(isset($adr)) {
636                         foreach($adr as $feadr) {
637                                 if((strcasecmp($feadr->mailbox, $data["name"]) == 0)
638                                         &&(strcasecmp($feadr->host, $phost) == 0)
639                                         && (strlen($feadr->personal))) {
640
641                                         $personal = imap_mime_header_decode($feadr->personal);
642                                         $data["name"] = "";
643                                         foreach($personal as $perspart)
644                                                 if ($perspart->charset != "default")
645                                                         $data["name"] .= iconv($perspart->charset, 'UTF-8//IGNORE', $perspart->text);
646                                                 else
647                                                         $data["name"] .= $perspart->text;
648
649                                         $data["name"] = notags($data["name"]);
650                                 }
651                         }
652                 }
653                 imap_close($mbox);
654
655                 return $data;
656         }
657 }
658 ?>