]> git.mxchange.org Git - friendica.git/blobdiff - boot.php
Merge pull request #96 from fabrixxm/api
[friendica.git] / boot.php
index 34be06c81607b164e7861800d1394db09c3d78d7..cddba996c22a3a02245797f06b6962ebe3d1293a 100644 (file)
--- a/boot.php
+++ b/boot.php
@@ -1,15 +1,26 @@
 <?php
 
 set_time_limit(0);
+ini_set('pcre.backtrack_limit', 250000);
 
-define ( 'FRIENDIKA_VERSION',      '2.1.939' );
-define ( 'DFRN_PROTOCOL_VERSION',  '2.2'  );
-define ( 'DB_UPDATE_VERSION',      1046   );
+define ( 'FRIENDIKA_VERSION',      '2.1.969' );
+define ( 'DFRN_PROTOCOL_VERSION',  '2.21'    );
+define ( 'DB_UPDATE_VERSION',      1054      );
 
 define ( 'EOL',                    "<br />\r\n"     );
 define ( 'ATOM_TIME',              'Y-m-d\TH:i:s\Z' );
 define ( 'DOWN_ARROW',             '&#x21e9;'       );
-         
+
+/**
+ *
+ * Image storage quality. Lower numbers save space at cost of image detail.
+ * For ease of upgrade, please do not change here. Change jpeg quality with 
+ * set_config('system','jpeg_quality',n) in .htconfig.php
+ * where n is netween 1 and 100, and with very poor results below about 50 
+ *
+ */
+
+define ( 'JPEG_QUALITY',            100              );         
 
 /**
  * SSL redirection policies
@@ -73,6 +84,18 @@ define ( 'PAGE_SOAPBOX',           1 );
 define ( 'PAGE_COMMUNITY',         2 );
 define ( 'PAGE_FREELOVE',          3 );
 
+/**
+ * Network and protocol family types 
+ */
+
+define ( 'NETWORK_DFRN',             'dfrn');    // Friendika, Mistpark, other DFRN implementations
+define ( 'NETWORK_OSTATUS',          'stat');    // status.net, identi.ca, GNU-social, other OStatus implementations
+define ( 'NETWORK_FEED',             'feed');    // RSS/Atom feeds with no known "post/notify" protocol
+define ( 'NETWORK_DIASPORA',         'dspr');    // Diaspora
+define ( 'NETWORK_MAIL',             'mail');    // IMAP/POP
+define ( 'NETWORK_FACEBOOK',         'face');    // Facebook API     
+
+
 /**
  * Maximum number of "people who like (or don't like) this"  that we will list by name
  */
@@ -189,6 +212,7 @@ class App {
        public  $user;
        public  $cid;
        public  $contact;
+       public  $page_contact;
        public  $content;
        public  $data;
        public  $error = false;
@@ -264,7 +288,7 @@ class App {
                $this->argv = explode('/',$this->cmd);
                $this->argc = count($this->argv);
                if((array_key_exists('0',$this->argv)) && strlen($this->argv[0])) {
-                       $this->module = $this->argv[0];
+                       $this->module = str_replace(".", "_", $this->argv[0]);
                }
                else {
                        $this->module = 'home';
@@ -277,7 +301,7 @@ class App {
 
                if($this->cmd === '.well-known/host-meta') {
                        require_once('include/hostxrd.php');
-                       hostxrd($this->hostname);
+                       hostxrd($this->get_baseurl());
                        // NOTREACHED
                }
 
@@ -437,15 +461,18 @@ function check_config(&$a) {
 
        load_config('system');
 
-       if(! x($_SERVER,'SERVER_NAME'))
-               return;
-
        $build = get_config('system','build');
        if(! x($build))
                $build = set_config('system','build',DB_UPDATE_VERSION);
 
        $url = get_config('system','url');
-       if(! x($url))
+
+       // if the url isn't set or the stored url is radically different 
+       // than the currently visited url, store the current value accordingly.
+       // "Radically different" ignores common variations such as http vs https 
+       // and www.example.com vs example.com.
+
+       if((! x($url)) || (! link_compare($url,$a->get_baseurl())))
                $url = set_config('system','url',$a->get_baseurl());
 
        if($build != DB_UPDATE_VERSION) {
@@ -592,19 +619,14 @@ function reload_plugins() {
 // For instance if 'test' => "foo" and 'testing' => "bar", testing could become either bar or fooing, 
 // depending on the order in which they were declared in the array.   
 
+require_once("include/template_processor.php");
+
 if(! function_exists('replace_macros')) {  
 function replace_macros($s,$r) {
+       global $t;
+       
+       return $t->replace($s,$r);
 
-       $search = array();
-       $replace = array();
-
-       if(is_array($r) && count($r)) {
-               foreach ($r as $k => $v ) {
-                       $search[] =  $k;
-                       $replace[] = $v;
-               }
-       }
-       return str_replace($search,$replace,$s);
 }}
 
 
@@ -834,8 +856,10 @@ function login($register = false) {
                $tpl = load_view_file("view/login.tpl");
 
        }
-       
-       $o = replace_macros($tpl,array(
+
+       $o = '<script type="text/javascript"> $(document).ready(function() { $("#login-name").focus();} );</script>';   
+
+       $o .= replace_macros($tpl,array(
                '$logout'        => t('Logout'),
                '$register_html' => $register_html, 
                '$classname'     => $classname,
@@ -1207,6 +1231,7 @@ function set_config($family,$key,$value) {
        global $a;
 
        if(get_config($family,$key,true) === false) {
+               $a->config[$family][$key] = $value;
                $ret = q("INSERT INTO `config` ( `cat`, `k`, `v` ) VALUES ( '%s', '%s', '%s' ) ",
                        dbesc($family),
                        dbesc($key),
@@ -1301,6 +1326,7 @@ function set_pconfig($uid,$family,$key,$value) {
        global $a;
 
        if(get_pconfig($uid,$family,$key,true) === false) {
+               $a->config[$uid][$family][$key] = $value;
                $ret = q("INSERT INTO `pconfig` ( `uid`, `cat`, `k`, `v` ) VALUES ( %d, '%s', '%s', '%s' ) ",
                        intval($uid),
                        dbesc($family),
@@ -1478,7 +1504,9 @@ function lrdd($uri) {
                return array();
 
        logger('lrdd: host_meta: ' . $xml, LOGGER_DATA);
-       $h = simplexml_load_string($xml);
+
+       $h = parse_xml_string($xml);
+
        $arr = convert_xml_element_to_array($h);
 
        if(isset($arr['xrd']['property'])) {
@@ -1550,16 +1578,19 @@ function lrdd($uri) {
        $headers = $a->get_curl_headers();
        logger('lrdd: headers=' . $headers, LOGGER_DEBUG);
 
-       require_once('library/HTML5/Parser.php');
-       $dom = @HTML5_Parser::parse($html);
-
-       if($dom) {
-               $items = $dom->getElementsByTagName('link');
-               foreach($items as $item) {
-                       $x = $item->getAttribute('rel');
-                       if($x == "lrdd") {
-                               $pagelink = $item->getAttribute('href');
-                               break;
+       // don't try and parse raw xml as html
+       if(! strstr($html,'<?xml')) {
+               require_once('library/HTML5/Parser.php');
+               $dom = @HTML5_Parser::parse($html);
+
+               if($dom) {
+                       $items = $dom->getElementsByTagName('link');
+                       foreach($items as $item) {
+                               $x = $item->getAttribute('rel');
+                               if($x == "lrdd") {
+                                       $pagelink = $item->getAttribute('href');
+                                       break;
+                               }
                        }
                }
        }
@@ -1638,7 +1669,7 @@ function fetch_xrd_links($url) {
                return array();
 
        logger('fetch_xrd_links: ' . $xml, LOGGER_DATA);
-       $h = simplexml_load_string($xml);
+       $h = parse_xml_string($xml);
        $arr = convert_xml_element_to_array($h);
 
        $links = array();
@@ -1826,38 +1857,6 @@ function allowed_email($email) {
        return $found;
 }}
 
-// Format the like/dislike text for a profile item
-// $cnt = number of people who like/dislike the item
-// $arr = array of pre-linked names of likers/dislikers
-// $type = one of 'like, 'dislike'
-// $id  = item id
-// returns formatted text
-
-if(! function_exists('format_like')) {
-function format_like($cnt,$arr,$type,$id) {
-       $o = '';
-       if($cnt == 1)
-               $o .= (($type === 'like') ? sprintf( t('%s likes this.'), $arr[0]) : sprintf( t('%s doesn\'t like this.'), $arr[0])) . EOL ;
-       else {
-               $spanatts = 'class="fakelink" onclick="openClose(\'' . $type . 'list-' . $id . '\');"';
-               $o .= (($type === 'like') ? 
-                                       sprintf( t('<span  %1$s>%2$d people</span> like this.'), $spanatts, $cnt)
-                                        : 
-                                       sprintf( t('<span  %1$s>%2$d people</span> don\'t like this.'), $spanatts, $cnt) ); 
-               $o .= EOL ;
-               $total = count($arr);
-               if($total >= MAX_LIKERS)
-                       $arr = array_slice($arr, 0, MAX_LIKERS - 1);
-               if($total < MAX_LIKERS)
-                       $arr[count($arr)-1] = t('and') . ' ' . $arr[count($arr)-1];
-               $str = implode(', ', $arr);
-               if($total >= MAX_LIKERS)
-                       $str .= sprintf( t(', and %d other people'), $total - MAX_LIKERS );
-               $str = (($type === 'like') ? sprintf( t('%s like this.'), $str) : sprintf( t('%s don\'t like this.'), $str));
-               $o .= "\t" . '<div id="' . $type . 'list-' . $id . '" style="display: none;" >' . $str . '</div>';
-       }
-       return $o;
-}}
 
 
 // wrapper to load a view template, checking for alternate
@@ -1865,13 +1864,19 @@ function format_like($cnt,$arr,$type,$id) {
 
 if(! function_exists('load_view_file')) {
 function load_view_file($s) {
-       global $lang;
+       global $lang, $a;
        if(! isset($lang))
                $lang = 'en';
        $b = basename($s);
        $d = dirname($s);
        if(file_exists("$d/$lang/$b"))
                return file_get_contents("$d/$lang/$b");
+       
+       $theme = current_theme();
+       
+       if(file_exists("$d/theme/$theme/$b"))
+               return file_get_contents("$d/theme/$theme/$b");
+                       
        return file_get_contents($s);
 }}
 
@@ -1955,29 +1960,6 @@ return str_replace ("%","=",rawurlencode($s));
 }} 
 
 
-if(! function_exists('like_puller')) {
-function like_puller($a,$item,&$arr,$mode) {
-
-       $url = '';
-       $sparkle = '';
-       $verb = (($mode === 'like') ? ACTIVITY_LIKE : ACTIVITY_DISLIKE);
-
-       if((activity_match($item['verb'],$verb)) && ($item['id'] != $item['parent'])) {
-               $url = $item['author-link'];
-               if((local_user()) && (local_user() == $item['uid']) && ($item['network'] === 'dfrn') && (! $item['self']) && (link_compare($item['author-link'],$item['url']))) {
-                       $url = $a->get_baseurl() . '/redir/' . $item['contact-id'];
-                       $sparkle = ' class="sparkle" ';
-               }
-               if(! ((isset($arr[$item['parent'] . '-l'])) && (is_array($arr[$item['parent'] . '-l']))))
-                       $arr[$item['parent'] . '-l'] = array();
-               if(! isset($arr[$item['parent']]))
-                       $arr[$item['parent']] = 1;
-               else    
-                       $arr[$item['parent']] ++;
-               $arr[$item['parent'] . '-l'][] = '<a href="'. $url . '"'. $sparkle .'>' . $item['author-name'] . '</a>';
-       }
-       return;
-}}
 
 if(! function_exists('get_mentions')) {
 function get_mentions($item) {
@@ -2024,18 +2006,7 @@ function contact_block() {
        if(count($r)) {
                $o .= '<h4 class="contact-h4">' .  sprintf( tt('%d Contact','%d Contacts', $total),$total) . '</h4><div id="contact-block">';
                foreach($r as $rr) {
-                       $redirect_url = $a->get_baseurl() . '/redir/' . $rr['id'];
-                       if(local_user() && ($rr['uid'] == local_user())
-                               && ($rr['network'] === 'dfrn')) {
-                               $url = $redirect_url;
-                               $sparkle = ' sparkle';
-                       }
-                       else {
-                               $url = $rr['url'];
-                               $sparkle = '';
-                       }
-
-                       $o .= '<div class="contact-block-div"><a class="contact-block-link' . $sparkle . '" href="' . $url . '" ><img class="contact-block-img' . $sparkle . '" src="' . $rr['micro'] . '" title="' . $rr['name'] . ' [' . $rr['url'] . ']" alt="' . $rr['name'] . '" /></a></div>' . "\r\n";
+                       $o .= micropro($rr,true,'mpfriend');
                }
                $o .= '</div><div id="contact-block-end"></div>';
                $o .=  '<div id="viewcontacts"><a id="viewcontacts-link" href="viewcontacts/' . $a->profile['nickname'] . '">' . t('View Contacts') . '</a></div>';
@@ -2049,6 +2020,35 @@ function contact_block() {
 
 }}
 
+if(! function_exists('micropro')) {
+function micropro($contact, $redirect = false, $class = '') {
+
+       if($class)
+               $class = ' ' . $class;
+
+       $url = $contact['url'];
+       $sparkle = '';
+
+       if($redirect) {
+               $a = get_app();
+               $redirect_url = $a->get_baseurl() . '/redir/' . $contact['id'];
+               if(local_user() && ($contact['uid'] == local_user()) && ($contact['network'] === 'dfrn')) {
+                       $url = $redirect_url;
+                       $sparkle = ' sparkle';
+               }
+       }
+       $click = ((x($contact,'click')) ? ' onclick="' . $contact['click'] . '" ' : '');
+       if($click)
+               $url = '';
+       return '<div class="contact-block-div' . $class . '"><a class="contact-block-link' . $class . $sparkle 
+               . (($click) ? ' fakelink' : '') . '" '
+               . (($url) ? ' href="' . $url . '"' : '') . $click . ' ><img class="contact-block-img' . $class . $sparkle . '" src="' 
+               . $contact['micro'] . '" title="' . $contact['name'] . ' [' . $contact['url'] . ']" alt="' . $contact['name'] 
+               . '" /></a></div>' . "\r\n";
+}}
+
+
+
 if(! function_exists('search')) {
 function search($s) {
        $a = get_app();
@@ -2140,7 +2140,7 @@ function smilies($s) {
        $a = get_app();
 
        return str_replace(
-       array( '&lt;3', '&lt;/3', '&lt;\\3', ':-)', ';-)', ':-(', ':(', ':-P', ':-"', ':-x', ':-X', ':-D', '8-|', '8-O'),
+       array( '&lt;3', '&lt;/3', '&lt;\\3', ':-)', ';-)', ':-(', ':(', ':-P', ':P', ':-"', ':-x', ':-X', ':-D', '8-|', '8-O'),
        array(
                '<img src="' . $a->get_baseurl() . '/images/smiley-heart.gif" alt="<3" />',
                '<img src="' . $a->get_baseurl() . '/images/smiley-brokenheart.gif" alt="</3" />',
@@ -2150,6 +2150,7 @@ function smilies($s) {
                '<img src="' . $a->get_baseurl() . '/images/smiley-frown.gif" alt=":-(" />',
                '<img src="' . $a->get_baseurl() . '/images/smiley-frown.gif" alt=":(" />',
                '<img src="' . $a->get_baseurl() . '/images/smiley-tongue-out.gif" alt=":-P" />',
+               '<img src="' . $a->get_baseurl() . '/images/smiley-tongue-out.gif" alt=":P" />',
                '<img src="' . $a->get_baseurl() . '/images/smiley-kiss.gif" alt=":-\"" />',
                '<img src="' . $a->get_baseurl() . '/images/smiley-kiss.gif" alt=":-x" />',
                '<img src="' . $a->get_baseurl() . '/images/smiley-kiss.gif" alt=":-X" />',
@@ -2267,8 +2268,15 @@ function profile_sidebar($profile) {
 
        $photo = '<div id="profile-photo-wrapper"><img class="photo" src="' . $profile['photo'] . '" alt="' . $profile['name'] . '" /></div>';
 
+       // don't show connect link to yourself
+       
        $connect = (($profile['uid'] != local_user()) ? '<li><a id="dfrn-request-link" href="dfrn_request/' . $profile['nickname'] . '">' . t('Connect') . '</a></li>' : '');
+
+       // don't show connect link to authenticated visitors either
+
+       if((remote_user()) && ($_SESSION['visitor_visiting'] == $profile['uid']))
+               $connect = ''; 
+
        if((x($profile,'address') == 1) 
                || (x($profile,'locality') == 1) 
                || (x($profile,'region') == 1) 
@@ -2293,9 +2301,9 @@ function profile_sidebar($profile) {
 
        $pubkey = ((x($profile,'pubkey') == 1) ? '<div class="key" style="display:none;">' . $profile['pubkey'] . '</div>' : '');
 
-       $marital = ((x($profile,'marital') == 1) ? '<div class="marital"><span class="marital-label"><span class="heart">&hearts;</span> ' . t('Status:') . ' </span><span class="marital-text">' . $profile['marital'] . '</span></div></div><div class="profile-clear"></div>' : '');
+       $marital = ((x($profile,'marital') == 1) ? '<div class="marital"><span class="marital-label"><span class="heart">&hearts;</span> ' . t('Status:') . ' </span><span class="marital-text">' . $profile['marital'] . '</span></div><div class="profile-clear"></div>' : '');
 
-       $homepage = ((x($profile,'homepage') == 1) ? '<div class="homepage"><span class="homepage-label">' . t('Homepage:') . ' </span><span class="homepage-url">' . linkify($profile['homepage']) . '</span></div></div><div class="profile-clear"></div>' : '');
+       $homepage = ((x($profile,'homepage') == 1) ? '<div class="homepage"><span class="homepage-label">' . t('Homepage:') . ' </span><span class="homepage-url">' . linkify($profile['homepage']) . '</span></div><div class="profile-clear"></div>' : '');
 
        $tpl = load_view_file('view/profile_vcard.tpl');
 
@@ -2514,34 +2522,38 @@ function proc_run($cmd){
        proc_close(proc_open($cmdline." &",array(),$foo));
 }}
 
-/*
- * Return full URL to theme which is currently in effect.
- * Provide a sane default if nothing is chosen or the specified theme does not exist.
- */
-
-if(! function_exists('current_theme_url')) {
-function current_theme_url() {
-
+if(! function_exists('current_theme')) {
+function current_theme(){
        $app_base_themes = array('duepuntozero', 'loozah');
-
+       
        $a = get_app();
-
+       
        $system_theme = ((isset($a->config['system']['theme'])) ? $a->config['system']['theme'] : '');
-       $theme_name = ((x($_SESSION,'theme')) ? $_SESSION['theme'] : $system_theme);
-
+       $theme_name = ((is_array($_SESSION) && x($_SESSION,'theme')) ? $_SESSION['theme'] : $system_theme);
+       
        if($theme_name && file_exists('view/theme/' . $theme_name . '/style.css'))
-               return($a->get_baseurl() . '/view/theme/' . $theme_name . '/style.css'); 
-
+               return($theme_name);
+       
        foreach($app_base_themes as $t) {
                if(file_exists('view/theme/' . $t . '/style.css'))
-                       return($a->get_baseurl() . '/view/theme/' . $t . '/style.css'); 
-       }       
-
+                       return($t);
+       }
+       
        $fallback = glob('view/theme/*/style.css');
        if(count($fallback))
-               return($a->get_baseurl() . $fallback[0]);
+               return (str_replace('view/theme/','', str_replace("/style.css","",$fallback[0])));
 
-       
+}}
+
+/*
+* Return full URL to theme which is currently in effect.
+* Provide a sane default if nothing is chosen or the specified theme does not exist.
+*/
+if(! function_exists('current_theme_url')) {
+function current_theme_url() {
+       global $a;
+       $t = current_theme();
+       return($a->get_baseurl() . '/view/theme/' . $t . '/style.css');
 }}
 
 if(! function_exists('feed_birthday')) {
@@ -2632,7 +2644,7 @@ if(! function_exists('get_plink')) {
 function get_plink($item) {
        $a = get_app(); 
        $plink = (((x($item,'plink')) && (! $item['private'])) ? '<div class="wall-item-links-wrapper"><a href="' 
-                       . $item['plink'] . '" title="' . t('link to source') . '" target="external-link" ><img src="' . $a->get_baseurl() . '/images/remote-link.gif" alt="' . t('link to source') . '" /></a></div>' : '');
+                       . $item['plink'] . '" title="' . t('link to source') . '" target="external-link" class="icon remote-link"></a></div>' : '');
        return $plink;
 }}
 
@@ -2641,106 +2653,6 @@ function unamp($s) {
        return str_replace('&amp;', '&', $s);
 }}
 
-if(! function_exists('extract_item_authors')) {
-function extract_item_authors($arr,$uid) {
-
-       if((! $uid) || (! is_array($arr)) || (! count($arr)))
-               return array();
-       $urls = array();
-       foreach($arr as $rr) {
-               if(! in_array("'" . dbesc($rr['author-link']) . "'",$urls))
-                       $urls[] = "'" . dbesc($rr['author-link']) . "'";
-       }
-
-       // pre-quoted, don't put quotes on %s
-       if(count($urls)) {
-               $r = q("SELECT `id`,`url` FROM `contact` WHERE `uid` = %d AND `url` IN ( %s ) AND `network` = 'dfrn' AND `self` = 0 AND `blocked` = 0 ",
-                       intval($uid),
-                       implode(',',$urls)
-               );
-               if(count($r)) {
-                       $ret = array();
-                       foreach($r as $rr)
-                               $ret[$rr['url']] = $rr['id'];
-                       return $ret;
-               }
-       }
-       return array();         
-}}
-
-if(! function_exists('item_photo_menu')){
-function item_photo_menu($item){
-       $a = get_app();
-       
-       if (!isset($a->authors)){
-               $rr = q("SELECT id, network, url FROM contact WHERE uid=%d AND self!=1", intval(local_user()));
-               $authors = array();
-               foreach($rr as $r) $authors[$r['url']]= $r;
-               $a->authors = $authors;
-       }
-       
-       $contact_url="";
-       $pm_url="";
-
-       $status_link="";
-       $photo_link="";
-       $profile_link   = ((strlen($item['author-link']))   ? $item['author-link'] : $item['url']);
-       $redirect_url = $a->get_baseurl() . '/redir/' . $item['cid'] ;
-
-       $contact_uid = ((x($item,'contact-uid')) && intval($item['contact-uid']) ? intval($item['contact-uid']) : 0);   
-
-       // $item['contact-uid'] is only set on profile page.
-       // So we are checking for a profile page where the viewer owns the page,
-       // otherwise a logged in user if some other page that displays items.
-       // Then check if we can use a sparkle (redirect) link to the profile by virtue of it being our contact
-       // or a friend's contact that we both have a connection to. 
-
-       if(((local_user() && (! $contact_uid)) || ($contact_uid && $contact_uid == local_user())) && strlen($item['author-link'])) {
-               if(link_compare($item['author-link'],$item['url']) && ($item['network'] === 'dfrn') && (! $item['self'])) {
-                       $status_link = $redirect_url."?url=status";
-                       $profile_link = $redirect_url."?url=profile";
-                       $photos_link = $redirect_url."?url=photos";
-                       if (local_user() && (! link_compare($_SESSION['my_url'],$item['author-link']))) {
-                               $pm_url = $a->get_baseurl() . '/message/new/' . $item['cid'];
-                               $contact_url = $item['self']?"":$a->get_baseurl() . '/contacts/' . $item['cid'];
-                       }
-               } 
-               elseif(isset($a->authors[$item['author-link']])) {
-                       $redirect_url = $a->get_baseurl() . '/redir/' . $a->authors[$item['author-link']]['id'];
-                       $status_link = $redirect_url."?url=status";
-                       $profile_link = $redirect_url."?url=profile";
-                       $photos_link = $redirect_url."?url=photos";
-
-                       if (local_user() && (! link_compare($_SESSION['my_url'],$a->authors[$item['author-link']]['url']))) {
-                               if ($a->authors[$item['author-link']]['network']==='dfrn'){
-                                       $pm_url = $a->get_baseurl() . '/message/new/' . $a->authors[$item['author-link']]['id'];
-                               }
-                               $contact_url = $item['self']?"":$a->get_baseurl() . '/contacts/' . $a->authors[$item['author-link']]['id'] ;
-                       }
-                                               
-               }
-       }
-
-
-       $menu = Array(
-               t("View status") => $status_link,
-               t("View profile") => $profile_link,
-               t("View photos") => $photos_link,               
-               t("Edit contact") => $contact_url,
-               t("Send PM") => $pm_url,
-       );
-       
-       
-       $args = array($item, &$menu);
-       
-       call_hooks('item_photo_menu', $args);
-       
-       $o = "";
-       foreach($menu as $k=>$v){
-               if ($v!="") $o .= "<li><a href='$v'>$k</a></li>\n";
-       }
-       return $o;
-}}
 
 if(! function_exists('lang_selector')) {
 function lang_selector() {
@@ -2761,3 +2673,18 @@ function lang_selector() {
        $o .= '</select></form></div>';
        return $o;
 }}
+
+
+if(! function_exists('parse_xml_string')) {
+function parse_xml_string($s) {
+       if(! strstr($s,'<?xml'))
+               return false;
+       $s2 = substr($s,strpos($s,'<?xml'));
+       libxml_use_internal_errors(true);
+       $x = @simplexml_load_string($s2);
+       if(count(libxml_get_errors()))
+               foreach(libxml_get_errors() as $err)
+                       logger('libxml: parse: ' . $err->code." at ".$err->line.":".$err->column." : ".$err->message, LOGGER_DATA);
+       libxml_clear_errors();
+       return $x;
+}}