PNG  IHDRQgAMA a cHRMz&u0`:pQ<bKGDgmIDATxwUﹻ& ^CX(J I@ "% (** BX +*i"]j(IH{~R)[~>h{}gy)I$Ij .I$I$ʊy@}x.: $I$Ii}VZPC)I$IF ^0ʐJ$I$Q^}{"r=OzI$gRZeC.IOvH eKX $IMpxsk.쒷/&r[޳<v| .I~)@$updYRa$I |M.e JaֶpSYR6j>h%IRز if&uJ)M$I vLi=H;7UJ,],X$I1AҒJ$ XY XzI@GNҥRT)E@;]K*Mw;#5_wOn~\ DC&$(A5 RRFkvIR}l!RytRl;~^ǷJj اy뷦BZJr&ӥ8Pjw~vnv X^(I;4R=P[3]J,]ȏ~:3?[ a&e)`e*P[4]T=Cq6R[ ~ޤrXR Հg(t_HZ-Hg M$ãmL5R uk*`%C-E6/%[t X.{8P9Z.vkXŐKjgKZHg(aK9ڦmKjѺm_ \#$5,)-  61eJ,5m| r'= &ڡd%-]J on Xm|{ RҞe $eڧY XYrԮ-a7RK6h>n$5AVڴi*ֆK)mѦtmr1p| q:흺,)Oi*ֺK)ܬ֦K-5r3>0ԔHjJئEZj,%re~/z%jVMڸmrt)3]J,T K֦OvԒgii*bKiNO~%PW0=dii2tJ9Jݕ{7"I P9JKTbu,%r"6RKU}Ij2HKZXJ,妝 XYrP ެ24c%i^IK|.H,%rb:XRl1X4Pe/`x&P8Pj28Mzsx2r\zRPz4J}yP[g=L) .Q[6RjWgp FIH*-`IMRaK9TXcq*I y[jE>cw%gLRԕiFCj-ďa`#e~I j,%r,)?[gp FI˨mnWX#>mʔ XA DZf9,nKҲzIZXJ,L#kiPz4JZF,I,`61%2s $,VOϚ2/UFJfy7K> X+6 STXIeJILzMfKm LRaK9%|4p9LwJI!`NsiazĔ)%- XMq>pk$-$Q2x#N ؎-QR}ᶦHZډ)J,l#i@yn3LN`;nڔ XuX5pF)m|^0(>BHF9(cզEerJI rg7 4I@z0\JIi䵙RR0s;$s6eJ,`n 䂦0a)S)A 1eJ,堌#635RIgpNHuTH_SԕqVe ` &S)>p;S$魁eKIuX`I4춒o}`m$1":PI<[v9^\pTJjriRŭ P{#{R2,`)e-`mgj~1ϣLKam7&U\j/3mJ,`F;M'䱀 .KR#)yhTq;pcK9(q!w?uRR,n.yw*UXj#\]ɱ(qv2=RqfB#iJmmL<]Y͙#$5 uTU7ӦXR+q,`I}qL'`6Kͷ6r,]0S$- [RKR3oiRE|nӦXR.(i:LDLTJjY%o:)6rxzҒqTJjh㞦I.$YR.ʼnGZ\ֿf:%55 I˼!6dKxm4E"mG_ s? .e*?LRfK9%q#uh$)i3ULRfK9yxm܌bj84$i1U^@Wbm4uJ,ҪA>_Ij?1v32[gLRD96oTaR׿N7%L2 NT,`)7&ƝL*꽙yp_$M2#AS,`)7$rkTA29_Iye"|/0t)$n XT2`YJ;6Jx".e<`$) PI$5V4]29SRI>~=@j]lp2`K9Jaai^" Ԋ29ORI%:XV5]JmN9]H;1UC39NI%Xe78t)a;Oi Ҙ>Xt"~G>_mn:%|~ޅ_+]$o)@ǀ{hgN;IK6G&rp)T2i୦KJuv*T=TOSV>(~D>dm,I*Ɛ:R#ۙNI%D>G.n$o;+#RR!.eU˽TRI28t)1LWϚ>IJa3oFbu&:tJ*(F7y0ZR ^p'Ii L24x| XRI%ۄ>S1]Jy[zL$adB7.eh4%%누>WETf+3IR:I3Xה)3אOۦSRO'ٺ)S}"qOr[B7ϙ.edG)^ETR"RtRݜh0}LFVӦDB^k_JDj\=LS(Iv─aTeZ%eUAM-0;~˃@i|l @S4y72>sX-vA}ϛBI!ݎߨWl*)3{'Y|iSlEڻ(5KtSI$Uv02,~ԩ~x;P4ցCrO%tyn425:KMlD ^4JRxSهF_}شJTS6uj+ﷸk$eZO%G*^V2u3EMj3k%)okI]dT)URKDS 7~m@TJR~荪fT"֛L \sM -0T KfJz+nإKr L&j()[E&I ߴ>e FW_kJR|!O:5/2跌3T-'|zX ryp0JS ~^F>-2< `*%ZFP)bSn"L :)+pʷf(pO3TMW$~>@~ū:TAIsV1}S2<%ޟM?@iT ,Eūoz%i~g|`wS(]oȤ8)$ ntu`өe`6yPl IzMI{ʣzʨ )IZ2= ld:5+請M$-ї;U>_gsY$ÁN5WzWfIZ)-yuXIfp~S*IZdt;t>KūKR|$#LcԀ+2\;kJ`]YǔM1B)UbG"IRߊ<xܾӔJ0Z='Y嵤 Leveg)$znV-º^3Ւof#0Tfk^Zs[*I꯳3{)ˬW4Ւ4 OdpbZRS|*I 55#"&-IvT&/윚Ye:i$ 9{LkuRe[I~_\ؠ%>GL$iY8 9ܕ"S`kS.IlC;Ҏ4x&>u_0JLr<J2(^$5L s=MgV ~,Iju> 7r2)^=G$1:3G< `J3~&IR% 6Tx/rIj3O< ʔ&#f_yXJiގNSz; Tx(i8%#4 ~AS+IjerIUrIj362v885+IjAhK__5X%nV%Iͳ-y|7XV2v4fzo_68"S/I-qbf; LkF)KSM$ Ms>K WNV}^`-큧32ŒVؙGdu,^^m%6~Nn&͓3ŒVZMsRpfEW%IwdǀLm[7W&bIRL@Q|)* i ImsIMmKmyV`i$G+R 0tV'!V)֏28vU7͒vHꦼtxꗞT ;S}7Mf+fIRHNZUkUx5SAJㄌ9MqμAIRi|j5)o*^'<$TwI1hEU^c_j?Е$%d`z cyf,XO IJnTgA UXRD }{H}^S,P5V2\Xx`pZ|Yk:$e ~ @nWL.j+ϝYb퇪bZ BVu)u/IJ_ 1[p.p60bC >|X91P:N\!5qUB}5a5ja `ubcVxYt1N0Zzl4]7­gKj]?4ϻ *[bg$)+À*x쳀ogO$~,5 زUS9 lq3+5mgw@np1sso Ӻ=|N6 /g(Wv7U;zωM=wk,0uTg_`_P`uz?2yI!b`kĸSo+Qx%!\οe|އԁKS-s6pu_(ֿ$i++T8=eY; צP+phxWQv*|p1. ά. XRkIQYP,drZ | B%wP|S5`~́@i޾ E;Չaw{o'Q?%iL{u D?N1BD!owPHReFZ* k_-~{E9b-~P`fE{AܶBJAFO wx6Rox5 K5=WwehS8 (JClJ~ p+Fi;ŗo+:bD#g(C"wA^ r.F8L;dzdIHUX݆ϞXg )IFqem%I4dj&ppT{'{HOx( Rk6^C٫O.)3:s(۳(Z?~ٻ89zmT"PLtw䥈5&b<8GZ-Y&K?e8,`I6e(֍xb83 `rzXj)F=l($Ij 2*(F?h(/9ik:I`m#p3MgLaKjc/U#n5S# m(^)=y=đx8ŬI[U]~SцA4p$-F i(R,7Cx;X=cI>{Km\ o(Tv2vx2qiiDJN,Ҏ!1f 5quBj1!8 rDFd(!WQl,gSkL1Bxg''՞^ǘ;pQ P(c_ IRujg(Wz bs#P­rz> k c&nB=q+ؔXn#r5)co*Ũ+G?7< |PQӣ'G`uOd>%Mctz# Ԫڞ&7CaQ~N'-P.W`Oedp03C!IZcIAMPUۀ5J<\u~+{9(FbbyAeBhOSܳ1 bÈT#ŠyDžs,`5}DC-`̞%r&ڙa87QWWp6e7 Rϫ/oY ꇅ Nܶըtc!LA T7V4Jsū I-0Pxz7QNF_iZgúWkG83 0eWr9 X]㾮݁#Jˢ C}0=3ݱtBi]_ &{{[/o[~ \q鯜00٩|cD3=4B_b RYb$óBRsf&lLX#M*C_L܄:gx)WΘsGSbuL rF$9';\4Ɍq'n[%p.Q`u hNb`eCQyQ|l_C>Lb꟟3hSb #xNxSs^ 88|Mz)}:](vbۢamŖ࿥ 0)Q7@0=?^k(*J}3ibkFn HjB׻NO z x}7p 0tfDX.lwgȔhԾŲ }6g E |LkLZteu+=q\Iv0쮑)QٵpH8/2?Σo>Jvppho~f>%bMM}\//":PTc(v9v!gոQ )UfVG+! 35{=x\2+ki,y$~A1iC6#)vC5^>+gǵ@1Hy٪7u;p psϰu/S <aʸGu'tD1ԝI<pg|6j'p:tպhX{o(7v],*}6a_ wXRk,O]Lܳ~Vo45rp"N5k;m{rZbΦ${#)`(Ŵg,;j%6j.pyYT?}-kBDc3qA`NWQū20/^AZW%NQ MI.X#P#,^Ebc&?XR tAV|Y.1!؅⨉ccww>ivl(JT~ u`ٵDm q)+Ri x/x8cyFO!/*!/&,7<.N,YDŽ&ܑQF1Bz)FPʛ?5d 6`kQձ λc؎%582Y&nD_$Je4>a?! ͨ|ȎWZSsv8 j(I&yj Jb5m?HWp=g}G3#|I,5v珿] H~R3@B[☉9Ox~oMy=J;xUVoj bUsl_35t-(ՃɼRB7U!qc+x4H_Qo֮$[GO<4`&č\GOc[.[*Af%mG/ ňM/r W/Nw~B1U3J?P&Y )`ѓZ1p]^l“W#)lWZilUQu`-m|xĐ,_ƪ|9i:_{*(3Gѧ}UoD+>m_?VPۅ15&}2|/pIOʵ> GZ9cmíتmnz)yߐbD >e}:) r|@R5qVSA10C%E_'^8cR7O;6[eKePGϦX7jb}OTGO^jn*媓7nGMC t,k31Rb (vyܴʭ!iTh8~ZYZp(qsRL ?b}cŨʊGO^!rPJO15MJ[c&~Z`"ѓޔH1C&^|Ш|rʼ,AwĴ?b5)tLU)F| &g٣O]oqSUjy(x<Ϳ3 .FSkoYg2 \_#wj{u'rQ>o;%n|F*O_L"e9umDds?.fuuQbIWz |4\0 sb;OvxOSs; G%T4gFRurj(֍ڑb uԖKDu1MK{1^ q; C=6\8FR艇!%\YÔU| 88m)֓NcLve C6z;o&X x59:q61Z(T7>C?gcļxѐ Z oo-08jہ x,`' ҔOcRlf~`jj".Nv+sM_]Zk g( UOPyεx%pUh2(@il0ݽQXxppx-NS( WO+轾 nFߢ3M<;z)FBZjciu/QoF 7R¥ ZFLF~#ȣߨ^<쩡ݛкvџ))ME>ώx4m#!-m!L;vv#~Y[đKmx9.[,UFS CVkZ +ߟrY٧IZd/ioi$%͝ب_ֶX3ܫhNU ZZgk=]=bbJS[wjU()*I =ώ:}-蹞lUj:1}MWm=̛ _ ¾,8{__m{_PVK^n3esw5ӫh#$-q=A̟> ,^I}P^J$qY~Q[ Xq9{#&T.^GVj__RKpn,b=`żY@^՝;z{paVKkQXj/)y TIc&F;FBG7wg ZZDG!x r_tƢ!}i/V=M/#nB8 XxЫ ^@CR<{䤭YCN)eKOSƟa $&g[i3.C6xrOc8TI;o hH6P&L{@q6[ Gzp^71j(l`J}]e6X☉#͕ ׈$AB1Vjh㭦IRsqFBjwQ_7Xk>y"N=MB0 ,C #o6MRc0|$)ف"1!ixY<B9mx `,tA>)5ػQ?jQ?cn>YZe Tisvh# GMމȇp:ԴVuږ8ɼH]C.5C!UV;F`mbBk LTMvPʍϤj?ԯ/Qr1NB`9s"s TYsz &9S%U԰> {<ؿSMxB|H\3@!U| k']$U+> |HHMLޢ?V9iD!-@x TIî%6Z*9X@HMW#?nN ,oe6?tQwڱ.]-y':mW0#!J82qFjH -`ѓ&M0u Uγmxϵ^-_\])@0Rt.8/?ٰCY]x}=sD3ojަЫNuS%U}ԤwHH>ڗjܷ_3gN q7[q2la*ArǓԖ+p8/RGM ]jacd(JhWko6ڎbj]i5Bj3+3!\j1UZLsLTv8HHmup<>gKMJj0@H%,W΃7R) ">c, xixј^ aܖ>H[i.UIHc U1=yW\=S*GR~)AF=`&2h`DzT󑓶J+?W+}C%P:|0H܆}-<;OC[~o.$~i}~HQ TvXΈr=b}$vizL4:ȰT|4~*!oXQR6Lk+#t/g lԁߖ[Jڶ_N$k*". xsxX7jRVbAAʯKҎU3)zSNN _'s?f)6X!%ssAkʱ>qƷb hg %n ~p1REGMHH=BJiy[<5 ǁJҖgKR*倳e~HUy)Ag,K)`Vw6bRR:qL#\rclK/$sh*$ 6덤 KԖc 3Z9=Ɣ=o>X Ώ"1 )a`SJJ6k(<c e{%kϊP+SL'TcMJWRm ŏ"w)qc ef꒵i?b7b('"2r%~HUS1\<(`1Wx9=8HY9m:X18bgD1u ~|H;K-Uep,, C1 RV.MR5άh,tWO8WC$ XRVsQS]3GJ|12 [vM :k#~tH30Rf-HYݺ-`I9%lIDTm\ S{]9gOڒMNCV\G*2JRŨ;Rҏ^ڽ̱mq1Eu?To3I)y^#jJw^Ńj^vvlB_⋌P4x>0$c>K†Aļ9s_VjTt0l#m>E-,,x,-W)سo&96RE XR.6bXw+)GAEvL)͞K4$p=Ũi_ѱOjb HY/+@θH9޼]Nԥ%n{ &zjT? Ty) s^ULlb,PiTf^<À] 62R^V7)S!nllS6~͝V}-=%* ʻ>G DnK<y&>LPy7'r=Hj 9V`[c"*^8HpcO8bnU`4JȪAƋ#1_\ XϘHPRgik(~G~0DAA_2p|J묭a2\NCr]M_0 ^T%e#vD^%xy-n}-E\3aS%yN!r_{ )sAw ڼp1pEAk~v<:`'ӭ^5 ArXOI驻T (dk)_\ PuA*BY]yB"l\ey hH*tbK)3 IKZ򹞋XjN n *n>k]X_d!ryBH ]*R 0(#'7 %es9??ښFC,ՁQPjARJ\Ρw K#jahgw;2$l*) %Xq5!U᢯6Re] |0[__64ch&_}iL8KEgҎ7 M/\`|.p,~`a=BR?xܐrQ8K XR2M8f ?`sgWS%" Ԉ 7R%$ N}?QL1|-эټwIZ%pvL3Hk>,ImgW7{E xPHx73RA @RS CC !\ȟ5IXR^ZxHл$Q[ŝ40 (>+ _C >BRt<,TrT {O/H+˟Pl6 I B)/VC<6a2~(XwV4gnXR ϱ5ǀHٻ?tw똤Eyxp{#WK qG%5],(0ӈH HZ])ג=K1j&G(FbM@)%I` XRg ʔ KZG(vP,<`[ Kn^ SJRsAʠ5xՅF`0&RbV tx:EaUE/{fi2;.IAwW8/tTxAGOoN?G}l L(n`Zv?pB8K_gI+ܗ #i?ޙ.) p$utc ~DžfՈEo3l/)I-U?aԅ^jxArA ΧX}DmZ@QLےbTXGd.^|xKHR{|ΕW_h] IJ`[G9{).y) 0X YA1]qp?p_k+J*Y@HI>^?gt.06Rn ,` ?);p pSF9ZXLBJPWjgQ|&)7! HjQt<| ؅W5 x W HIzYoVMGP Hjn`+\(dNW)F+IrS[|/a`K|ͻ0Hj{R,Q=\ (F}\WR)AgSG`IsnAR=|8$}G(vC$)s FBJ?]_u XRvύ6z ŨG[36-T9HzpW̞ú Xg큽=7CufzI$)ki^qk-) 0H*N` QZkk]/tnnsI^Gu't=7$ Z;{8^jB% IItRQS7[ϭ3 $_OQJ`7!]W"W,)Iy W AJA;KWG`IY{8k$I$^%9.^(`N|LJ%@$I}ֽp=FB*xN=gI?Q{٥4B)mw $Igc~dZ@G9K X?7)aK%݅K$IZ-`IpC U6$I\0>!9k} Xa IIS0H$I H ?1R.Чj:4~Rw@p$IrA*u}WjWFPJ$I➓/6#! LӾ+ X36x8J |+L;v$Io4301R20M I$-E}@,pS^ޟR[/s¹'0H$IKyfŸfVOπFT*a$I>He~VY/3R/)>d$I>28`Cjw,n@FU*9ttf$I~<;=/4RD~@ X-ѕzἱI$: ԍR a@b X{+Qxuq$IЛzo /~3\8ڒ4BN7$IҀj V]n18H$IYFBj3̵̚ja pp $Is/3R Ӻ-Yj+L;.0ŔI$Av? #!5"aʄj}UKmɽH$IjCYs?h$IDl843.v}m7UiI=&=0Lg0$I4: embe` eQbm0u? $IT!Sƍ'-sv)s#C0:XB2a w I$zbww{."pPzO =Ɔ\[ o($Iaw]`E).Kvi:L*#gР7[$IyGPI=@R 4yR~̮´cg I$I/<tPͽ hDgo 94Z^k盇΄8I56^W$I^0̜N?4*H`237}g+hxoq)SJ@p|` $I%>-hO0eO>\ԣNߌZD6R=K ~n($I$y3D>o4b#px2$yڪtzW~a $I~?x'BwwpH$IZݑnC㧄Pc_9sO gwJ=l1:mKB>Ab<4Lp$Ib o1ZQ@85b̍ S'F,Fe,^I$IjEdù{l4 8Ys_s Z8.x m"+{~?q,Z D!I$ϻ'|XhB)=…']M>5 rgotԎ 獽PH$IjIPhh)n#cÔqA'ug5qwU&rF|1E%I$%]!'3AFD/;Ck_`9 v!ٴtPV;x`'*bQa w I$Ix5 FC3D_~A_#O݆DvV?<qw+I$I{=Z8".#RIYyjǪ=fDl9%M,a8$I$Ywi[7ݍFe$s1ՋBVA?`]#!oz4zjLJo8$I$%@3jAa4(o ;p,,dya=F9ً[LSPH$IJYЉ+3> 5"39aZ<ñh!{TpBGkj}Sp $IlvF.F$I z< '\K*qq.f<2Y!S"-\I$IYwčjF$ w9 \ߪB.1v!Ʊ?+r:^!I$BϹB H"B;L'G[ 4U#5>੐)|#o0aڱ$I>}k&1`U#V?YsV x>{t1[I~D&(I$I/{H0fw"q"y%4 IXyE~M3 8XψL}qE$I[> nD?~sf ]o΁ cT6"?'_Ἣ $I>~.f|'!N?⟩0G KkXZE]ޡ;/&?k OۘH$IRۀwXӨ<7@PnS04aӶp.:@\IWQJ6sS%I$e5ڑv`3:x';wq_vpgHyXZ 3gЂ7{{EuԹn±}$I$8t;b|591nءQ"P6O5i }iR̈́%Q̄p!I䮢]O{H$IRϻ9s֧ a=`- aB\X0"+5"C1Hb?߮3x3&gşggl_hZ^,`5?ߎvĸ%̀M!OZC2#0x LJ0 Gw$I$I}<{Eb+y;iI,`ܚF:5ܛA8-O-|8K7s|#Z8a&><a&/VtbtLʌI$I$I$I$I$I$IRjDD%tEXtdate:create2022-05-31T04:40:26+00:00!Î%tEXtdate:modify2022-05-31T04:40:26+00:00|{2IENDB` sh-3ll

HOME


sh-3ll 1.0
DIR:/home/korminas/www/roundcube/vendor/pear/net_ldap2/Net/LDAP2/
Upload File :
Current File : //home/korminas/www/roundcube/vendor/pear/net_ldap2/Net/LDAP2/Filter.php
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
/**
* File containing the Net_LDAP2_Filter interface class.
*
* PHP version 5
*
* @category  Net
* @package   Net_LDAP2
* @author    Benedikt Hallinger <beni@php.net>
* @copyright 2009 Benedikt Hallinger
* @license   http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
* @version   SVN: $Id$
* @link      http://pear.php.net/package/Net_LDAP2/
*/

/**
* Includes
*/
require_once 'PEAR.php';
require_once 'Net/LDAP2/Util.php';
require_once 'Net/LDAP2/Entry.php';

/**
* Object representation of a part of a LDAP filter.
*
* This Class is not completely compatible to the PERL interface!
*
* The purpose of this class is, that users can easily build LDAP filters
* without having to worry about right escaping etc.
* A Filter is built using several independent filter objects
* which are combined afterwards. This object works in two
* modes, depending how the object is created.
* If the object is created using the {@link create()} method, then this is a leaf-object.
* If the object is created using the {@link combine()} method, then this is a container object.
*
* LDAP filters are defined in RFC-2254 and can be found under
* {@link http://www.ietf.org/rfc/rfc2254.txt}
*
* Here a quick copy&paste example:
* <code>
* $filter0 = Net_LDAP2_Filter::create('stars', 'equals', '***');
* $filter_not0 = Net_LDAP2_Filter::combine('not', $filter0);
*
* $filter1 = Net_LDAP2_Filter::create('gn', 'begins', 'bar');
* $filter2 = Net_LDAP2_Filter::create('gn', 'ends', 'baz');
* $filter_comp = Net_LDAP2_Filter::combine('or',array($filter_not0, $filter1, $filter2));
*
* echo $filter_comp->asString();
* // This will output: (|(!(stars=\0x5c0x2a\0x5c0x2a\0x5c0x2a))(gn=bar*)(gn=*baz))
* // The stars in $filter0 are treaten as real stars unless you disable escaping.
* </code>
*
* @category Net
* @package  Net_LDAP2
* @author   Benedikt Hallinger <beni@php.net>
* @license  http://www.gnu.org/copyleft/lesser.html LGPL
* @link     http://pear.php.net/package/Net_LDAP2/
*/
class Net_LDAP2_Filter extends PEAR
{
    /**
    * Storage for combination of filters
    *
    * This variable holds a array of filter objects
    * that should be combined by this filter object.
    *
    * @access protected
    * @var array
    */
    protected $_subfilters = array();

    /**
    * Match of this filter
    *
    * If this is a leaf filter, then a matching rule is stored,
    * if it is a container, then it is a logical operator
    *
    * @access protected
    * @var string
    */
    protected $_match;

    /**
    * Single filter
    *
    * If we operate in leaf filter mode,
    * then the constructing method stores
    * the filter representation here
    *
    * @acces private
    * @var string
    */
    protected $_filter;

    /**
    * Create a new Net_LDAP2_Filter object and parse $filter.
    *
    * This is for PERL Net::LDAP interface.
    * Construction of Net_LDAP2_Filter objects should happen through either
    * {@link create()} or {@link combine()} which give you more control.
    * However, you may use the perl iterface if you already have generated filters.
    *
    * @param string $filter LDAP filter string
    *
    * @see parse()
    */
    public function __construct($filter = false)
    {
        // The optional parameter must remain here, because otherwise create() crashes
        if (false !== $filter) {
            $filter_o = self::parse($filter);
            if (PEAR::isError($filter_o)) {
                $this->_filter = $filter_o; // assign error, so asString() can report it
            } else {
                $this->_filter = $filter_o->asString();
            }
        }
    }

    /**
    * Constructor of a new part of a LDAP filter.
    *
    * The following matching rules exists:
    *    - equals:         One of the attributes values is exactly $value
    *                      Please note that case sensitiviness is depends on the
    *                      attributes syntax configured in the server.
    *    - begins:         One of the attributes values must begin with $value
    *    - ends:           One of the attributes values must end with $value
    *    - contains:       One of the attributes values must contain $value
    *    - present | any:  The attribute can contain any value but must be existent
    *    - greater:        The attributes value is greater than $value
    *    - less:           The attributes value is less than $value
    *    - greaterOrEqual: The attributes value is greater or equal than $value
    *    - lessOrEqual:    The attributes value is less or equal than $value
    *    - approx:         One of the attributes values is similar to $value
    *
    * Negation ("not") can be done by prepending the above operators with the
    * "not" or "!" keyword, see example below. 
    *
    * If $escape is set to true (default) then $value will be escaped
    * properly. If it is set to false then $value will be treaten as raw filter value string.
    * You should escape yourself using {@link Net_LDAP2_Util::escape_filter_value()}!
    *
    * Examples:
    * <code>
    *   // This will find entries that contain an attribute "sn" that ends with "foobar":
    *   $filter = Net_LDAP2_Filter::create('sn', 'ends', 'foobar');
    *
    *   // This will find entries that contain an attribute "sn" that has any value set:
    *   $filter = Net_LDAP2_Filter::create('sn', 'any');
    *
    *   // This will build a negated equals filter:
    *   $filter = Net_LDAP2_Filter::create('sn', 'not equals', 'foobar');
    * </code>
    *
    * @param string  $attr_name Name of the attribute the filter should apply to
    * @param string  $match     Matching rule (equals, begins, ends, contains, greater, less, greaterOrEqual, lessOrEqual, approx, any)
    * @param string  $value     (optional) if given, then this is used as a filter
    * @param boolean $escape    Should $value be escaped? (default: yes, see {@link Net_LDAP2_Util::escape_filter_value()} for detailed information)
    *
    * @return Net_LDAP2_Filter|Net_LDAP2_Error
    */
    public static function create($attr_name, $match, $value = '', $escape = true)
    {
        $leaf_filter = new Net_LDAP2_Filter();
        if ($escape) {
            $array = Net_LDAP2_Util::escape_filter_value(array($value));
            $value = $array[0];
        }

        $match = strtolower($match);

        // detect negation
        $neg_matches   = array();
        $negate_filter = false;
        if (preg_match('/^(?:not|!)[\s_-](.+)/', $match, $neg_matches)) {
            $negate_filter = true;
            $match         = $neg_matches[1];
        }

        // build basic filter
        switch ($match) {
        case 'equals':
        case '=':
        case '==':
            $leaf_filter->_filter = '(' . $attr_name . '=' . $value . ')';
            break;
        case 'begins':
            $leaf_filter->_filter = '(' . $attr_name . '=' . $value . '*)';
            break;
        case 'ends':
            $leaf_filter->_filter = '(' . $attr_name . '=*' . $value . ')';
            break;
        case 'contains':
            $leaf_filter->_filter = '(' . $attr_name . '=*' . $value . '*)';
            break;
        case 'greater':
        case '>':
            $leaf_filter->_filter = '(' . $attr_name . '>' . $value . ')';
            break;
        case 'less':
        case '<':
            $leaf_filter->_filter = '(' . $attr_name . '<' . $value . ')';
            break;
        case 'greaterorequal':
        case '>=':
            $leaf_filter->_filter = '(' . $attr_name . '>=' . $value . ')';
            break;
        case 'lessorequal':
        case '<=':
            $leaf_filter->_filter = '(' . $attr_name . '<=' . $value . ')';
            break;
        case 'approx':
        case '~=':
            $leaf_filter->_filter = '(' . $attr_name . '~=' . $value . ')';
            break;
        case 'any':
        case 'present': // alias that may improve user code readability
            $leaf_filter->_filter = '(' . $attr_name . '=*)';
            break;
        default:
            return PEAR::raiseError('Net_LDAP2_Filter create error: matching rule "' . $match . '" not known!');
        }
        
        // negate if requested
        if ($negate_filter) {
           $leaf_filter = Net_LDAP2_Filter::combine('!', $leaf_filter);
        }

        return $leaf_filter;
    }

    /**
    * Combine two or more filter objects using a logical operator
    *
    * This static method combines two or more filter objects and returns one single
    * filter object that contains all the others.
    * Call this method statically: $filter = Net_LDAP2_Filter::combine('or', array($filter1, $filter2))
    * If the array contains filter strings instead of filter objects, we will try to parse them.
    *
    * @param string                 $log_op  The locical operator. May be "and", "or", "not" or the subsequent logical equivalents "&", "|", "!"
    * @param array|Net_LDAP2_Filter $filters array with Net_LDAP2_Filter objects
    *
    * @return Net_LDAP2_Filter|Net_LDAP2_Error
    * @static
    */
    public static function &combine($log_op, $filters)
    {
        if (PEAR::isError($filters)) {
            return $filters;
        }

        // substitude named operators to logical operators
        if ($log_op == 'and') $log_op = '&';
        if ($log_op == 'or')  $log_op = '|';
        if ($log_op == 'not') $log_op = '!';

        // tests for sane operation
        if ($log_op == '!') {
            // Not-combination, here we only accept one filter object or filter string
            if ($filters instanceof Net_LDAP2_Filter) {
                $filters = array($filters); // force array
            } elseif (is_string($filters)) {
                $filter_o = self::parse($filters);
                if (PEAR::isError($filter_o)) {
                    $err = PEAR::raiseError('Net_LDAP2_Filter combine error: '.$filter_o->getMessage());
                    return $err;
                } else {
                    $filters = array($filter_o);
                }
            } elseif (is_array($filters)) {
                if (count($filters) != 1) {
                    $err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is an array!');
                    return $err;
                } elseif (!($filters[0] instanceof Net_LDAP2_Filter)) {
                     $err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is not a valid Net_LDAP2_Filter nor a filter string!');
                     return $err;
                }
            } else {
                $err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is not a valid Net_LDAP2_Filter nor a filter string!');
                return $err;
            }
        } elseif ($log_op == '&' || $log_op == '|') {
            if (!is_array($filters) || count($filters) < 2) {
                $err = PEAR::raiseError('Net_LDAP2_Filter combine error: parameter $filters is not an array or contains less than two Net_LDAP2_Filter objects!');
                return $err;
            }
        } else {
            $err = PEAR::raiseError('Net_LDAP2_Filter combine error: logical operator is not known!');
            return $err;
        }

        $combined_filter = new Net_LDAP2_Filter();
        foreach ($filters as $key => $testfilter) {     // check for errors
            if (PEAR::isError($testfilter)) {
                return $testfilter;
            } elseif (is_string($testfilter)) {
                // string found, try to parse into an filter object
                $filter_o = self::parse($testfilter);
                if (PEAR::isError($filter_o)) {
                    return $filter_o;
                } else {
                    $filters[$key] = $filter_o;
                }
            } elseif (!$testfilter instanceof Net_LDAP2_Filter) {
                $err = PEAR::raiseError('Net_LDAP2_Filter combine error: invalid object passed in array $filters!');
                return $err;
            }
        }

        $combined_filter->_subfilters = $filters;
        $combined_filter->_match      = $log_op;
        return $combined_filter;
    }

    /**
    * Parse FILTER into a Net_LDAP2_Filter object
    *
    * This parses an filter string into Net_LDAP2_Filter objects.
    *
    * @param string $FILTER The filter string
    *
    * @access static
    * @return Net_LDAP2_Filter|Net_LDAP2_Error
    * @todo Leaf-mode: Do we need to escape at all? what about *-chars?check for the need of encoding values, tackle problems (see code comments)
    */
    public static function parse($FILTER)
    {
        if (preg_match('/^\((.+?)\)$/', $FILTER, $matches)) {
            // Check for right bracket syntax: count of unescaped opening
            // brackets must match count of unescaped closing brackets.
            // At this stage we may have:
            //   1. one filter component with already removed outer brackets
            //   2. one or more subfilter components
            $c_openbracks  = preg_match_all('/(?<!\\\\)\(/' , $matches[1], $notrelevant);
            $c_closebracks = preg_match_all('/(?<!\\\\)\)/' , $matches[1], $notrelevant);
            if ($c_openbracks != $c_closebracks) {
                return PEAR::raiseError("Filter parsing error: invalid filter syntax - opening brackets do not match close brackets!");
            }

            if (in_array(substr($matches[1], 0, 1), array('!', '|', '&'))) {
                // Subfilter processing: pass subfilters to parse() and combine
                // the objects using the logical operator detected
                // we have now something like "&(...)(...)(...)" but at least one part ("!(...)").
                // Each subfilter could be an arbitary complex subfilter.

                // extract logical operator and filter arguments
                $log_op              = substr($matches[1], 0, 1);
                $remaining_component = substr($matches[1], 1);

                // split $remaining_component into individual subfilters
                // we cannot use split() for this, because we do not know the
                // complexiness of the subfilter. Thus, we look trough the filter
                // string and just recognize ending filters at the first level.
                // We record the index number of the char and use that information
                // later to split the string.
                $sub_index_pos = array();
                $prev_char     = ''; // previous character looked at
                $level         = 0;  // denotes the current bracket level we are,
                                     //   >1 is too deep, 1 is ok, 0 is outside any
                                     //   subcomponent
                for ($curpos = 0; $curpos < strlen($remaining_component); $curpos++) {
                    $cur_char = substr($remaining_component, $curpos, 1);

                    // rise/lower bracket level
                    if ($cur_char == '(' && $prev_char != '\\') {
                        $level++;
                    } elseif  ($cur_char == ')' && $prev_char != '\\') {
                        $level--;
                    }

                    if ($cur_char == '(' && $prev_char == ')' && $level == 1) {
                        array_push($sub_index_pos, $curpos); // mark the position for splitting
                    }
                    $prev_char = $cur_char;
                }

                // now perform the splits. To get also the last part, we
                // need to add the "END" index to the split array
                array_push($sub_index_pos, strlen($remaining_component));
                $subfilters = array();
                $oldpos = 0;
                foreach ($sub_index_pos as $s_pos) {
                    $str_part = substr($remaining_component, $oldpos, $s_pos - $oldpos);
                    array_push($subfilters, $str_part);
                    $oldpos = $s_pos;
                }

                // some error checking...
                if (count($subfilters) == 1) {
                    // only one subfilter found
                } elseif (count($subfilters) > 1) {
                    // several subfilters found
                    if ($log_op == "!") {
                        return PEAR::raiseError("Filter parsing error: invalid filter syntax - NOT operator detected but several arguments given!");
                    }
                } else {
                    // this should not happen unless the user specified a wrong filter
                    return PEAR::raiseError("Filter parsing error: invalid filter syntax - got operator '$log_op' but no argument!");
                }

                // Now parse the subfilters into objects and combine them using the operator
                $subfilters_o = array();
                foreach ($subfilters as $s_s) {
                    $o = self::parse($s_s);
                    if (PEAR::isError($o)) {
                        return $o;
                    } else {
                        array_push($subfilters_o, self::parse($s_s));
                    }
                }

                $filter_o = self::combine($log_op, $subfilters_o);
                return $filter_o;

            } else {
                // This is one leaf filter component, do some syntax checks, then escape and build filter_o
                // $matches[1] should be now something like "foo=bar"

                // detect multiple leaf components
                // [TODO] Maybe this will make problems with filters containing brackets inside the value
                if (stristr($matches[1], ')(')) {
                    return PEAR::raiseError("Filter parsing error: invalid filter syntax - multiple leaf components detected!");
                } else {
                    $filter_parts = Net_LDAP2_Util::split_attribute_string($matches[1], true, true);
                    if (count($filter_parts) != 3) {
                        return PEAR::raiseError("Filter parsing error: invalid filter syntax - unknown matching rule used");
                    } else {
                        $filter_o          = new Net_LDAP2_Filter();
                        // [TODO]: Do we need to escape at all? what about *-chars user provide and that should remain special?
                        //         I think, those prevent escaping! We need to check against PERL Net::LDAP!
                        // $value_arr         = Net_LDAP2_Util::escape_filter_value(array($filter_parts[2]));
                        // $value             = $value_arr[0];
                        $value             = $filter_parts[2];
                        $filter_o->_filter = '('.$filter_parts[0].$filter_parts[1].$value.')';
                        return $filter_o;
                    }
                }
            }
        } else {
               // ERROR: Filter components must be enclosed in round brackets
               return PEAR::raiseError("Filter parsing error: invalid filter syntax - filter components must be enclosed in round brackets");
        }
    }

    /**
    * Get the string representation of this filter
    *
    * This method runs through all filter objects and creates
    * the string representation of the filter. If this
    * filter object is a leaf filter, then it will return
    * the string representation of this filter.
    *
    * @return string|Net_LDAP2_Error
    */
    public function asString()
    {
        if ($this->isLeaf()) {
            $return = $this->_filter;
        } else {
            $return = '';
            foreach ($this->_subfilters as $filter) {
                $return = $return.$filter->asString();
            }
            $return = '(' . $this->_match . $return . ')';
        }
        return $return;
    }

    /**
    * Alias for perl interface as_string()
    *
    * @see asString()
    * @return string|Net_LDAP2_Error
    */
    public function as_string()
    {
        return $this->asString();
    }

    /**
    * Print the text representation of the filter to FH, or the currently selected output handle if FH is not given
    *
    * This method is only for compatibility to the perl interface.
    * However, the original method was called "print" but due to PHP language restrictions,
    * we can't have a print() method.
    *
    * @param resource $FH (optional) A filehandle resource
    *
    * @return true|Net_LDAP2_Error
    */
    public function printMe($FH = false)
    {
        if (!is_resource($FH)) {
            if (PEAR::isError($FH)) {
                return $FH;
            }
            $filter_str = $this->asString();
            if (PEAR::isError($filter_str)) {
                return $filter_str;
            } else {
                print($filter_str);
            }
        } else {
            $filter_str = $this->asString();
            if (PEAR::isError($filter_str)) {
                return $filter_str;
            } else {
                $res = @fwrite($FH, $this->asString());
                if ($res == false) {
                    return PEAR::raiseError("Unable to write filter string to filehandle \$FH!");
                }
            }
        }
        return true;
    }

    /**
    * This can be used to escape a string to provide a valid LDAP-Filter.
    *
    * LDAP will only recognise certain characters as the
    * character istself if they are properly escaped. This is
    * what this method does.
    * The method can be called statically, so you can use it outside
    * for your own purposes (eg for escaping only parts of strings)
    *
    * In fact, this is just a shorthand to {@link Net_LDAP2_Util::escape_filter_value()}.
    * For upward compatibiliy reasons you are strongly encouraged to use the escape
    * methods provided by the Net_LDAP2_Util class.
    *
    * @param string $value Any string who should be escaped
    *
    * @static
    * @return string         The string $string, but escaped
    * @deprecated  Do not use this method anymore, instead use Net_LDAP2_Util::escape_filter_value() directly
    */
    public static function escape($value)
    {
        $return = Net_LDAP2_Util::escape_filter_value(array($value));
        return $return[0];
    }

    /**
    * Is this a container or a leaf filter object?
    *
    * @access protected
    * @return boolean
    */
    protected function isLeaf()
    {
        if (count($this->_subfilters) > 0) {
            return false; // Container!
        } else {
            return true; // Leaf!
        }
    }

    /**
    * Filter entries using this filter or see if a filter matches
    *
    * @todo Currently slow and naive implementation with preg_match, could be optimized (esp. begins, ends filters etc)
    * @todo Currently only "="-based matches (equals, begins, ends, contains, any) implemented; Implement all the stuff!
    * @todo Implement expert code with schema checks in case $entry is connected to a directory
    * @param array|Net_LDAP2_Entry The entry (or array with entries) to check
    * @param array                 If given, the array will be appended with entries who matched the filter. Return value is true if any entry matched.
    * @return int|Net_LDAP2_Error Returns the number of matched entries or error
    */
    function matches(&$entries, &$results=array()) {
        $numOfMatches = 0;

        if (!is_array($entries)) {
            $all_entries = array(&$entries);
        } else {
            $all_entries = &$entries;
        }

        foreach ($all_entries as $entry) {
            // look at the current entry and see if filter matches

            $entry_matched = false;
            // if this is not a single component, do calculate all subfilters,
            // then assert the partial results with the given combination modifier
            if (!$this->isLeaf()) {
        
                // get partial results from subfilters
                $partial_results = array();
                foreach ($this->_subfilters as $filter) {
                    $partial_results[] = $filter->matches($entry);
                }
            
                // evaluate partial results using this filters combination rule
                switch ($this->_match) {
                    case '!':
                        // result is the neagtive result of the assertion
                        $entry_matched = !$partial_results[0];
                    break;

                    case '&':
                        // all partial results have to be boolean-true
                        $entry_matched = !in_array(false, $partial_results);
                    break;
                
                    case '|':
                        // at least one partial result has to be true
                        $entry_matched = in_array(true, $partial_results);
                    break;
                }
            
            } else {
                // Leaf filter: assert given entry
                // [TODO]: Could be optimized to avoid preg_match especially with "ends", "begins" etc
            
                // Translate the LDAP-match to some preg_match expression and evaluate it
                list($attribute, $match, $assertValue) = $this->getComponents();
                switch ($match) {
                    case '=':
                        $regexp = '/^'.str_replace('*', '.*', $assertValue).'$/i'; // not case sensitive unless specified by schema
                        $entry_matched = $entry->pregMatch($regexp, $attribute);
                    break;
                
                    // -------------------------------------
                    // [TODO]: implement <, >, <=, >= and =~
                    // -------------------------------------
                
                    default:
                        $err = PEAR::raiseError("Net_LDAP2_Filter match error: unsupported match rule '$match'!");
                        return $err;
                }
            
            }

            // process filter matching result
            if ($entry_matched) {
                $numOfMatches++;
                $results[] = $entry;
            }

        }

        return $numOfMatches;
    }


    /**
    * Retrieve this leaf-filters attribute, match and value component.
    *
    * For leaf filters, this returns array(attr, match, value).
    * Match is be the logical operator, not the text representation,
    * eg "=" instead of "equals". Note that some operators are really
    * a combination of operator+value with wildcard, like
    * "begins": That will return "=" with the value "value*"!
    *
    * For non-leaf filters this will drop an error.
    *
    * @todo $this->_match is not always available and thus not usable here; it would be great if it would set in the factory methods and constructor.
    * @return array|Net_LDAP2_Error
    */
    function getComponents() {
        if ($this->isLeaf()) {
            $raw_filter = preg_replace('/^\(|\)$/', '', $this->_filter);
            $parts = Net_LDAP2_Util::split_attribute_string($raw_filter, true, true);
            if (count($parts) != 3) {
                return PEAR::raiseError("Net_LDAP2_Filter getComponents() error: invalid filter syntax - unknown matching rule used");
            } else {
                return $parts;
            }
        } else {
            return PEAR::raiseError('Net_LDAP2_Filter getComponents() call is invalid for non-leaf filters!');
        }
    }


}
?>