Current File : /home/lifechur/carp/carp/carpinc.php
<?php
/*
CaRP Evolution v4.1.8
Copyright (c) 2002-22 Antone Roundy

All rights reserved
This program may not be redistributed in whole or in part without written
permission from the copyright owner.

https://www.geckotribe.com/rss/carp/
Installation & Configuration Manual: http://carp.docs.geckotribe.com/
*/

class RSSParser {
	var $insideitem=0;
	var $insidechannel=0;
	var $displaychannel;
	var $tag='';
	var $tagName=array();
	var $dups;
	var $ivalues;
	var $cvalues;
	var $itemcount=0;
	var $itemindex=0;
	var $top='';
	var $bottom='';
	var $body='';
	var $showit;
	var $tagpairs;
	var $filterin;
	var $filterout;
	var $filterinfield;
	var $filteroutfield;
	var $linktargets=array('',' target="_blank"',' target="_top"');
	var $channelborder;
	var $channelaorder;
	var $itemorder;
	var $formatCheck;
	var $isatom;
	var $moreitems=1;
	var $xmlbase;
	var $isinline=0;
	var $inlinetype=0;
	var $thisdata;
	var $getdata=0;
	var $encodingout='';

	function SetItemOrder($iord) {
		$this->itemorder=explode(',',preg_replace('/[^a-z0-9,]/','',strtolower($iord)));
	}

	function GetFieldValue($name,$ischannel=0) {
		global $carpcapriority,$carpiapriority,$carpcallbacks;

		$name=strtolower($name);
		$rv='';
		if ($ischannel) {
			$priority=&$carpcapriority;
			$values=&$this->cvalues;
		} else {
			$priority=&$carpiapriority;
			$values=&$this->ivalues;
		}
		if (isset($priority["$name"])) {
			foreach ($priority["$name"] as $fn => $val) {
				if ($fn[0]==':') $fn=substr($fn,strpos($fn,':',1)+1);
				if (isset($values["$fn"])) {
					$got=1;
					if (is_array($val)) {
						for ($i=1,$j=count($val);$i<$j;$i+=2) {
							if (
								(($val[$i+1]!='')!=($values[$val[$i]]!=''))||
								(($val[$i+1]!='')&&!preg_match($val[$i+1],$values[$val[$i]]))
							) {
								$got=0;
								break;
							}
						}
					}
					if ($got) {
						$rv=$values["$fn"];
						break;
					}
				}
			}
		}
		foreach ($carpcallbacks['getfieldvalue'] as $cb)
			if (($cb[2]=='')||($cb[2]==$name))
				$rv=call_user_func(($cb[0]==='')?$cb[1]:array($cb[0],$cb[1]),$ischannel?0:1,$name,$rv);
		return $rv;
	}

	function CheckFilter($lookfor,$field) {
		if (!empty($field)) {
			if (strpos(strtolower($this->GetFieldValue($field)),$lookfor)!==false) return 1;
		} else {
			if (strpos(strtolower($this->GetFieldValue('TITLE').' '.$this->GetFieldValue('DESC')),$lookfor)!==false) return 1;
		}
		return 0;
	}

	function Truncate(&$text,$max,$after,$afterlen) {
		if (($max>0)&&(CarpStrLen(preg_replace("/<.*?>/",'',$text))>$max)) {
			$j=strlen($text);
			$truncmax=$max-$afterlen;
			$isUTF8=$this->encodingout=='UTF-8';
			$out='';
			for ($i=0,$len=0;($len<$truncmax)&&($i<$j);$i++) {
				switch($text[$i]) {
				case '<':
					for ($k=$i+1;($k<$j)&&($text[$k]!='>');$k++) {
						if (($text[$k]=='"')||($text[$k]=="'")) {
							if ($m=strpos($text,$text[$k],$k+1)) $k=$m;
							else $k=$j;
						}
					}
					if (($k<$j)&&($text[$k]=='>')) $out.=substr($text,$i,$k+1-$i);
					$i=$k;
					break;
				case '&':
					if ($text[$i+1]=='#') {
						if ($text[$i+2]=='x') {
							$matchset='/[0-9]/';
							$start=$i+3;
						} else {
							$matchset='/[0-9a-fA-F]/';
							$start=$i+2;
						}
					} else {
						$matchset='/[a-zA-Z]/';
						$start=$i+1;
					}
					$valid=0;
					for ($k=$start;$k<$j;$k++) {
						$c=$text[$k];
						if (($c==';')||($c==' ')) {
							if ($k>$start) $valid=1;
							if ($c==' ') $k--;
							break;
						} else if (!preg_match($matchset,$c)) break;
					}
					if ($valid) {
						$out.=substr($text,$i,$k+1-$i);
						$i=$k;
					} else $out.='&amp;';
					$len++;
					break;
				default:
					if ($isUTF8) {
						$val=ord($text[$i]);
						$bytes=($val<=0x7F)?1:(($val<=0xDF)?2:(($val<=0xEF)?3:4));
						$out.=substr($text,$i,$bytes);
						$i+=($bytes-1);
					} else $out.=$text[$i];
					$len++;
				}
			}
			$did=$i<$j;
			$text=$out.($did?$after:'');
		} else $did=0;
		return $did;
	}

	function ApplyXMLBase($url,$basedomain,$basepath) {
		if (($url!='')&&($url[0]=='/')) $url=$basedomain.$url;
		else if (!preg_match('#^[a-zA-Z]+://#',$url))
			$url=$basedomain.(($where=strrpos($basepath,'/'))?substr($basepath,0,$where):'')."/$url";
		return $url;
	}
	function GetXMLBase($i) {
		if ($i==-1) $i=count($this->xmlbase)-1;
		if (!preg_match('#^[a-zA-Z]+://#',$this->xmlbase[$i])) {
			if ($i&&preg_match('#^([a-zA-Z]+://[^/]+)(/.*)?$#',$this->GetXMLBase($i-1),$matches)) {
				$this->xmlbase[$i]=$this->ApplyXMLBase($this->xmlbase[$i],$matches[1],(!empty($matches[2]))?$matches[2]:'/');
			} // else error--return what we've got and hope for the best
		}
		return $this->xmlbase[$i];
	}
	function CleanURL($val) {
		global $carpconf;
		if (($val!='')&&(($val[0]=='/')||!preg_match('#^[a-zA-Z]+://#',$val))) {
			if (preg_match('#^([a-zA-Z]+://[^/]+)(/.*)?$#',$this->GetXMLBase(-1),$matches)) {
				$val=$this->ApplyXMLBase($val,$matches[1],(!empty($matches[2]))?$matches[2]:'/');
			} // else bad base URI
		}
		return preg_replace("/<[^>]*>/",'',$carpconf['html-urls']?str_replace('"','&quot;',str_replace('&','&amp;',trim($val))):trim($val));
	}

	function FormatLink($title,$link,$class,$style,$maxtitle,$atrunc,$atrunclen,$btitle,$atitle,$deftitle,$titles,$attrs) {
		global $carpcallbacks;
		global $carpconf;

		$fulltitle=$title=trim(preg_replace("/<.*?>/",'',$title));
		$didTrunc=$this->Truncate($title,$maxtitle,$atrunc,$atrunclen);
		if ($title=='') $title=$deftitle;

		$rv=$btitle.
			(($link!='')?(
				"<a href=\"$link\"".$this->linktargets[$carpconf['linktarget']].
				((($titles&&$didTrunc)||($titles==2))?" title=\"".str_replace('"','&quot;',$fulltitle)."\"":'')
			):(("$class$style"!='')?'<span':'')).
			(($class!='')?(' class="'.$class.'"'):'').
			(($style!='')?(' style="'.$style.'"'):'').
			((($link!='')&&($attrs!=''))?" $attrs ":'').
			(("$link$class$style"!='')?'>':'').
			$title.
			(($link!='')?'</a>':(("$class$style"!='')?'</span>':'')).
			$atitle.$carpconf['afield'];
		foreach ($carpcallbacks['outputfield'] as $cb)
			if (($cb[2]=='')||($cb[2]=='title')||($cb[2]=='link'))
				$rv=call_user_func(($cb[0]==='')?$cb[1]:array($cb[0],$cb[1]),$this->insideitem,(($link!='')?'link':'title'),
					$this->itemindex,$this->itemcount,$rv);
		return $rv;
	}

	function FormatImage($url,$link,$w,$h,$alt,$ci) {
		global $carpcallbacks;
		global $carpconf;
		if ($url!='') {
			if ($carpconf["set$ci".'imagew']) {
				if ($carpconf["set$ci".'imageh']) {
					$w=$carpconf["set$ci".'imagew'];
					$h=$carpconf["set$ci".'imageh'];
				} else {
					if ($w) {
						$sr=$carpconf["set$ci".'imagew']/$w;
						$h=round($h*$sr);
					}
					$w=$carpconf["set$ci".'imagew'];
				}
			} else if ($carpconf["set$ci".'imageh']) {
				if ($h) {
					$sr=$carpconf["set$ci".'imageh']/$h;
					$w=round($w*$sr);
				}
				$h=$carpconf["set$ci".'imageh'];
			} else if ($carpconf["max$ci".'imagew']&&($w>$carpconf["max$ci".'imagew'])) {
				$wr=($carpconf["max$ci".'imagew']/$w);
				if ($carpconf["max$ci".'imageh']) {
					$hr=($h>$carpconf["max$ci".'imageh'])?($carpconf["max$ci".'imageh']/$h):1;
					$sr=min($wr,$hr);
					$w=round($w*$sr);
					$h=round($h*$sr);
				} else {
					$w=$carpconf["max$ci".'imagew'];
					$h=round($h*$wr);
				}
			} else if ($carpconf["max$ci".'imageh']&&($h>$carpconf["max$ci".'imageh'])) {
				$sr=($carpconf["max$ci".'imageh']/$h);
				$h=$carpconf["max$ci".'imageh'];
				$w=round($w*$sr);
			}
			if (!$w&&$carpconf["def$ci".'imagew']) $w=$carpconf["def$ci".'imagew'];
			if (!$h&&$carpconf["def$ci".'imageh']) $h=$carpconf["def$ci".'imageh'];
			$rv=($carpconf["b$ci".'image'].
				(($link!='')?('<a href="'.$link.'"'.$this->linktargets[$carpconf['linktarget']].'>'):'').
				'<img src="'.$url.'"'.($w?" width=\"$w\"":'').($h?" height=\"$h\"":'').' border="0"'.(($alt!='')?(' alt="'.str_replace('"','&quot;',$alt).'"'):'').' />'.
				(($link!='')?'</a>':'').
				$carpconf["a$ci".'image'].$carpconf['afield']);
		} else $rv='';
		foreach ($carpcallbacks['outputfield'] as $cb)
			if (($cb[2]=='')||($cb[2]=='image'))
				$rv=call_user_func(($cb[0]==='')?$cb[1]:array($cb[0],$cb[1]),($ci=='i'),'image',$this->itemindex,$this->itemcount,$rv);
		return $rv;
	}

	function FormatDate($val,$ci) {
		global $carpcallbacks;
		global $carpconf;
		$rv=($val>0)?($carpconf["b$ci".'date'].($carpconf[$ci.'useidate']?
				strftime($carpconf[$ci.'idateformat'],$val):
				date($carpconf[$ci.'dateformat'],$val)
			).$carpconf["a$ci".'date'].$carpconf['afield']):'';
		foreach ($carpcallbacks['outputfield'] as $cb)
			if (($cb[2]=='')||($cb[2]=='date'))
				$rv=call_user_func(($cb[0]==='')?$cb[1]:array($cb[0],$cb[1]),($ci=='i'),'date',$this->itemindex,$this->itemcount,$rv);
		return $rv;
	}

	function FormatSimpleField($val,$ci,$name,$fixamp=0) {
		global $carpcallbacks;
		global $carpconf;
		if ($fixamp) $val=str_replace('&','&amp;',$val);
		$rv=($val!='')?($carpconf["b$ci$name"].$val.$carpconf["a$ci$name"].$carpconf['afield']):'';
		foreach ($carpcallbacks['outputfield'] as $cb)
			if (($cb[2]=='')||($cb[2]==$name))
				$rv=call_user_func(($cb[0]==='')?$cb[1]:array($cb[0],$cb[1]),($ci=='i'),$name,$this->itemindex,$this->itemcount,$rv);
		return $rv;
	}

	function ListOpenTags(&$input) {
		if (preg_match_all("#<(/?\w+).*?>#",$input,$matches)) {
			$rv=$matches[1];
			for ($i=0;$i<count($rv);$i++) {
				$tag=$rv[$i]=strtolower($rv[$i]);
				if ($isClose=($tag[0]=='/')) $tag=substr($tag,1);
				if (!isset($this->tagpairs["$tag"])) {
					array_splice($rv,$i,1);
					$i--;
				} else if ($isClose) {
					array_splice($rv,$i,1);
					$i--;
					for ($j=$i;$j>=0;$j--) {
						if ($rv[$j]==$tag) {
							array_splice($rv,$j,1);
							$i--;
							break;
						}
					}
				}
			}
		} else $rv=array();
		return $rv;
	}

	function ProcessDescription($description,$maxdesc,$atrunc,$atrunclen) {
		global $carpconf;
		if ($description!='') {
			if ($carpconf['desctags']!='') {
				$adddesc=trim(preg_replace("#<(?!".$carpconf['desctags'].")(.*?)>#is",
					($carpconf['removebadtags']?'':"&lt;\\1\\2&gt;"),$description));
				$adddesc=preg_replace('/(<[^>]*?)\bon[a-z]+\s*=\s*("[^"]*"|\'[^\']*\')(.*?>)/i',"\\1\\3",$adddesc);
			} else $adddesc=trim(preg_replace("#<(.*?)>#s",($carpconf['removebadtags']?'':"&lt;\\1&gt;"),$description));
			$didTrunc=$this->Truncate($adddesc,$maxdesc,'',$atrunclen);

			$opentags=$this->ListOpenTags($adddesc);
			if ($adddesc!='') {
				if ($didTrunc) $adddesc.=$atrunc;
				for ($i=count($opentags)-1;$i>=0;$i--) $adddesc.="</$opentags[$i]>";
			}
		} else $adddesc='';
		return $adddesc;
	}

	function FormatDescription($description,$maxdesc,$b,$a,$atrunc,$atrunclen) {
		global $carpcallbacks;
		global $carpconf;
		$adddesc=$this->ProcessDescription($description,$maxdesc,$atrunc,$atrunclen);
		if ($adddesc!='') $adddesc="$b$adddesc$a".$carpconf['afield'];
		foreach ($carpcallbacks['outputfield'] as $cb)
			if (($cb[2]=='')||($cb[2]=='desc'))
				$adddesc=call_user_func(($cb[0]==='')?$cb[1]:array($cb[0],$cb[1]),$this->insideitem,'desc',$this->itemindex,$this->itemcount,$adddesc);
		return $adddesc;
	}

	function XMLFormatError($show=0) {
		switch ($this->formatCheck) {
		case -1: $rv='Unknown RDF-based format or non-standard RSS element name prefix.'; break;
		case -11:
		case -12: $rv='Unknown feed format.'; break;
		case -20: $rv='This appears to be an HTML webpage, not a feed.'; break;
		case -100:
		case -101: $rv='Unknown document format.'; break;
		default: $rv='';
		}
		if (($rv!='')&&$show) CarpError($rv,'unknown-format');
		return " - $rv";
	}

	function CheckFormat($tagName,&$attrs) {
		if (strpos($tagName,':')) {
			list($prefix,$name)=explode(':',$tagName);
			switch ($name) {
			case 'RDF':
				foreach ($attrs as $k=>$v) {
					if ((strpos($k,'XMLNS')===0)&&(strpos($v,'http://purl.org/rss/')===0)) {
						$this->formatCheck=1;
						break;
					}
				}
				if (!$this->formatCheck) $this->formatCheck=-1;
				break;
			case 'feed':
				switch ($attrs["XMLNS:$prefix"]) {
				case 'http://www.w3.org/2005/Atom': $this->formatCheck=10; break;
				case 'http://purl.org/atom/ns#': $this->formatCheck=3; break;
				default: $this->formatCheck=-11;
				}
				break;
			default: $this->formatCheck=-100;
			}
		} else {
			switch($tagName) {
			case 'RSS': $this->formatCheck=2; break;
			case 'HTML': $this->formatCheck=-20; break;
			case 'FEED':
				switch ($attrs["XMLNS"]) {
				case 'http://www.w3.org/2005/Atom': $this->formatCheck=10; break;
				case 'http://purl.org/atom/ns#': $this->formatCheck=3; break;
				default: $this->formatCheck=-12;
				}
				break;
			default: $this->formatCheck=-101;
			}
		}
		switch($this->formatCheck) {
		case 3: case 10: $this->isatom=1; break;
		default: $this->isatom=0;
		}
	}

	function MapPrefix(&$tagName,&$attrs) {
		global $carpconf;
		foreach ($carpconf['prefix-map'] as $k=>$v) {
			if ($v!='') $v="$v:";
			$tagName=preg_replace("/^$k:/",$v,$tagName);
			if (is_array($attrs)) {
				$newattrs=array();
				foreach ($attrs as $ak=>$av) {
					if (($nak=preg_replace("/^$k:/","$v:",$ak))!=$ak) $newattrs[$nak]=$av;
					else $newattrs[$ak]=$av;
				}
				$attrs=$newattrs;
			}
		}
	}

	function startElement($parser,$tagName,$attrs) {
		global $carpcallbacks;
		global $carpconf;
		global $carpcafields,$carpiafields,$carpurlattrs,$carpinline,$carprenametag;

		if (isset($attrs['XML:BASE'])) $this->xmlbase[]=$attrs['XML:BASE'];
		else $this->xmlbase[]='';

		if ($carpconf['strip-xhtml-prefixes']) {
			foreach ($attrs as $k=>$v)
				if ((substr($k,0,6)=='XMLNS:')&&($v=='http://www.w3.org/1999/xhtml')) {
					list($junk,$ns)=explode(':',$k,2);
					$carpconf['prefix-map'][$ns]='';
				}
		}

		$this->MapPrefix($tagName,$attrs);

		if ((!$this->isinline)&&isset($carprenametag[$tagName])) {
			foreach ($carprenametag[$tagName] as $k=>$v) {
				$is_match=1;
				for ($i=0,$j=count($v);$i<$j;$i+=2) {
					$invert=(($v[$i+1]!='')&&($v[$i+1][0]=='^'));
					if (!(isset($attrs[$v[$i]])&&(preg_match($invert?substr($v[$i+1],1):$v[$i+1],$attrs[$v[$i]])!=$invert))) {
						$is_match=0;
						break;
					}
				}
				if ($is_match) {
					$tagName=$k;
					break;
				}
			}
		}
		array_unshift($this->tagName,$tagName);

		$this->tag.=(($this->tag!='')?'^':'').$tagName;

		if (isset($carpurlattrs[$tagName])) {
			foreach ($carpurlattrs[$tagName] as $attr) if (isset($attrs[$attr]))
				$attrs[$attr]=$this->CleanURL($attrs[$attr]);
		}

		if (!$this->formatCheck) $this->CheckFormat($tagName,$attrs);

		if ($this->insideitem) {
			$f=&$carpiafields;
			$vals=&$this->ivalues;
		} else {
			$f=$carpcafields;
			$vals=&$this->cvalues;
		}

		if (!$this->isinline) {
			$this->getdata=0;
			if (isset($f[$this->tag])) {
				if (!isset($vals[$this->tag])) {
					$vals[$this->tag]='';
					$this->thisdata=&$vals[$this->tag];
					$this->getdata=1;
				}
			}
			if ($this->isatom&&$this->getdata&&in_array($tagName,$carpinline)) {
				$this->isinline=1;
				switch($this->formatCheck) {
				case 3:
					if (isset($attrs['MODE'])&&($attrs['MODE']=='base64')) $this->inlinetype+=1;
					if (!isset($attrs['TYPE'])||($attrs['TYPE']=='text/plain')) $this->inlinetype+=2;
					break;
				case 10:
					if ((!isset($attrs['TYPE']))||($attrs['TYPE']=='')||($attrs['TYPE']=='text')||($attrs['TYPE']=='text/plain'))
						$this->inlinetype=1;
					else if (isset($attrs['TYPE'])&&(($attrs['TYPE']=='xhtml')||($attrs['TYPE']=='application/xhtml+xml'))) $this->inlinetype=2;
					else if (isset($attrs['TYPE'])&&(($attrs['TYPE']=='html')||($attrs['TYPE']=='text/html'))) $this->inlinetype=3;
					break;
				}
			}
		}
		if ($this->isinline) $this->isinline++;
		if ($this->isinline>2) {
			$this->thisdata.='<'.strtolower($tagName);
			foreach ($attrs as $k=>$v) $this->thisdata.=" $k=\"".strtr($v,array('&'=>'&amp;','"'=>'&quot;')).'"';
			$this->thisdata.='>';
		} else {
			foreach ($carpcallbacks['startelement'] as $cb)
				if (($cb[2]=='')||preg_match("/$cb[2]/",$this->tag))
					call_user_func(($cb[0]==='')?$cb[1]:array($cb[0],$cb[1]),$this->insideitem,$this->tag,$attrs);
			if ($this->insidechannel) $this->insidechannel++;
			if ($this->insideitem) $this->insideitem++;
			if (($tagName=="ITEM")||($tagName=="ENTRY")) {
				$this->insideitem=1;
				$this->ivalues=array();
				$this->tag='';
			} else if (($tagName=="CHANNEL")||($tagName=="FEED")) {
				$this->insidechannel=1;
				$this->cvalues=array();
				$this->tag='';
			}
			else {
				$haveSome=0;
				foreach($attrs as $key => $val)
					if (isset($f[$this->tag."^$key"])&&isset($vals[$this->tag."^$key"])) {
						$haveSome=1;
						break;
					}
				if (!$haveSome) foreach($attrs as $key => $val)
					if (isset($f[$this->tag."^$key"])&&!isset($vals[$this->tag."^$key"])) $vals[$this->tag."^$key"]=$val;
			}
		}
	}

	function ProcessDataField($name,$is_channel=0) {
		global $carpcallbacks;
		global $carpconf;
		$rv='';
		if ($is_channel) {
			switch ($name) {
			case 'link':
			case 'title':
				$rv.=$this->FormatLink($this->GetFieldValue('TITLE',1),(($name=='link')?$this->GetFieldValue('URL',1):''),
				$carpconf['clinkclass'],$carpconf['clinkstyle'],$carpconf['maxctitle'],$carpconf['atruncctitle'],$carpconf['atruncctitlelen'],
				$carpconf['bctitle'],$carpconf['actitle'],'',$carpconf['clinktitles'],$carpconf['clink_attrs']); break;
			case 'url': $rv.=$this->FormatSimpleField($this->GetFieldValue('URL',1),'c','url',1); break;
			case 'desc':
				$rv.=$this->FormatDescription($this->GetFieldValue('DESC',1),
					$carpconf['maxcdesc'],$carpconf['bcdesc'],$carpconf['acdesc'],$carpconf['atrunccdesc'],$carpconf['atrunccdesclen']);
				break;
			case 'date': $rv.=$this->FormatDate(CarpDecodeDate($this->GetFieldValue('DATE',1)),'c'); break;
			case 'image': $rv.=$this->FormatImage($this->GetFieldValue('IMAGEURL',1),$this->GetFieldValue('IMAGELINK',1),$this->GetFieldValue('IMAGEWIDTH',1),$this->GetFieldValue('IMAGEHEIGHT',1),$this->GetFieldValue('IMAGEALT',1),'c'); break;
			default:
				$rvd='';
				foreach ($carpcallbacks['handlefield'] as $cb)
					if ($cb[2]==$name)
						$rvd=call_user_func(($cb[0]==='')?$cb[1]:array($cb[0],$cb[1]),1,$name,0,$this->cvalues,$rvd);
				$rv.=$rvd;

			}
		} else {
			switch ($name) {
			case 'link':
			case 'title':
				$rv.=$this->FormatLink($this->GetFieldValue('TITLE'),(($name=='link')?$this->GetFieldValue('URL'):''),
				$carpconf['ilinkclass'],$carpconf['ilinkstyle'],$carpconf['maxititle'],$carpconf['atruncititle'],$carpconf['atruncititlelen'],
				$carpconf['bilink'],$carpconf['ailink'],$carpconf['defaultititle'],$carpconf['ilinktitles'],$carpconf['ilink_attrs']); break;
			case 'url': $rv.=$this->FormatSimpleField($this->GetFieldValue('URL'),'i','url',1); break;
			case 'author': $rv.=$this->FormatSimpleField($this->GetFieldValue('AUTHOR'),'i','author'); break;
			case 'date':
				$rv.=$this->FormatDate(CarpDecodeDate($this->GetFieldValue('DATE')),'i'); break;
			case 'podcast': $rv.=$this->FormatSimpleField($this->GetFieldValue('PODCAST'),'i','podcast');
				break;
			case 'image': $rv.=$this->FormatImage($this->GetFieldValue('IMAGEURL'),$this->GetFieldValue('IMAGELINK'),$this->GetFieldValue('IMAGEWIDTH'),$this->GetFieldValue('IMAGEHEIGHT'),$this->GetFieldValue('IMAGEALT'),'i'); break;
			case 'desc':
				$rv.=$this->FormatDescription($this->GetFieldValue('DESC'),
					$carpconf['maxidesc'],$carpconf['bidesc'],$carpconf['aidesc'],$carpconf['atruncidesc'],$carpconf['atruncidesclen']);
				break;
			default:
				$rvd='';
				foreach ($carpcallbacks['handlefield'] as $cb)
					if ($cb[2]==$name)
						$rvd=call_user_func(($cb[0]==='')?$cb[1]:array($cb[0],$cb[1]),1,$name,$this->itemindex,$this->itemcount,$this->ivalues,$rvd);
				$rv.=$rvd;
			}
		}
		return $rv;
	}

	function endElement($parser,$tagName) {
		global $carpconf;
		global $carpurltags;
		global $carpcallbacks;

		$tagName=array_shift($this->tagName);

		$empty='';
		$this->MapPrefix($tagName,$empty);

		if (in_array($this->tag,$carpurltags)) $this->thisdata=$this->CleanURL($this->thisdata);

		array_pop($this->xmlbase);

		if ($this->isinline) {
			$this->isinline--;
			if ($this->isinline==1) $this->isinline=0;
			else {
				$this->thisdata.='</'.strtolower($tagName).'>';
				$this->tag=substr($this->tag,0,strrpos($this->tag,'^'));
			}
		}
		if (!$this->isinline) {
			if ($this->inlinetype) {
				switch ($this->formatCheck) {
				case 3:
					if ($this->inlinetype&1) $this->thisdata=base64decode($this->thisdata);
					if ($this->inlinetype&2) $this->thisdata=strtr($this->thisdata,array('&'=>'&amp;','<'=>'&lt;','>'=>'&gt;'));
					break;
				case 10:
					switch ($this->inlinetype) {
					case 1: $this->thisdata=strtr($this->thisdata,array('&'=>'&amp;','<'=>'&lt;','>'=>'&gt;')); break;
					case 2:
						$start=strpos($this->thisdata,'>')+1;
						$this->thisdata=substr($this->thisdata,$start,strrpos($this->thisdata,'<')-$start);
						break;
					case 3: break;
					default: $this->thisdata='';
					}
					break;
				}
				$this->inlinetype=0;
			}
			foreach ($carpcallbacks['endelement'] as $cb)
				if (($cb[2]=='')||preg_match("/$cb[2]/",$this->tag))
					call_user_func(($cb[0]==='')?$cb[1]:array($cb[0],$cb[1]),$this->insideitem,$this->tag);
			$this->getdata=0;
			$this->tag=substr($this->tag,0,strrpos($this->tag,'^'));
			if (($tagName=="ITEM")||($tagName=="ENTRY")) {
				if ($this->moreitems&&($this->itemcount<$carpconf['maxitems'])) {
					$filterblock=0;

					if (count($this->filterin)) {
						$filterblock=1;
						for ($i=count($this->filterin)-1;$i>=0;$i--) {
							if ($this->CheckFilter($this->filterin[$i],$this->filterinfield[$i])) {
								$filterblock=0;
								break;
							}
						}
					}
					if (count($this->filterout)&&!$filterblock) {
						for ($i=count($this->filterout)-1;$i>=0;$i--) {
							if ($this->CheckFilter($this->filterout[$i],$this->filteroutfield[$i])) {
								$filterblock=1;
								break;
							}
						}
					}
					if (!$filterblock) foreach ($carpcallbacks['displayitem'] as $cb)
						if (($rv=call_user_func(($cb[0]==='')?$cb[1]:array($cb[0],$cb[1]),$this->itemindex,$this->itemcount))<=0) {
							$filterblock=1;
							if ($rv<0) $this->moreitems=0;
							break;
						}
					if (!$filterblock) {
						$fulltitle=trim($this->GetFieldValue('TITLE'));
						$skipit=0;
						if ($carpconf['skipdups']) {
							if (!isset($this->dups["$fulltitle"])) $this->dups["$fulltitle"]=1;
							else $skipit=1;
						}
						if (!$skipit) {
							$carpconf['items-shown']++;
							$thisitem=$carpconf['bi'];

							$pubdate=CarpDecodeDate($this->GetFieldValue('DATE'));

							for ($ioi=0;$ioi<count($this->itemorder);$ioi++) $thisitem.=$this->ProcessDataField($this->itemorder[$ioi]);
							$thisitem.=$carpconf['ai'];
							$this->itemcount++;
							if ($this->showit) $this->body.=$thisitem.$carpconf['aitem'];
							else $this->body.=(
									$pubdate?($pubdate+($carpconf['timeoffset']*60)):(($cdate=CarpDecodeDate($this->GetFieldValue('DATE',1)))?
										($cdate+($carpconf['timeoffset']*60)-$this->itemcount):(($carpconf['lastmodified']>0)?($carpconf['lastmodified']-$this->itemcount):0)
									)
								).
								':'.preg_replace("/[\r\n]/",' ',(str_replace(":",'_',$fulltitle).':'.$thisitem))."\n";
						}
					}
				}
				$this->insideitem=0;
				$this->itemindex++;
			} else if (($tagName=="CHANNEL")||($tagName=="FEED")) {
				$this->displaychannel=1;
				foreach ($carpcallbacks['displaychannel'] as $cb)
					if (($rv=call_user_func(($cb[0]==='')?$cb[1]:array($cb[0],$cb[1])))<=0) {
						$this->displaychannel=0;
						if ($rv<0) $this->itemcount=$carpconf['maxitems'];
					}
				$this->insidechannel=0;
			}
			if ($this->insidechannel) $this->insidechannel--;
			if ($this->insideitem) $this->insideitem--;
		}
	}

	function DoEndChannel(&$data,&$order,&$b,&$a) {
		global $carpconf;
		for ($coi=0;$coi<count($order);$coi++) $data.=$this->ProcessDataField($order[$coi],1);
		if ($data!='') $data=$b.$data.$a;
		if (!$this->showit) $data=preg_replace("/\n/",' ',$data);
	}

	function characterData($parser,$data) {
		global $carpconf,$carpcafields,$carpiafields;
		global $carpcallbacks;

		if ($this->insideitem&&($this->itemcount==$carpconf['maxitems'])) return;

		foreach ($carpcallbacks['characterdata'] as $cb)
			if (($cb[2]=='')||preg_match("/$cb[2]/",$this->tag))
				call_user_func(($cb[0]==='')?$cb[1]:array($cb[0],$cb[1]),$this->insideitem,$this->tag,$data);
		if ($this->getdata) $this->thisdata.=$data;
	}

	function PrepTagPairs($tags) {
		$this->tagpairs=$findpairs=array();
		$temptags=explode('|',strtolower(preg_replace("/\\\\b/",'',$tags)));
		for ($i=count($temptags)-1;$i>=0;$i--) {
			$tag=$temptags[$i];
			if (strcmp(substr($tag,0,1),'/')) {
				$searchpre='/';
				$baretag=$tag;
			} else {
				$searchpre='';
				$baretag=substr($tag,1);
			}
			if (isset($findpairs["$searchpre$baretag"])) {
				$this->tagpairs["$baretag"]=1;
				$findpairs["$baretag"]=$findpairs["/$baretag"]=2;
			} else $findpairs["$tag"]='1';
		}
	}
}

function CarpDecodeDate($val) {
	global $carpconf;
	if ($val!='') {
		if (
			(($rv=strtotime($val))==-1)&&
			(($rv=strtotime(preg_replace("/([0-9]+\-[0-9]+\-[0-9]+)T([0-9:]*)(\\.[0-9]*)?(?:Z|([-+][0-9]{1,2}):([0-9]{2}))/","$1 $2 $4$5",$val)))==-1)
		) {
			$thisyear=date('Y');
			if (($rv=strtotime(preg_replace("/( [0-9]{1,2}:[0-9]{2})/",", $thisyear $1",$val)))==-1) $rv=0;
		}
	} else $rv=0;
	return $rv?($rv+($carpconf['timeoffset']*60)):0;
}

function CarpRequestHeaders() {
	global $carpconf;
	$rv='';
	foreach ($carpconf['request-headers'] as $k=>$v) $rv.="$k: $v\r\n";
	return $rv;
}

function OpenRSSFeed($url) {
	global $carpconf,$carpversion,$CarpRedirs;
	$carpconf['statuscode']=-1;
	$carpconf['response-headers'][$url]=array();
	$rh=&$carpconf['response-headers'][$url];
	$now=time();

	if (strtolower(substr($url,0,7))=='feed://') $url='http://'.substr($url,7);
	else if (strtolower(substr($url,0,8))=='feeds://') $url='https://'.substr($url,9); // non-standard
	$carpconf['final_url']=$url;
	$carpconf['lastmodified']='';
	if (preg_match('#^https?://#i',$url)) {
		if ($carpconf['caches']&2) {
			$mc=&CarpLoadMetaCache($carpconf['original-url']);
			if (isset($mc['redir'])) while (isset($mc['redir'][$url])&&($mc['redir'][$url]['exp']>=$now)) $carpconf['final_url']=$url=$mc['redir'][$url]['url'];
			if (isset($mc['rh'])&&($url==$mc['rh']['url'])) $oh=&$mc['rh'];
			else $oh=array();
		} else $oh=$mc=array();
		if ($carpconf['proxyserver']!='') {
			$urlparts=parse_url($carpconf['proxyserver']);
			$therest=$url;
			$scheme='';
		} else {
			$urlparts=parse_url($url);
			$therest=$urlparts['path'].(isset($urlparts['query'])?('?'.$urlparts['query']):'');
			$scheme=(strtolower($urlparts['scheme'])=='https')?'ssl://':'';
		}
		$domain=$urlparts['host'];
		$port=empty($urlparts['port'])?(empty($scheme)?80:443):$urlparts['port'];
		$carpconf['loadstart']=time();
		$fp=fsockopen($scheme.$domain,$port,$errno,$errstr,$carpconf['timeout']);
		if ($fp) {
			fputs($fp,"GET $therest HTTP/1.0\r\n".
				($carpconf['sendhost']?"Host: $domain\r\n":'').
				(($carpconf['proxyauth']!='')?('Proxy-Authorization: Basic '.base64_encode($carpconf['proxyauth'])."\r\n"):'').
				(($carpconf['basicauth']!='')?('Authorization: Basic '.base64_encode($carpconf['basicauth'])."\r\n"):'').
				(($carpconf['accept']!='')?('Accept: '.$carpconf['accept']."\r\n"):'').
				'User-Agent: '.(($carpconf['useragent']!='')?$carpconf['useragent']:"CaRP/$carpversion")."\r\n".
				(isset($oh['etag'])?"If-None-Match: {$oh['etag']}\r\n":'').
				(isset($oh['last-modified'])?"If-Modified-Since: {$oh['last-modified']}\r\n":'').
				CarpRequestHeaders()."Connection: close\r\n\r\n");
			stream_set_blocking($fp,TRUE);
			stream_set_timeout($fp,$carpconf['timeout']);
			$streaminfo=stream_get_meta_data($fp);
			if ($streaminfo['timed_out']) {
				fclose($fp);
				return 0;
			}
			if ($header=fgets($fp,1000)) {
				$temp=explode(' ',$header);
				if (count($temp)<2) {
					fclose($fp);
					return 0;
				}
				$rh['statuscode']=$carpconf['statuscode']=$temp[1];
				if (!in_array($temp[1],array(200,203,301,308,302,303,307,304))) {
					fclose($fp);
					return 0;
				}
			}
			while ((!feof($fp))&&(!$streaminfo['timed_out'])&&preg_match("/[^\r\n]/",$header=fgets($fp,1000))) {
				$streaminfo=stream_get_meta_data($fp);
				list($hk,$hv)=explode(':',$header,2);
				$rh[strtolower($hk)]=trim($hv);
			}
			if ($streaminfo['timed_out']) {
				fclose($fp);
				return 0;
			}
			$exp=0;
			if ($carpconf['caches']&2) {
				$mc['lastchecked']=$now;
				$mc['laststatus']=$carpconf['statuscode'];
			}
			switch($carpconf['statuscode']) {
			case 301: case 308:
				if (isset($rh['location'])&&isset($rh['expires'])) $exp=strtotime($rh['expires']);
			case 302: case 303: case 307:
				fclose($fp);
				if (count($CarpRedirs)<$carpconf['maxredir']) {
					if (isset($rh['location'])) {
						if (!isset($mc['redir'])) $mc['redir']=array();
						$mc['redir'][$url]=array('url'=>$rh['location'],'exp'=>$exp);
						if (!preg_match('#^https?://#i',$rh['location'])) {
							if ($carpconf['proxyserver']!='') {
								$redirparts=parse_url($url);
								$rh['location']=$redirparts['scheme'].'://'.$redirparts['host'].(isset($redirparts['port'])?(':'.$redirparts['port']):'').$rh['location'];
							} else $rh['location']="http://$domain".(($port==80)?'':":$port").$rh['location'];
						}
						for ($i=count($CarpRedirs)-1;$i>=0;$i--) if (!strcmp($rh['location'],$CarpRedirs[$i])) {
							CarpError('Redirection loop detected. Giving up.','redirection-loop');
							return 0;
						}
						$CarpRedirs[count($CarpRedirs)]=$rh['location'];
						return OpenRSSFeed($rh['location']);
					} else {
						CarpError('Invalid redirect: no destination URL provided.','redirection-no-location');
						return 0;
					}
				} else {
					CarpError('Too many redirects. Giving up.','redirection-too-many');
					return 0;
				}
				break;
			case 304:
				fclose($fp);
				CarpTouchCache($carpconf['cachefile']);
				if ($carpconf['caches']&2) CarpSaveMetaCache($carpconf['original-url']);
				return 0;
			default:
				if ($carpconf['caches']&2) {
					$modd=0;
					if ((!isset($mc['rh']))||($mc['rh']['url']!=$url)) $mc['rh']=array('url'=>$url);
					if (isset($rh['last-modified'])) $carpconf['lastmodified']=CarpDecodeDate($rh['last-modified']);
					if ((isset($rh['last-modified'])&&((!isset($mc['rh']['last-modified']))||($rh['last-modified']!=$mc['rh']['last-modified'])))
						||((!isset($rh['last-modified']))&&isset($mc['rh']['last-modified']))
					) {
						$modd=1;
						if (isset($rh['last-modified'])) $mc['rh']['last-modified']=$rh['last-modified'];
						else unset($mc['rh']['last-modified']);
					}
					if ((isset($rh['etag'])&&((!isset($mc['rh']['etag']))||($rh['etag']!=$mc['rh']['etag'])))
						||((!isset($rh['etag']))&&isset($mc['rh']['etag']))
					) {
						$modd=1;
						if (isset($rh['etag'])) $mc['rh']['etag']=$rh['etag'];
						else unset($mc['rh']['etag']);
					}
					if ($modd) {
						if (isset($mc['caches'])) unset($mc['caches']);
						$mc['lastchanged']=$now;
					}
				}
			}
		} else CarpError("$errstr ($errno)",'connection-failed');
	} else if ($fp=fopen($url,'r')) {
		if ($stat=fstat($fp)) $carpconf['lastmodified']=$stat['mtime'];
	} else CarpError("Failed to open file: $url",'local-file-open-failed');
	return $fp;
}

function DoCacheRSSFeed($data,$cache='') {
	global $carpconf;
	if ($cache!='') {
		$savecache=$carpconf['cachefile'];
		$carpconf['cachefile']=$cache;
	}
	if (($outf=OpenCacheWrite())>0) {
		switch($carpconf['cache-method']) {
		case 'mysql':
			CarpParseMySQLPath($carpconf['cachefile'],$which,$key);
			if (!CarpMySQLQuery('update '.$carpconf['mysql-database-name'].$carpconf['mysql-tables'][$which].' set updated='.time().',cache="'.addslashes($data).
				'" where id="'.$key.'"')
			) CarpError('Database error attempting to cache feed.','database-error');
			break;
		default: fwrite($outf,$data);
		}
		CloseCacheWrite($outf);
	}
	if ($cache!='') $carpconf['cachefile']=$savecache;
}

function CacheRSSFeed($url) {
	global $carpconf,$CarpRedirs;
	$d='';
	$CarpRedirs=array();
	if (substr($url,0,8)=='grouper:') $d=GrouperGetCache(substr($url,8))?$GLOBALS['grouperrawdata']:'';
	else if ($fp=OpenRSSFeed($url)) {
		$streaminfo=stream_get_meta_data($fp);
		while ((!feof($fp))&&!$streaminfo['timed_out']) {
			if (($l=fread($fp,4000))!==false) $d.=$l;
			$streaminfo=stream_get_meta_data($fp);
		}
		fclose($fp);
		if ($streaminfo['timed_out']) CarpError('Remote newsfeed timed out.','connection-failed',0);
		else {
			$carpconf['metacache'][$url]['loadtime']=time()-$carpconf['loadstart'];
			$carpconf['metacache'][$url]['avgloadtime']=isset($carpconf['metacache'][$url]['avgloadtime'])
				?(($carpconf['metacache'][$url]['loadtime']*0.1)+($carpconf['metacache'][$url]['avgloadtime']*0.9))
				:$carpconf['metacache'][$url]['loadtime'];
			if ($carpconf['caches']&2) CarpSaveMetaCache($carpconf['original-url']);
		}
	} else if ($carpconf['statuscode']!=304) CarpError('Can\'t open remote newsfeed ['.$carpconf['statuscode'].'].','feed-access-failed',0);
	if ($d!='') DoCacheRSSFeed($d);
}

function CarpReadData($fp) {
	global $carpconf;
	return $carpconf['fixentities']?
		preg_replace("/&(?!lt|gt|amp|apos|quot|#[0-9]+|#x[0-9a-f]+)(.*\b)/is","&amp;\\1\\2",preg_replace("/\\x00/",'',fread($fp,4096))):
		preg_replace("/\\x00/",'',fread($fp,4096));
}

function CarpStrLen($s) {
	if (strtoupper($GLOBALS['carpconf']['encodingout'])=='UTF-8') {
		for ($i=$len=0,$j=strlen($s);$i<$j;$len++) {
			$val=ord($s[$i]);
			$i+=($val<=0x7F)?1:(($val<=0xDF)?2:(($val<=0xEF)?3:4));
		}
	} else $len=strlen($s);
	return $len;
}

function CarpCleanInput(&$data,$encodingin) {
	switch($encodingin) {
	case 'UTF-8':
		$data=preg_replace('/(\r|\n|\t|[\x20-\x7E]|[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3})|./','$1',$data);
		break;
	case 'ISO-8859-1':
		$data=preg_replace('/(\r|\n|\t|[\x20-\x7E]|[\xA0-\xFF])|./','$1',$data);
		break;
	}
}

function GetRSSFeed($url,$cache,$showit) {
	global $carpconf,$CarpRedirs;

	MyForceConf();

	$carpconf['desctags']=preg_replace("/(^\\|)|(\\|$)/",'',preg_replace("/\\|+/","|",preg_replace('#/?('.
		str_replace(',','|',carp_banned_tags).')#i','',$carpconf['descriptiontags'])));
	if (!empty($carpconf['desctags'])) $carpconf['desctags']=str_replace('|','\b|',$carpconf['desctags']).'\b';

	$carpconf['cuseidate']=($carpconf['cidateformat']!='');
	$carpconf['iuseidate']=($carpconf['iidateformat']!='');
	$carpconf['atruncititlelen']=CarpStrLen($carpconf['atruncititle']);
	$carpconf['atruncctitlelen']=CarpStrLen($carpconf['atruncctitle']);
	$carpconf['atruncidesclen']=CarpStrLen($carpconf['atruncidesc']);
	$carpconf['atrunccdesclen']=CarpStrLen($carpconf['atrunccdesc']);

	$rss_parser=new RSSParser();
	$carpconf['rssparser']=&$rss_parser;
	CarpTranscodePrep();
	if ($carpconf['skipdups']) $rss_parser->dups=array();
	$rss_parser->showit=$showit;
	$rss_parser->channelborder=explode(',',preg_replace('/[^a-z0-9,]/','',strtolower($carpconf['cborder'])));
	$rss_parser->channelaorder=explode(',',preg_replace('/[^a-z0-9,]/','',strtolower($carpconf['caorder'])));
	$rss_parser->SetItemOrder($carpconf['iorder']);
	$rss_parser->formatCheck=0;

	if (preg_match("/[^0-9]/",$carpconf['linktarget'])) $rss_parser->linktargets[$carpconf['linktarget']]=' target="'.$carpconf['linktarget'].'"';
	$rss_parser->filterinfield=array();
	if ($carpconf['filterin']!='') {
		$rss_parser->filterin=explode('|',strtolower($carpconf['filterin']));
		for ($i=count($rss_parser->filterin)-1;$i>=0;$i--) {
			if (strpos($rss_parser->filterin[$i],':')!==false)
				list($rss_parser->filterinfield[$i],$rss_parser->filterin[$i])=explode(':',$rss_parser->filterin[$i],2);
			else $rss_parser->filterinfield[$i]='';
		}
	} else $rss_parser->filterin=array();
	$rss_parser->filteroutfield=array();
	if ($carpconf['filterout']!='') {
		$rss_parser->filterout=explode('|',strtolower($carpconf['filterout']));
		for ($i=count($rss_parser->filterout)-1;$i>=0;$i--) {
			if (strpos($rss_parser->filterout[$i],':')!==false)
				list($rss_parser->filteroutfield[$i],$rss_parser->filterout[$i])=explode(':',$rss_parser->filterout[$i],2);
			else $rss_parser->filteroutfield[$i]='';
		}
	} else $rss_parser->filterout=array();

	$fromfp=0;
	if (substr($url,0,6)=='mysql:') $data=CarpGetCache($url);
	else if (substr($url,0,8)=='grouper:') $data=GrouperGetCache(substr($url,8))?$GLOBALS['grouperrawdata']:'';
	else $fromfp=1;
	$CarpRedirs=array();
	if ($fromfp&&($carpconf['caches']&2)&&preg_match('#^(http|feed)s?://#',$url)) $mc=&CarpLoadMetaCache($carpconf['original-url']);
	else $mc=array();
	if ((!$fromfp)||($fp=OpenRSSFeed($url))) {
		if ($fromfp) $data=CarpReadData($fp);
		$data=preg_replace('/^[^<]+/','',$data);
		$encodings_internal=array('ISO-8859-1','UTF-8','US-ASCII');
		$transcodeout=(($carpconf['encodingout']!='')&&!in_array(strtoupper($carpconf['encodingout']),$encodings_internal))?1:0;
		if (($carpconf['encodingin']!='')) $encodingin=$carpconf['encodingin'];
		else $encodingin=preg_match("/^<\?xml\b.*?\bencoding=(\"|')(.*?)(\"|')/",$data,$matches)?
			strtoupper($matches[2]):'UTF-8';
		$encodingquestion=0;
		if (!in_array($encodingin,$encodings_internal)) {
			if ($carpconf['haveiconv']||$carpconf['havemb']) {
				if ($fromfp) {
					$streaminfo=stream_get_meta_data($fp);
					while ((!feof($fp))&&!$streaminfo['timed_out']) {
						if (($temp=CarpReadData($fp))!==false) $data.=$temp;
						$streaminfo=stream_get_meta_data($fp);
					}
					fclose($fp);
					$fromfp=0;
					if ($streaminfo['timed_out']) {
						CarpError('Remote newsfeed timed out.','connection-failed',0);
						if ($showit&&($carpconf['cachefile']!='')) CarpOutput(CarpGetCache($carpconf['cachefile']));
						return;
					}
				}
				$newencodingin=$transcodeout?'UTF-8':
					(($carpconf['encodingout']!='')?$carpconf['encodingout']:'ISO-8859-1');
				if (CarpTranscodeData($data,$encodingin,$newencodingin)) {
					$data=preg_replace("/(<\?xml\b.*?\bencoding=)(\"|').*?(\"|')/","\\1\\2$newencodingin\\3",$data);
					$encodingin=$newencodingin;
				} else CarpError('Encoding conversion ('.($carpconf['haveiconv']?'iconv':'mb_convert_encoding').') failed. Attempting to use original data...','iconv-failed',0);
			} else {
				$actualencoding=$encodingin;
				$encodingin='UTF-8';
				$encodingquestion=1;
			}
		}

		$xml_parser=xml_parser_create(strtoupper($encodingin));
		if ($carpconf['encodingout']!='') {
			$rss_parser->encodingout=$transcodeout?'UTF-8':strtoupper($carpconf['encodingout']);
			xml_parser_set_option($xml_parser,XML_OPTION_TARGET_ENCODING,$rss_parser->encodingout);
		}

		xml_set_object($xml_parser,$rss_parser);
		xml_set_element_handler($xml_parser,"startElement","endElement");
		xml_set_character_data_handler($xml_parser,"characterData");

		$rss_parser->PrepTagPairs($carpconf['desctags']);
		$rss_parser->xmlbase=array(($url{strlen($url)-1}=='/')?$url:substr($url,0,strrpos($url,'/')+1));
		$carpconf['items-shown']=0;
		if ($fromfp) $streaminfo=stream_get_meta_data($fp);
		while (($data!='')||($fromfp&&(!feof($fp))&&!$streaminfo['timed_out'])) {
			if (($data!='')||(($data=CarpReadData($fp))!==false)) {
				if ($fromfp) $streaminfo=stream_get_meta_data($fp);
				if (!($fromfp&&$streaminfo['timed_out'])) {
					if ($carpconf['clean_input']) CarpCleanInput($data,$encodingin);
					if (!xml_parse($xml_parser,$data,$fromfp?feof($fp):1)) {
						CarpError("XML error: ".xml_error_string(xml_get_error_code($xml_parser))." at line ".xml_get_current_line_number($xml_parser).
							($encodingquestion?(". This error may be caused by the fact that PHP is unable to process this feed's encoding ($actualencoding), ".
								"and your server does not support the \"iconv\" or \"mb_convert_encoding\" function, ".
								"one of which is necessary to convert it to an encoding that PHP can process."):'').
								$rss_parser->XMLFormatError()
							,'xml-error');
						if ($fromfp) fclose($fp);
						xml_parser_free($xml_parser);
						unset($rss_parser);
						unset($carpconf['rssparser']);
						return;
					}
				}
			}
			$data='';
		}
		if ($fromfp) fclose($fp);
		if ($fromfp&&$streaminfo['timed_out']) {
			CarpError('Remote newsfeed timed out.','connection-failed',0);
			if ($showit&&($carpconf['cachefile']!='')) CarpOutput(CarpGetCache($carpconf['cachefile']));
			return;
		}
		if ($rss_parser->displaychannel) {
			if ($rss_parser->channelborder[0]!='') $rss_parser->DoEndChannel($rss_parser->top,$rss_parser->channelborder,$carpconf['bcb'],$carpconf['acb']);
			if ($rss_parser->channelaorder[0]!='') $rss_parser->DoEndChannel($rss_parser->bottom,$rss_parser->channelaorder,$carpconf['bca'],$carpconf['aca']);
		}
		$data=($showit?($rss_parser->top.$carpconf['bitems']):('cb: :'.$rss_parser->top."\n".'ca: :'.$rss_parser->bottom."\n")).
			$rss_parser->body.
			($showit?($carpconf['aitems'].$rss_parser->bottom.$carpconf['poweredby']):'');
		if ($transcodeout) {
			if ($carpconf['haveiconv']||$carpconf['havemb']) {
				if (!CarpTranscodeData($data,'UTF-8',$carpconf['encodingout']))
					CarpError('Encoding conversion ('.($carpconf['haveiconv']?'iconv':'mb_convert_encoding').') failed. Outputting unconverted data.','iconv-failed',0);
			} else CarpError('Your server does not support the \"iconv\" or \"mb_convert_encoding\" function, ".
				"one of which is needed to convert CaRP\'s output to '.$carpconf['encodingout'].'. Outputting unconverted data.', 'no-iconv', 0);
		}

		if ($showit) {
			if ($carpconf['shownoitems']&&!$rss_parser->itemcount) CarpOutput($carpconf['noitems']);
			else CarpOutput($data);
			if (isset($rss_parser)&&!$rss_parser->itemcount) $rss_parser->XMLFormatError(1);
		}
		if ($cache) {
			if (($cfp=OpenCacheWrite())>0) {
				if ($carpconf['shownoitems']&&!$rss_parser->itemcount) CarpSaveCache($cfp,$carpconf['noitems']);
				else CarpSaveCache($cfp,$data);
				CloseCacheWrite($cfp);
			}
		}
		xml_parser_free($xml_parser);
		unset($carpconf['rssparser']);
	} else {
		CarpError('Can\'t open remote newsfeed ['.$carpconf['statuscode'].'].','feed-access-failed',0);
		if ($showit&&($carpconf['cachefile']!='')) CarpOutput(CarpGetCache($carpconf['cachefile']));
	}
}

return;
?>