PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i5h-3LL

HOME


5h-3LL 1.0
DIR: /srv/http/vyvoj.adent.cz/vyvoj/old.farma-sidlakov.cz/www/test/news
/srv/http/vyvoj.adent.cz/vyvoj/old.farma-sidlakov.cz/www/test/news/
Upload File:
Current File : /srv/http/vyvoj.adent.cz/vyvoj/old.farma-sidlakov.cz/www/test/news/functions.php
<?php

/**
 * Global functions used throughout the script
 *
 * @package FusionNews
 * @copyright (c) 2006 - 2010, FusionNews.net
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL 3.0 License
 * @version $Id: functions.php 341 2010-12-17 16:45:57Z xycaleth $
 *
 * This file is part of Fusion News.
 *
 * Fusion News is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * Fusion News is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Fusion News.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Replaces BBCode in the given text
 * @param string $message The text containing the BBCodes to be replaced
 * @return string The processed text with BBCodes replaced
 * @todo Handle nested tags.
 */
function replace_bbcode ( $message )
{
    static $bbcode_normal_find_pair = array (
       '[move]', '[/move]',
       '[sub]', '[/sub]',
       '[sup]', '[/sup]',
       '[s]', '[/s]',
       '[b]', '[/b]',
       '[u]', '[/u]',
       '[i]', '[/i]',
       '[tt]', '[/tt]',
       '[quote]', '[/quote]',
       '[list]', '[/list]'
    );
    
    static $bbcode_normal_replace_pair = array (
       '<marquee>', '</marquee>',
       '<sub>', '</sub>',
       '<sup>', '</sup>',
       '<del>', '</del>',
       '<strong>', '</strong>',
       '<u>', '</u>',
       '<em>', '</em>',
       '<tt>', '</tt>',
       '<blockquote>quote:<hr style="height:1px" />&quot;', '&quot;<hr style="height:1px" /></blockquote>',
       '<ul>', '</ul>'
    );
    
    static $bbcode_normal_find = array (
        '[hr]'
    );
    
    static $bbcode_normal_replace = array (
        '<hr />'
    );
    
    $message = str_replace ($bbcode_normal_find, $bbcode_normal_replace, $message);
    
    $find = array();
    $replace = array();
    for ( $i = 0, $num_bbcode = sizeof ($bbcode_normal_find_pair); $i < $num_bbcode; $i += 2 )
    {
        $find[] = '#' . preg_quote ($bbcode_normal_find_pair[$i], '#') . '(.*?)' . preg_quote ($bbcode_normal_find_pair[$i + 1], '#') . '#i';
        $replace[] = $bbcode_normal_replace_pair[$i] . '$1' . $bbcode_normal_replace_pair[$i + 1];
    }
    
    $message = preg_replace ($find, $replace, $message);
	
    static $email_regex = '([A-Za-z0-9\!\#\$\%\&\'\*\+\-\/\=\?\^_`\{\|\}\~]{1,64}@[a-z0-9\-\.]{2,65})';
	$bbcode_preg_find = array (
	   '/\[font=(\w+)](.*?)\[\/font\]/i',
	   '/\[color=(\w+)](.*?)\[\/color\]/i',
	   '/\[size=(\d+)](.*?)\[\/size\]/i',
	   '/\[align=(left|center|right)](.*?)\[\/align\]/i',
	   '/\[img]([^\[\]]*)\[\/img]/i',
	   '/\[img height=(\d+) width=(\d+)]([^\[\]]*)\[\/img]/i',
	   '/\[img width=(\d+) height=(\d+)]([^\[\]]*)\[\/img]/i',
	   '/\[flash=(\d+),(\d+)]([^\[\]]*)\[\/flash]/i',
	   '/\[email]' . $email_regex . '\[\/email\]/i',
	   '/\[email=' . $email_regex . '](.*?)\[\/email\]/i',
	   '#\[\*\]([^\[]+)#',
	   '#\[url\]([^\[\]]+)\[/url\]#i',
	   '#\[url=([^\[\]]+)\]([^\[]+)\[/url\]#i',
	);
	
	$bbcode_preg_replace = array (
	   '<span style="font-family:$1">$2</span>',
	   '<span style="color:$1">$2</span>',
	   '<span style="font-size:$1px">$2</span>',
	   '<div style="text-align:$1">$2</div>',
	   '<img src="$1" alt="" />',
	   '<img src="$3" style="height:$1px; width:$2px" alt="" />',
	   '<img src="$3" style="height:$2px; width:$1px" alt="" />',
	   '<object type="application/x-shockwave-flash" data="$3" width="$1" height="$2"><param name="movie" value="$3" /><span>Flash required</span></object>',
	   '<a href="mailto:$1">$1</a>',
	   '<a href="mailto:$1">$2</a>',
	   '<li>$1</li>',
	   '<a href="$1">$1</a>',
	   '<a href="$1">$2</a>'
	);
	
	$message = preg_replace ($bbcode_preg_find, $bbcode_preg_replace, $message);

	return $message;
}

/**
 * @return array List of all smileys
 */
function get_smiley_list()
{
    static $smileys = null;
    
    if ( $smileys === null )
    {
        $file = file (FNEWS_ROOT_PATH . 'smillies.php');
        array_shift ($file);
        
        $smileys = array();
        foreach ( $file as $value )
        {
            $smiley = get_line_data ('smillies', $value);
            $smiley['bbcode'] = html_entity_decode ($smiley['bbcode']);
            $smiley['image'] = chop ($smiley['image']);
            $smileys[] = $smiley;
        }
    }
    
    return $smileys;
}

/**
 * Replaces smiley codes in the given text
 * @param string $message Text containing the smiley codes to be replaced
 * @return string The processed text with smiley codes replaced
 */
function replace_smileys ( $message )
{
	global $furl;
	
	static $smiley_table = null;
	
	if ( $smiley_table === null )
	{
        $smileys = get_smiley_list();
	    foreach ( $smileys as $smiley )
	    {
		    $smiley_table['find'][] = $smiley['bbcode'];
		    $smiley_table['replace'][] = '<img src="' . $furl . '/smillies/' . $smiley['image'] . '" alt="' . $smiley['image'] . '" />';
	    }
	}

	$message = str_replace ($smiley_table['find'], $smiley_table['replace'], $message);

	return $message;
}

/**
 * @param string $template File name of template to get
 * @param bool $php_enabled Whether or not to parse PHP in the template file
 * @return string Contents of template file
 */
function get_template ( $template, $php_enabled )
{
	$text = '';

    if ( $php_enabled )
    {
        ob_start();
        include (FNEWS_ROOT_PATH . 'templates/' . $template);
        $text = ob_get_clean();
    }
    else
    {
        $text = file_get_contents (FNEWS_ROOT_PATH . 'templates/' . $template);
    }
        
	return $text;
}

/**
 * @return array Array of toc.php lines, ordered by date
 */
function get_ordered_toc()
{
	$file = file (FNEWS_ROOT_PATH . 'news/toc.php');
	array_shift ($file);

	if ( count ($file) <= 0 )
	{
		return array();
	}
	
	$array = array();
	foreach ( $file as $value )
	{
		$news_data = explode ('|<|', $value);
		$array[$news_data[1]] = chop (trim ($value));
	}

	krsort ($array);
	return array_values ($array);
}

/**
 * Filters words listed in the word filter
 * @param string $message Text to have the word filter applied to
 * @return string Word-filtered text
 */
function filter_badwords ( $message )
{
    static $badword_table = null;
    
    if ( $badword_table === null )
    {
	    $badword_table = array('find' => array(), 'replace' => array());
	    $file = file (FNEWS_ROOT_PATH . 'badwords.php');
	    array_shift ($file);

	    foreach ( $file as $rule )
	    {
		    $badword = get_line_data ('badwords', $rule);

		    if ( $badword['type'] == 2 )
		    {
			    // Regular expressions match
			    $badword_table['find'][] = html_entity_decode ($badword['find']);
			    $badword_table['replace'][] = html_entity_decode ($badword['replace']);
		    }
		    else
		    {
			    // Strict
			    if ( $badword['type'] == 0 )
			    {
				    $badword_table['find'][] = '#\b' . preg_quote ($badword['find'], '#') . '\b#' . (!$badword['case_sensitive'] ? 'i' : '');
			    }
			    // Loose
			    else if ( $badword['type'] == 1 )
			    {
				    $badword_table['find'][] = '#' . preg_quote ($badword['find'], '#') . '#' . (!$badword['case_sensitive'] ? 'i' : '');
			    }
			    $badword_table['replace'][] = $badword['replace'];
		    }
	    }
	}

	$message = preg_replace ($badword_table['find'], $badword_table['replace'], $message);

	return $message;
}

/**
 * Checks if the given user name or nick name exists, and then returns
 * the said user's data.
 * @param string $user User's log in name
 * @param string $nick User's nick name
 * @return array|bool Returns FALSE if the user doesn't exist, otherwise
 * returns the specified user's data.
 */
function get_author ( $user, $nick = '' )
{
    static $user_table = array();

	if ( !$nick && !$user )
	{
		return false;
	}
	
	if ( isset ($user_table[$user]) )
    {
        return $user_table[$user];
    }
    
    if ( isset ($user_table[$nick]) )
    {
        return $user_table[$nick];
    }

	if ( !$nick && $user )
	{
		$nick = $user;
	}
	else if ($nick && !$user)
	{
		$user = $nick;
	}

	$file = file(FNEWS_ROOT_PATH . 'users.php');
	array_shift($file);
	foreach ( $file as $value )
	{
		$userdat = get_line_data ('users', $value);

		if( ($user == $userdat['username']) || ($nick == $userdat['nickname']) )
		{		
			$email = explode ('=', $userdat['email']);

		    $user_array = array (
				'user'		=> $userdat['username'],
				'nick'		=> $userdat['nickname'],
				'email'		=> $email[1],
				'showemail'		=> $email[0],
				'icon'		=> $userdat['icon'],
				'timeoffset'	=> $userdat['timeoffset'],
				'level'		=> $userdat['level']
			);
			
			$user_table[$userdat['username']] = $user_table[$userdat['nickname']] = $user_array;
			
			return $user_array;
		}
	}

	return false;
}

/**
 * Converts a number of bytes into text, taking into account the units (B, KB, MB, etc)
 * @param int $size Number of bytes to convert
 * @return string The converted bytes as text.
 */
function calc_size ( $size )
{
	if ( $size < 1024 )
	{ // Bytes
		return $size . ' B';
	}
	else if ( $size < (1024 * 1024) )
	{ // Kilobytes
		return round (($size / 1024), 2) . ' KB';
	}
	else if ( $size < (1024 * 1024 * 1024) )
	{ // Megabytes
		return round ($size / (1024 * 1024), 2) . ' MB';
	}
}

/**
 * Checks whether an email address has a valid format.
 * @param string $email Email address to validate.
 * @return bool True if the email address is valid, otherwise false.
 */
function is_valid_email ( $email )
{
	// Returns true if email address has a valid form.
	return preg_match ('#[A-Za-z0-9\!\#\$\%\&\'\*\+\-\/\=\?\^_`\{\|\}\~]{1,64}@[a-z0-9\-\.]{2,65}#', $email);
}

/**
 * Checks if the user is flooding the comments.
 * @return bool True is the user is flooding, otherwise false.
 */
function is_flooding()
{
	global $floodtime;

	$user_ip = get_ip();
	$current_time = time();

	$file = file (FNEWS_ROOT_PATH . 'flood.php');
	$data = array_shift ($file);

	$flooding = false;
	foreach ( $file as $line )
	{
		$record = get_line_data ('flood', $line);

		if ( ($record['timestamp'] + $floodtime) <= $current_time )
		{
			// Times up. Remove this old record.
			continue;
		}

		if ( $record['ip'] == $user_ip )
		{
			// We've added a comment too recently.
			$flooding = true;
		}

		$data .= $line;
	}

	safe_write ('flood.php', 'wb', $data);

	return $flooding;
}

/**
 * Check if the given IP is banned
 * @param string $ip IP address to check if banned
 * @return bool True is the given IP is banned, otherwise false.
 */
function is_ip_banned ( $ip )
{
	$file = file (FNEWS_ROOT_PATH . 'banned.php');
	array_shift($file);

	$my_subnet = explode ('.', $ip);
	foreach ( $file as $value )
	{
		$value = trim ($value);
		$octet = explode ('.', $value);
		if ( ($octet[0] == $my_subnet[0] || $octet[0] == '*') &&
			($octet[1] == $my_subnet[1] || $octet[1] == '*') &&
			($octet[2] == $my_subnet[2] || $octet[2] == '*') &&
			($octet[3] == $my_subnet[3] || $octet[3] == '*') )
		{
			return true;
		}
	}

	return false;
}

/**
 * @return string Returns the user's IP address
 */
function get_ip()
{
	$realip = '';

	if ( isset ($_SERVER) )
	{
		if ( isset ( $_SERVER['REMOTE_ADDR']) )
		{
			$realip = $_SERVER['REMOTE_ADDR'];
		}
		else if ( isset ($_SERVER['HTTP_CLIENT_IP']) )
		{
			$realip = $_SERVER['HTTP_CLIENT_IP'];
		}
		else
		{
			$realip = $_SERVER['HTTP_X_FORWARDED_FOR'];
		}
	}
	else
	{
		if ( getenv ('REMOTE_ADDR') )
		{
			$realip = getenv ('REMOTE_ADDR');
		}
		else if ( getenv ('HTTP_CLIENT_IP') )
		{
			$realip = getenv ('HTTP_CLIENT_IP');
		}
		else
		{
			$realip = getenv ('HTTP_X_FORWARDED_FOR');
		}
	}

	return $realip;
}

/**
 * Checks if the user has sufficient access rights.
 * @param int $level Access level to check against
 * @return bool True if the user has sufficient access rights, otherwise false.
 */
function has_access ( $level )
{
	global $userdata;

	return ( $userdata != NULL ) ? ($userdata['level'] >= $level) : false;
}

/**
 * Cleans array key of characters other than A-Z, a-z, 0-9, underscore
 * @param string $key Key to be cleaned
 * @return string Cleaned key
 */
function clean_key ( $key )
{
	if ( $key != '' )
	{
		$key = preg_replace ('/[^A-Za-z0-9_]+/',	'',	$key);
		$key = preg_replace ('/\.\./',			'',	$key);
		$key = preg_replace ('/\_\_(.+?)\_\_/',		'',	$key);
		$key = preg_replace ('/^([\w\.\-\_]+)$/',	'$1',	$key);
	}

	return $key;
}

/**
 * Cleans array value of potentially dangerous characters
 * @param string $val Value to be cleaned
 * @return string Cleaned value
 */
function clean_value ( $val )
{
	if ( $val != '' )
	{
		// I think this block of slightly modified code came from IPB.
		/*$val = str_replace ('&#032;',		' ',		$val);
		$val = str_replace ('&',		'&amp;',	$val);
		$val = str_replace ('<!',		'&#60;&#33;',	$val);
		$val = str_replace ('-->',		'--&#62;',	$val);
		$val = preg_replace ('/<script/i',	'&#60;script',	$val);
		$val = str_replace ('>',		'&gt;',		$val);
		$val = str_replace ('<',		'&lt;',		$val);
		$val = preg_replace ('/\|/',		'&#124;',	$val);*/
		
        if ( get_magic_quotes_gpc() )
        {
            $val = stripslashes ($val);
        }
		$val = str_replace ("\r\n",		"\n",		$val);	// Win32 => new line
		$val = str_replace ("\r",		"\n",		$val);	// Mac => new line
		//$val = str_replace ('!',		'&#33;',	$val);
		
		$val = htmlspecialchars ($val);

		// Multibyte characters fix (could do it properly, but this is the easiest way and it works relatively well)
		$val = preg_replace ('/&amp;#([0-9]+);/', '&#$1;', $val);
		$val = preg_replace ('/&amp;#x([A-Z0-9]+);/i', '&#x$1', $val);
	}

	return $val;
}

/**
 * @return array Returns configuration settings
 */
function config_array()
{
	require './config.php';

	return array(
		'fusion_id'		=> $fusion_id,
		'site'			=> $site,
		'furl'			=> $furl,
		'hurl'			=> $hurl,
		'datefor'		=> $datefor,
		'numofposts'		=> $numofposts,
		'numofh'		=> $numofh,
		'bb'			=> $bb,
		'ht'			=> $ht,
		'post_per_day'		=> $post_per_day,
		'ppp_date'		=> $ppp_date,
		'wfpost'		=> $wfpost,
		'wfcom'			=> $wfcom,
		'skin'			=> $skin,
		'smilies'		=> $smilies,
		'stfpop'		=> $stfpop,
		'comallowbr'		=> $comallowbr,
		'stfwidth'		=> $stfwidth,
		'stfheight'		=> $stfheight,
		'fslink'		=> $fslink,
		'stflink'		=> $stflink,
		'pclink'		=> $pclink,
		'fsnw'			=> $fsnw,
		'cbflood'		=> $cbflood,
		'floodtime'		=> $floodtime,
		'comlength'		=> $comlength,
		'fullnewsw'		=> $fullnewsw,
		'fullnewsh'		=> $fullnewsh,
		'fullnewss'		=> $fullnewss,
		'stfresize'		=> $stfresize,
		'stfscrolls'		=> $stfscrolls,
		'fullnewsz'		=> $fullnewsz,
		'htc'			=> $htc,
		'smilcom'		=> $smilcom,
		'bbc'			=> $bbc,
		'compop'		=> $compop,
		'comscrolls'		=> $comscrolls,
		'comresize'		=> $comresize,
		'comheight'		=> $comheight,
		'comwidth'		=> $comwidth,
		'uploads_active'	=> $uploads_active,
		'uploads_size'		=> $uploads_size,
		'uploads_ext'		=> $uploads_ext,
		'enable_rss'		=> $enable_rss,
		'link_headline_fullstory' => $link_headline_fullstory,
		'flip_news'		=> $flip_news,
		'rss_title'		=> $rss_title,
		'rss_description'	=> $rss_description,
		'rss_encoding'		=> $rss_encoding,
		'com_validation'	=> $com_validation,
		'com_captcha'		=> $com_captcha,
		'news_pagination'	=> $news_pagination,
		'ppp_date'		=> $ppp_date,
		'news_pagination_arrows'=> $news_pagination_arrows,
		'news_pagination_numbers'=> $news_pagination_numbers,
		'news_pagination_prv'	=> $news_pagination_prv,
		'news_pagination_nxt'	=> $news_pagination_nxt,
		'comments_pages'	=> $comments_pages,
		'comments_per_page'	=> $comments_per_page,
        'use_wysiwyg'   => isset ($use_wysiwyg) ? $use_wysiwyg : 0,
        'stf_captcha'   => isset ($stf_captcha) ? $stf_captcha : 0,
	);
}

/**
 * Saves configuration settings to file.
 * @param array $configs Config data array
 */
function save_config ( $configs )
{
	require './config.php';

	// Replace ' with \'
	$find = '\'';
	$replace = '\\\'';
	$variables = array ('site', 'furl', 'hurl', 'datefor', 'skin', 'fslink', 'stflink', 'pclink',
				'rss_title', 'rss_description', 'rss_encoding', 'news_pagination_nxt', 'news_pagination_prv');
	foreach ( $variables as $config_var )
	{
		$configs[$config_var] = str_replace ($find, $replace, $configs[$config_var]);
	}
    
    // Override HTML setting if WYSIWYG is enabled.
    if ( $configs['use_wysiwyg'] )
    {
        $configs['ht'] = 1;
    }

	// Restrict values between specified ranges
	$variables = array (
		'numofposts' => array ('min' => 1),
		'numofh' => array ('min' => 1),
		'fullnewsw' => array ('min' => 100),
		'fullnewsh' => array ('min' => 100),
		'comheight' => array ('min' => 100),
		'comwidth' => array ('min' => 100),
		'stfwidth' => array ('min' => 100),
		'stfheight' => array ('min' => 100),
		'floodtime' => array ('min' => 1),
		'comlength' => array ('min' => 0),
		'comments_per_page' => array ('min' => 0),
        'uploads_size' => array ('min' => 1000)
	);
	foreach ( $variables as $config_var => $range )
	{
		if ( isset ($range['min']) && $configs[$config_var] < $range['min'] )
		{
			$configs[$config_var] = isset ($$config_var) ? $$config_var : $range['min'];
		}

		if ( isset ($range['max']) && $configs[$config_var] > $range['max'] )
		{
			$configs[$config_var] = isset ($$config_var) ? $$config_var : $range['max'];
		}
	}

	$save  = "<?php\n\n";
	$save .= '// Auto generated by Fusion News v' . FNEWS_CURVE . "\n\n";
	$save .= "\$fusion_id = '".$configs['fusion_id']."';\n";
	$save .= "\$site = '".$configs['site']."';\n";
	$save .= "\$furl = '".$configs['furl']."';\n";
	$save .= "\$hurl = '".$configs['hurl']."';\n";
	$save .= "\$datefor = '".$configs['datefor']."';\n";
	$save .= "\$numofposts = ".$configs['numofposts'].";\n";
	$save .= "\$numofh = ".$configs['numofh'].";\n";
	$save .= "\$bb = ".$configs['bb'].";\n";
	$save .= "\$ht = ".$configs['ht'].";\n";
	$save .= "\$post_per_day = ".$configs['post_per_day'].";\n";
	$save .= "\$wfpost = ".$configs['wfpost'].";\n";
	$save .= "\$wfcom = ".$configs['wfcom'].";\n";
	$save .= "\$skin = '".$configs['skin']."';\n";
	$save .= "\$smilies = ".$configs['smilies'].";\n";
	$save .= "\$stfpop = ".$configs['stfpop'].";\n";
	$save .= "\$comallowbr = ".$configs['comallowbr'].";\n";
	$save .= "\$stfwidth = ".$configs['stfwidth'].";\n";
	$save .= "\$stfheight = ".$configs['stfheight'].";\n";
	$save .= "\$fslink = '".$configs['fslink']."';\n";
	$save .= "\$stflink = '".$configs['stflink']."';\n";
	$save .= "\$pclink = '".$configs['pclink']."';\n";
	$save .= "\$fsnw = ".$configs['fsnw'].";\n";
	$save .= "\$cbflood = ".$configs['cbflood'].";\n";
	$save .= "\$floodtime = ".$configs['floodtime'].";\n";
	$save .= "\$comlength = ".$configs['comlength'].";\n";
	$save .= "\$fullnewsw = ".$configs['fullnewsw'].";\n";
	$save .= "\$fullnewsh = ".$configs['fullnewsh'].";\n";
	$save .= "\$fullnewss = ".$configs['fullnewss'].";\n";
	$save .= "\$stfresize = ".$configs['stfresize'].";\n";
	$save .= "\$stfscrolls = ".$configs['stfscrolls'].";\n";
	$save .= "\$fullnewsz = ".$configs['fullnewsz'].";\n";
	$save .= "\$htc = ".$configs['htc'].";\n";
	$save .= "\$smilcom = ".$configs['smilcom'].";\n";
	$save .= "\$bbc = ".$configs['bbc'].";\n";
	$save .= "\$compop = ".$configs['compop'].";\n";
	$save .= "\$comscrolls = ".$configs['comscrolls'].";\n";
	$save .= "\$comresize = ".$configs['comresize'].";\n";
	$save .= "\$comheight = ".$configs['comheight'].";\n";
	$save .= "\$comwidth = ".$configs['comwidth'].";\n";
	$save .= "\$uploads_active = ".$configs['uploads_active'].";\n";
	$save .= "\$uploads_size = ".$configs['uploads_size'].";\n";
	$save .= "\$uploads_ext = '".$configs['uploads_ext']."';\n";
	$save .= "\$enable_rss = ".$configs['enable_rss'].";\n";
	$save .= "\$link_headline_fullstory = ".$configs['link_headline_fullstory'].";\n";
	$save .= "\$flip_news = ".$configs['flip_news'].";\n";
	$save .= "\$rss_title = '" . $configs['rss_title'] . "';\n";
	$save .= "\$rss_description = '" . $configs['rss_description'] . "';\n";
	$save .= "\$rss_encoding = '" . $configs['rss_encoding'] . "';\n";
	$save .= '$com_validation = ' . $configs['com_validation'] . ';' . "\n";
	$save .= '$com_captcha = ' . $configs['com_captcha'] . ';' . "\n";
	$save .= '$news_pagination = ' . $configs['news_pagination'] . ';' . "\n";
	$save .= '$news_pagination_prv = \'' . $configs['news_pagination_prv'] . '\';' . "\n";
	$save .= '$news_pagination_nxt = \'' . $configs['news_pagination_nxt'] . '\';' . "\n";
	$save .= '$news_pagination_numbers = ' . $configs['news_pagination_numbers'] . ';' . "\n";
	$save .= '$news_pagination_arrows = ' . $configs['news_pagination_arrows'] . ';' . "\n";
	$save .= '$ppp_date = \'' . $configs['ppp_date'] . '\';' . "\n";
	$save .= '$comments_pages = ' . $configs['comments_pages'] . ';' . "\n";
	$save .= '$comments_per_page = ' . $configs['comments_per_page'] . ';' . "\n";
	$save .= '$use_wysiwyg = ' . $configs['use_wysiwyg'] . ';' . "\n";
	$save .= '$stf_captcha = ' . $configs['stf_captcha'] . ';' . "\n\n";
	$save .= '?' . '>';	// Split it up to prevent some editors from thinking it's a real PHP end tag.

	safe_write ('config.php', 'w', $save);
}

/**
 * Checks whether CAPTCHA code is correct for a given news article, and removes the code from database.
 * @param string $captcha_code 5 character CAPTCHA code
 * @param string $page_session_id User's session ID for the page
 * @param int $news_id News ID of the article
 * @param string $page Page the code applies to
 * @return bool True is the given code is correct, otherwise false.
 */
function is_valid_captcha_code ( $captcha_code, $page_session_id, $news_id, $page )
{
	global $error1;

	if ( empty ($page_session_id) || strlen ($captcha_code) != 5 )
	{
		return false;
	}

	$file = file (FNEWS_ROOT_PATH . 'sessions.php');
	array_shift ($file);

	$valid_code = false;
	$data = '<?php die (\'' . $error1 . '\'); ?>' . "\n";
	$current_time = time();
	$user_ip = get_ip();
	foreach ( $file as $value )
	{
		$session = get_line_data ('sessions', $value);

		if ( $page_session_id == $session['session_id'] && $session['page'] == $page )
		{
			if ( $captcha_code == $session['code'] &&
				$news_id == $session['news_id'] &&
				$session['ip'] == $user_ip &&
				($session['last_visit'] + 600 >= $current_time) )
			{
				$valid_code = true;
			}
		}
		else
		{
			if ( ($session['last_visit'] + 600) >= $current_time )
			{
				$data .= $value;
			}
		}
	}

	safe_write ('sessions.php', 'wb', $data);

	return $valid_code;
}

/**
 * Generates HTML to display smiley and BBCode buttons if enabled.
 * @param string $form_name Name of the form to which the buttons should add text to.
 * @param string $textbox_name Name of the textbox which should have text added to.
 * @param bool $show_smilies Whether or not to display smiley buttons
 * @param bool $show_bbcode Whether or not to display BBCode buttons
 * @return string HTML for displaying smiley and BBCode buttons
 */
function show_extras ( $form_name, $textbox_name, $show_smilies, $show_bbcode )
{
	global $furl;

	$extra_html = '';

	if ( $show_smilies )
	{
		$file = file (FNEWS_ROOT_PATH . 'smillies.php');
		array_shift ($file);
		foreach ( $file as $smiley )
		{
			$smiley = get_line_data ('smillies', $smiley);

			$text = addslashes ($smiley['bbcode']);
			$extra_html .= '<a href="javascript:smiley_bbcode(\'' . $textbox_name . '\', \'' . $text . '\');"><img src="' . $furl . '/smillies/' . $smiley['image'] . '" alt="' . $text . '" /></a>';
		}

		$extra_html .= '<br />' . "\n";
	}

	if ( $show_bbcode )
	{
		$extra_html .=
<<< html
<a href="javascript:smiley_bbcode('$textbox_name', '[b]', '[/b]');"><img src="{$furl}/img/bold.gif" alt="Bold" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[i]', '[/i]');"><img src="{$furl}/img/italic.gif" alt="Italic" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[u]', '[/u]');"><img src="{$furl}/img/underline.gif" alt="Underline" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[s]', '[/s]');"><img src="{$furl}/img/strike.gif" alt="Strikethrough" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[sub]', '[/sub]');"><img src="{$furl}/img/sub.gif" alt="Subscript" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[sup]', '[/sup]');"><img src="{$furl}/img/sup.gif" alt="Superscript" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[color=red]', '[/color]');"><img src="{$furl}/img/color.gif" alt="Font color" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[font=verdana]', '[/font]');"><img src="{$furl}/img/fontface.gif" alt="Font Family" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[size=16]', '[/size]');"><img src="{$furl}/img/fontsize.gif" alt="Font Size" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[align=left]', '[/align]');"><img src="{$furl}/img/fontleft.gif" alt="Left Align" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[align=center]', '[/align]');"><img src="{$furl}/img/center.gif" alt="Center Align" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[align=right]', '[/align]');"><img src="{$furl}/img/right.gif" alt="Right Align" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[tt]', '[/tt]');"><img src="{$furl}/img/tele.gif" alt="Teletype" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[hr]');"><img src="{$furl}/img/hr.gif" alt="Horizontal Line" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[move]', '[/move]');"><img src="{$furl}/img/move.gif" alt="Marquee" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[quote]', '[/quote]');"><img src="{$furl}/img/quote2.gif" alt="Quote" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[flash=200,200]', '[/flash]');"><img src="{$furl}/img/flash.gif" alt="Flash Image" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[img]', '[/img]');"><img src="{$furl}/img/img.gif" alt="Image" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[email=username@site.com]', '[/email]');"><img src="{$furl}/img/email2.gif" alt="E-mail link" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[url=http://www.url.com]', '[/url]');"><img src="{$furl}/img/url.gif" alt="hyperlink" /></a>
<a href="javascript:smiley_bbcode('$textbox_name', '[list]', '[/list]');"><img src="{$furl}/img/list.gif" alt="List" /></a><br />
html;
	}

	return $extra_html;
}

/**
 * Generates HTML for a category dropdown menu
 * @param string $user_login Login in name of user to determine what categories to show.
 * @param int $selected_category Preselected category ID.
 * @return string HTML for category drop down menu
 */
function build_category_dropdown ( $user_login = null, $selected_category = 0, $remove_selected = false )
{
    $file = file (FNEWS_ROOT_PATH . 'categories.php');
    array_shift ($file);
    
    $dropdown = '<select class="post" id="category" name="category">' . "\n";
    foreach ( $file as $category )
    {
        $category = get_line_data ('categories', $category);
        $cusers = explode (',', $category['users']);
        
        if ( $category['category_id'] != 1 && $user_login !== null && !in_array ($user_login, $cusers) )
        {
            continue;
        }
        
        $selected = '';
        if ( $selected_category == $category['category_id'] )
        {
            if ( $remove_selected )
            {
                continue;
            }
            
            $selected = ' selected="selected"';
        }
        
        $dropdown .= "<option value=\"{$category['category_id']}\"$selected>{$category['name']}</option>\n";
    }
    
    $dropdown .= "</select>\n";
    
    return $dropdown;
}

/**
 * Generates HTML for a category selection menu
 * @param string $user_login Login in name of user to determine what categories to show.
 * @param int|array $selected_categories Preselected category IDs. If only one category is selected, then a single integer can be given.
 * @param bool $invert_selected Whether or not to invert the selection.
 * @return string HTML for category selection menu.
 */
function build_category_selection ( $user_login = null, $selected_categories = array(1), $invert_selected = false )
{
    $file = file (FNEWS_ROOT_PATH . 'categories.php');
    array_shift ($file);
    
    if ( !is_array ($selected_categories) )
    {
        $selected_categories = array ($selected_categories);
    }
    
    ob_start();
    $line_break = '';
    foreach ( $file as $category )
    {
        $category = get_line_data ('categories', $category);
        $cusers = explode (',', $category['users']);
        
        if ( $category['category_id'] != 1 && $user_login !== null && !in_array ($user_login, $cusers) )
        {
            continue;
        }
        
        $id = $category['category_id'];
        $name = $category['name'];
        
        $selected = '';
        if ( in_array ($id, $selected_categories) != $invert_selected )
        {
            $selected = ' checked="checked"';
        }
        
        echo $line_break . "<input type=\"checkbox\" name=\"category[$id]\" value=\"$id\" id=\"category_$id\"$selected /> <label for=\"category_$id\">$name</label>";
        $line_break = '<br />';
    }
    
    return ob_get_clean();
}

/**
 * Generates HTML for an author selection menu
 * @param int|array $selected_authors Preselected author usernames. If only one author is selected, then a single username can be given.
 * @param bool $invert_selected Whether or not to invert the selection.
 * @return string HTML for author selection menu.
 */
function build_author_selection ( $selected_authors = array(1), $invert_selected = false )
{
    $file = file (FNEWS_ROOT_PATH . 'users.php');
    array_shift ($file);
    
    if ( !is_array ($selected_authors) )
    {
        $selected_authors = array ($selected_authors);
    }
    
    ob_start();
    $line_break = '';
    $i = 0;
    foreach ( $file as $author )
    {
        $author = get_line_data ('users', $author);
        
        $selected = '';
        
        $username = $author['username'];
        $nickname = $author['nickname'];
        
        if ( in_array ($username, $selected_authors) != $invert_selected )
        {
            $selected = ' checked="checked"';
        }
        
        echo $line_break . "<input type=\"checkbox\" name=\"author[$username]\" value=\"$username\" id=\"author_$i\"$selected /> <label for=\"author_$i\">$nickname</label>";
        $line_break = '<br />';
        
        ++$i;
    }
    
    return ob_get_clean();
}

/**
 * Checks if a given user is allowed to post in all given categories
 * @param string $user_login User's log in name to check
 * @param array $category_array Array of categories to check for access
 * @return mixed Returns the name of the first category which the user cannot post in. If there are
 * none, then NULL is returned
 */
function check_category_access ( $user_login, $category_array = array() )
{
	if ( sizeof ($category_array) > 0 )
	{
		$file = file (FNEWS_ROOT_PATH . 'categories.php');
		array_shift ($file);

		foreach ( $file as $category )
		{
			$category = get_line_data ('categories', $category);

			if ( $category['category_id'] == 1 )
			{
				continue;
			}

			if ( in_array ($category['category_id'], $category_array) )
			{
				$cusers = explode (',', $category['users']);
				if ( !in_array ($user_login, $cusers) )
				{
					return $category['name'];
				}
			}
		}
	}

	return NULL;
}

/**
 * Check if a given category ID exists
 * @param int $category_id Category ID to check that exists
 * @return bool Returns true if the given category ID exists, otherwise false.
 */
function category_exists ( $category_id = -1 )
{
	$category_id = (int)$category_id;

	$file = file (FNEWS_ROOT_PATH . 'categories.php');
	array_shift ($file);

	$found = false;
	foreach ( $file as $category )
	{
		$category = get_line_data ('categories', $category);
		if ( (int)$category['category_id'] === $category_id )
		{
			$found = true;
		}
	}

	return $found;
}

/**
 * Writes data to a specified file.
 * @param string $filename File name of file to write data to.
 * @param string $accessmode Mode of access.
 * @param string $data Data to be written to the file.
 */
function safe_write ( $filename, $accessmode, $data )
{
	global $ind17, $error2;

	if ( !($fp = @fopen (FNEWS_ROOT_PATH . $filename, $accessmode)) )
	{
		trigger_error (sprintf ($error2, $filename), E_USER_WARNING);
	}
    
    @flock ($fp, LOCK_EX);
    fputs ($fp, $data, strlen ($data));
    @flock ($fp, LOCK_UN);
    fclose ($fp);
}

/**
 * Generates HTML for use in checkboxes.
 * @param int $value The value to match against
 * @param int $match The value which $value must match to generate the HTML
 * @return string Returns HTML to select a checkbox if $value equals $match
 */
function checkbox_checked ( $value, $match = 1 )
{
	return $value == $match ? ' checked="checked"' : '';
}

/**
 * Formats the given message.
 * @param string $message Message to format
 * @param bool $allowHTML Allow HTML in message
 * @param bool $allowBBCode Allow BBCode in message
 * @param bool $allowSmileys Allow Smileys in message
 * @param bool $wordFilter Use the word filter on this message
 * @param bool $clearHTML Clear HTML completely from the message
 * @return string Formatted message
 */
function format_message ( $message, $allowHTML, $allowBBCode, $allowSmileys, $wordFilter, $clearHTML = false )
{
	if ( $wordFilter )
	{
		$message = filter_badwords ($message);
	}

    if ( $clearHTML )
    {
        $message = html_entity_decode ($message);
        $message = strip_tags ($message);
    }
	else if ( $allowHTML )
	{
		$message = html_entity_decode ($message);
	}

	if ( $allowBBCode )
	{
		$message = replace_bbcode ($message);
	}

	if ( $allowSmileys )
	{
		$message = replace_smileys ($message);
	}

	return $message;
}

/**
 * Parses news text or news data so that it is displayed along with its template.
 * @param string|array $news_string News text to parse, or the array from the required news file.
 * @param array $settings Override settings when parsing.
 * @return Parsed news text
 */
function parse_news_to_view ( $news_string, $settings = array() )
{
	assert (is_array ($settings));
	
	global $fsnw, $wfpost, $ht, $smilies, $bb, $stfpop, $compop,
		$furl, $fullnewsh, $fullnewsw, $fullnewss, $fullnewsz, $fslink, $datefor,
		$stflink, $stfheight, $stfwidth, $stfscrolls, $stfresize, $pclink, $datefor,
		$link_headline_fullstory, $hurl, $comheight, $comwidth, $comscrolls,
		$comresize;

	$news_text = array();

	if ( !empty ($news_string) )
	{
		$icon = '';
		$email = '';
		$writer = '';
		$link_full_news = '';
		$link_comments = '';
		$link_tell_friend = '';

		$article = $news_string;
		if ( !is_array ($news_string) )
		{
			$article = get_line_data ('news', $news_string);
		}

		// Get the template HTML
		$news_tmpl = get_template ((isset ($settings['template']) ? $settings['template'] : 'news_temp') . '.php', false);
		$other_qs = clean_query_string();
		
		$news_url = isset ($settings['news_url']) ? $settings['news_url'] : '';
		$sep = ( strpos ($news_url, '?') === false ) ? '?' : '&amp;';

		// Create the 'read more...' link
		if ( $article['fullnews'] != '' )
		{
			if ( $fsnw )
			{
				$link_full_news = '<a href="' . $furl . '/fullnews.php?fn_id=' . $article['news_id'] . '" onclick="window.open(this.href,\'\',\'height=' . $fullnewsh . ',width=' . $fullnewsw . ',toolbar=no,menubar=no,scrollbars=' . $fullnewss . ',resizable=' . $fullnewsz . '\'); return false">' . $fslink . '</a>';
			}
			else
			{
				$link_full_news = '<a href="' . $news_url . $sep . 'fn_mode=fullnews&amp;fn_id=' . $article['news_id'] . $other_qs . '">' . $fslink . '</a>';
			}
		}

		// Create the comments link
		if ( $compop )
		{
			$link_comments = '<a href="' . $furl . '/comments.php?fn_id=' . $article['news_id'] . '" onclick="window.open(this.href,\'\',\'height=' . $comheight . ',width=' . $comwidth . ',toolbar=no,menubar=no,scrollbars=' . $comscrolls . ',resizable=' . $comresize . '\'); return false">' . $pclink . '</a>';
		}
		else
		{
			$link_comments = '<a href="' . $news_url . $sep . 'fn_mode=comments&amp;fn_id=' . $article['news_id'] . $other_qs . '">' . $pclink . '</a>';
		}

		// Create the tell a friend link
		if ( $stfpop )
		{
			$link_tell_friend = '<a href="' . $furl . '/send.php?fn_id=' . $article['news_id'] . '" onclick="window.open(this.href,\'\',\'height=' . $stfheight . ',width=' . $stfwidth . ',toolbar=no,menubar=no,scrollbars=' . $stfscrolls . ',resizable=' . $stfresize . '\'); return false">' . $stflink . '</a>';
		}
		else
		{
			$link_tell_friend = '<a href="' . $news_url . $sep . 'fn_mode=send&amp;fn_id=' . $article['news_id'] . $other_qs . '">' . $stflink . '</a>';
		}

		// Make sure the number of comments is 0 or above.
		$num_comments = max ((int)$article['numcomments'], 0);

		// Get author information
		$author = get_author ($article['author']);
		if ( $author === false )
		{
			$author = array ('showemail' => false, 'nick' => $article['author']);
		}

		// Create the icon
		if ( strpos ($news_tmpl, '{icon}') !== false && !empty ($author['icon']) )
		{
			$icon = '<img src="' . $author['icon'] . '" alt="" />';
		}

		// Put the writer's name with his email as a link, or in some cases not.
		$email = ( $author['showemail'] ) ? $author['email'] : '';
		if ( !$email )
		{
			$writer = $author['nick'];
		}
		else
		{
			$writer = '<a href="mailto:' . $author['email'] . '">' . $author['nick'] . '</a>';
		}

		// Get our new lines back
        $article['shortnews'] = str_replace ('&br;', $ht ? '' : '<br />', $article['shortnews']);
        $article['fullnews'] = str_replace ('&br;', $ht ? '' : '<br />', $article['fullnews']);

		$article['headline'] = format_message ($article['headline'], $ht, $bb, $smilies, $wfpost);
		$article['shortnews'] = format_message ($article['shortnews'], $ht, $bb, $smilies, $wfpost);
		$article['fullnews'] = format_message ($article['fullnews'], $ht, $bb, $smilies, $wfpost);

		$file = file (FNEWS_ROOT_PATH . 'categories.php');
		array_shift ($file);
		$categories = explode (',', $article['categories']);
		$cat_icon = '';
		$cat_id = 0;
		$cat_name = '';
		
		$category_filter = isset ($settings['category']) ? $settings['category'] : array();
		$num_category_filter = sizeof ($category_filter);
		
		foreach ( $file as $category )
		{
			$category = get_line_data ('categories', $category);

			if ( ($num_category_filter > 0 && in_array ($category['category_id'], $category_filter)) ||
				($num_category_filter == 0 && in_array ($category['category_id'], $categories)) )
			{
				$cat_icon = $category['icon'] != '' ? '<img src="' . $category['icon'] . '" alt="" />' : '';
				$cat_id = $category['category_id'];
				$cat_name = $category['name'];
				break;
			}
		}

		$news_text = array (
			'post_id'		=> $article['news_id'],
			'link_tell_friend'=> $link_tell_friend,
			'link_full_news'	=> $link_full_news,
			'subject'		=> $article['headline'],
			'description'	=> $article['description'],
			'writer'		=> $writer,
			'email'		=> $email,
			'date'		=> date ($datefor, (int)$article['timestamp']),
			'icon'		=> $icon,
			'news'		=> $article['shortnews'],
			'fullnews'		=> $article['fullnews'],
			'cat_icon'		=> $cat_icon,
			'cat_id'		=> $cat_id,
			'cat_name'		=> $cat_name,
		);

		if ( strpos ($news_tmpl, '{comments}') !== false )
		{
			$news_text += array (
				'nrc'			=> $num_comments,
				'link_comments'	=> $link_comments,
			);
		}
		else
		{
			$news_text += array ('nrc' => '', 'link_comments' => '');
		}

		// Replace in the values!
		$news_tmpl = replace_masks ($news_tmpl, array (
			'post_id'		=> $news_text['post_id'],
			'user'		=> $news_text['writer'],
			'date'		=> $news_text['date'],
			'icon'		=> $news_text['icon'],
			'send'		=> $news_text['link_tell_friend'],
			'nrc'			=> $news_text['nrc'],
			'cat_id'		=> $news_text['cat_id'],
			'cat_name'		=> $news_text['cat_name'],
			'cat_icon'		=> $news_text['cat_icon'],
			'fullstory'		=> $news_text['link_full_news'],
			'comments'		=> $news_text['link_comments'],
			'subject'		=> '<a id="fus_' . $news_text['post_id'] . '"></a>' . $news_text['subject'],
			'news'		=> $news_text['news'],
			'description'	=> $news_text['description']
		));

		$news_text += array ('display' => $news_tmpl);
	}

	return $news_text;
}

/**
 * Checks and returns the number of comments awaiting to be validated.
 * @return int Number of comments awaiting to be validated.
 */
function get_pending_comments()
{
	global $com_validation;
	if ( !$com_validation )
	{
		return 0;
	}

	$count = 0;

	$file = get_ordered_toc();
	foreach ( $file as $value )
	{
		$toc = get_line_data ('news_toc', $value);
		if ( !file_exists (FNEWS_ROOT_PATH . 'news/news.' . $toc['news_id'] . '.php') )
		{
			continue;
		}

		$news_file = file (FNEWS_ROOT_PATH . 'news/news.' . $toc['news_id'] . '.php');
        if ( sizeof ($news_file) <= 2 )
        {
            continue;
        }
        
		array_shift ($news_file);
		array_shift ($news_file);

		foreach ( $news_file as $value2 )
		{
			$comment = get_line_data ('comments', $value2);
			if ( $comment['validated'] == 0 )
			{
				++$count;
			}
		}
	}

	return $count;
}

function get_validated_comments_for ( $news_id )
{
    global $com_validation;

    $news_file = file (FNEWS_ROOT_PATH . 'news/news.' . $news_id . '.php');
    array_shift ($news_file);
    array_shift ($news_file);
    
    $validated_comments = array();
    foreach ( $news_file as $comment )
    {
        $comment = get_line_data ('comments', $comment);
        if ( $comment['validated'] )
        {
            $validated_comments[] = $comment;
        }
    }
    
    return $validated_comments;
}

// PHP 4.3.2 compatability
if ( !function_exists ('session_regenerate_id') )
{
	/**
	 * Regenerates the internal (PHP) session id
	 * @return bool True is successful, otherwise false.
	 */
	function session_regenerate_id()
	{
		$str = '';
		mt_srand ((double)microtime() * 100000);
		for ( $i = 0; $i < 32; $i++ )
		{
			$x = mt_rand (1, 3);
			$str .= ($x == 1) ? chr (mt_rand (48, 57)) : (( $x == 2 ) ? chr (mt_rand (65, 90)) : chr (mt_rand (97, 122)));
		}

		if ( session_id ($str) )
		{
			return true;
		}
		else
		{
			return false;
		}
	}
}

/**
 * Login session functions
 */

/**
 * Creates a pseudo-random string of alphanumeric characters of a specified length.
 * This function is shared by the installer too to create the login identifier
 * @param int $length Length of the pseudo-random string
 * @return string Pseudo-random string
 */
function create_security_id ( $length = 32 )
{
	$str = '';
	mt_srand ((double)microtime() * 100000);
	for ( $i = 0; $i < $length; $i++ )
	{
		$x = mt_rand (1, 3);
		$str .= ($x == 1) ? chr (mt_rand (48, 57)) : (( $x == 2 ) ? chr (mt_rand (65, 90)) : chr (mt_rand (97, 122)));
	}

	return $str;
}

/**
 * Creates a login session for the given user log in name.
 * @param string $uid Log in name of the user logging in
 * @param int $autologin Whether or not the user wishes to auto log in next time he/she visits the page
 * @return array User data array for the newly logged in user.
 */
function login_session_create ( $uid, $autologin = 0 )
{
	$file = file (FNEWS_ROOT_PATH . 'logins.php');
	$write = array_shift ($file);

	$user_ip = get_ip();
	$current_time = time();
	foreach ( $file as $login_data )
	{
		$login = get_line_data ('logins', $login_data);

		if ( $login['user_id'] == $uid && $login['autologin'] != 1 )
		{
			// Purge old existing security id
			continue;
		}

		if ( $current_time <= ($login['login_time'] + 1800) )
		{
			$write .= $login_data;
		}
	}

	$security_id = create_security_id();

	$write .= $security_id . '|<|' . $uid . '|<|' . $user_ip . '|<|' . $autologin . '|<|' . $current_time . '|<|' . "\n";

	safe_write ('logins.php', 'wb', $write);

	setcookie ('fus_uid', $uid, $current_time + (365 * 86400));
	setcookie ('fus_sid', $security_id, $current_time + (365 * 86400));
	
    $userfile = file (FNEWS_ROOT_PATH . 'users.php');
    array_shift ($userfile);

    $userdata = array();
    foreach ( $userfile as $userinfo )
    {
        $user = get_line_data ('users', $userinfo);

        if ( $user['username'] == $uid )
        {
            $email = explode ('=', $user['email']);
            $userdata = array (
                'user'  => $user['username'],
                'nick'  => $user['nickname'],
                'showemail' => $email[0],
                'email' => $email[1],
                'icon'  => $user['icon'],
                'offset'    => (int)$user['timeoffset'],
                'password'  => $user['passwordhash'],
                'level' => (int)$user['level']
            );
            
            break;
        }
    }
    
    return $userdata;
}

/**
 * Updates the user's log in session time, and removes old log in sessions from the data file
 * @param string $uid User log in name of the user logged in.
 * @param string $sid Session log in ID for the user
 * @return array If an invalid $uid or $sid is given, a blank array, otherwise the data for the
 * logged in user.
 */
function login_session_update ( $uid, $sid )
{
	if ( !$uid || !$sid )
	{
		return array();
	}

	$file = file (FNEWS_ROOT_PATH . 'logins.php');
	$write = array_shift ($file);
	
	$userfile = file (FNEWS_ROOT_PATH . 'users.php');
    array_shift ($userfile);

	$valid_sid = false;
	$userdata = NULL;
	$current_time = time();
	$user_ip = get_ip();
	foreach ( $file as $login_data )
	{
		$login = get_line_data ('logins', $login_data);

		if ( ($current_time >= ($login['login_time'] + 1800)) && $login['autologin'] != 1 )
		{
			continue;
		}

		if ( $login['security_id'] != $sid )
		{
			$write .= $login_data;
			continue;
		}

		if ( ($user_ip != $login['ip']) || ($uid != $login['user_id']) )
		{
			continue;
		}

		foreach ( $userfile as $userinfo )
		{
			$user = get_line_data ('users', $userinfo);

			if ( $user['username'] == $login['user_id'] )
			{
				$valid_sid = true;

				$email = explode ('=', $user['email']);
				$userdata = array (
					'user'	=> $user['username'],
					'nick'	=> $user['nickname'],
					'showemail'	=> $email[0],
					'email'	=> $email[1],
					'icon'	=> $user['icon'],
					'offset'	=> (int)$user['timeoffset'],
					'password'	=> $user['passwordhash'],
					'level'	=> (int)$user['level']
				);

				$write .= $login['security_id'] . '|<|' . $login['user_id'] . '|<|' . $login['ip'] . '|<|' . $login['autologin'] . '|<|' . $current_time . '|<|' . "\n";
				break;
			}
		}
	}

	safe_write ('logins.php', 'wb', $write);

	if ( !$valid_sid || $userdata === NULL )
	{
		setcookie ('fus_sid', '', $current_time - 86400);
		setcookie ('fus_uid', '', $current_time - 86400);
	}

	return $userdata;
}

/**
 * Destroy the log in session for the given log in session ID and removes
 * old log in data from the data file
 * @param string $sid Log in session ID to destroy
 */
function login_session_destroy ( $sid )
{

	$file = file (FNEWS_ROOT_PATH . 'logins.php');
	$write = array_shift ($file);

	$valid_sid = false;
	$current_time = time();
	foreach ( $file as $login_data )
	{
		$login = get_line_data ('logins', $login_data);

		if ( ($current_time >= ($login['login_time'] + 1800)) && $login['autologin'] != 1 )
		{
			continue;
		}

		if ( $login['security_id'] == $sid )
		{
			continue;
		}

		$write .= $login_data;
	}

	safe_write ('logins.php', 'wb', $write);
}

/**
 * Retrieves the file extension from given file.
 * @param string $filename Filename to get extension from
 * @return string Returns the file's extension
 */
function get_file_extension ( $filename )
{
    return strtolower (substr ($filename, strrpos ($filename, '.') + 1));
}

/**
 * Uploads an image to the directory in $directory.
 * @param int $file_number The ID number of the file in the $_FILES['F']['xxx'] array. If -1, then only one file was uploaded.
 * @param string $allowedExts The allowed file extensions to be uploaded, separated by HTML encoded |.
 * @param string $directory The directory to upload the file to.
 * @return string Message showing whether the upload was successful or not.
 * @todo Make this function more generalized. I don't like the beginning if() statement
 * which could be solved by passing a custom array instead of specifying a file number.
 * Also the returned messages need to be turned into return codes.
 */
function upload_file ( $file_number, $allowedExts, $directory = './uploads/' )
{
	global $ind252, $ind254, $ind255, $ind255a, $ind256, $ind257;

	if ( $file_number == -1 )
	{
		// We only have one file uploaded...
		if ( $_FILES['F']['error'] != UPLOAD_ERR_OK )
		{
			// Problem with the upload. Let's take a closer look
			switch ( $_FILES['F']['error'] )
			{
				case UPLOAD_ERR_INI_SIZE:
				case UPLOAD_ERR_FORM_SIZE:
					return sprintf ($ind252, $_FILES['F']['name']);
				break;

				case UPLOAD_ERR_PARTIAL:
				break;

				case UPLOAD_ERR_NO_FILE:
					return $ind254;
				break;

				default:
					return 'Uh-oh, this isn\'t supposed to happen. Error code: ' . $_FILES['F']['error'];
				break;
			}
		}

		$filename = ( isset ($_FILES['F']['name']) ) ? $_FILES['F']['name'] : '';
		$tmpname = ( isset ($_FILES['F']['tmp_name']) ) ? $_FILES['F']['tmp_name'] : '';
	}
	else
	{
		if ( $_FILES['F']['error'][$file_number] != UPLOAD_ERR_OK )
		{
			// Problem with the upload. Let's take a closer look
			switch ( $_FILES['F']['error'][$file_number] )
			{
				case UPLOAD_ERR_INI_SIZE:
				case UPLOAD_ERR_FORM_SIZE:
					return sprintf ($ind252, $_FILES['F']['name'][$file_number]);
				break;

				case UPLOAD_ERR_PARTIAL:
				break;

				case UPLOAD_ERR_NO_FILE:
					return $ind254;
				break;

				default:
					return 'Uh-oh, this isn\'t supposed to happen.';
				break;
			}
		}

		$filename = ( isset ($_FILES['F']['name'][$file_number]) ) ? $_FILES['F']['name'][$file_number] : '';
		$tmpname = ( isset ($_FILES['F']['tmp_name'][$file_number]) ) ? $_FILES['F']['tmp_name'][$file_number] : '';
	}

	$extensions = explode ('|', $allowedExts);
	$num_exts = sizeof ($extensions);
	$valid_ext = false;

	foreach ( $extensions as $ext )
	{
		if ( get_file_extension ($filename) == strtolower ($ext) )
		{
			$valid_ext = true;
			break;
		}
	}

	if ( !$valid_ext )
	{
		return $ind255 . $allowedExts . $ind255a;
	}

	$uploaded = false;

	$origname = $filename;
	$i = 1;

	while ( file_exists ($directory . $filename) )
	{
		$filename = substr ($origname, 0, strrpos ($origname, '.')) . '_' . $i . strrchr ($origname, '.');
		$i++;
	}

	if ( @move_uploaded_file ($tmpname, $directory . $filename) )
	{
		$uploaded = true;
	}
	else if ( @copy ($tmpname, $directory . $filename) )
	{
		$uploaded = true;
	}

	if ( !$uploaded )
	{
		return $ind256;
	}

	chmod ($directory . $filename, 0644);
	if ( file_exists ($tmpname) )
	{
		unlink ($tmpname);
	}

	return $filename . ' ' . $ind257;
}

/**
 * Generates HTML for a redirect page
 * @param string $message Message to display before the user is redirected
 * @param string $return_url URL to return to
 * @param string $return_text Text to display to return to the given URL
 * @return string HTML to display the redirect page
 */
function make_redirect ( $message, $return_url = '', $return_text = '' )
{
	global $ind76;

	$text = '<p>' . $message . '</p>';
	if ( $return_url && $return_text )
	{
		$text .= '<p><a href="' . $return_url . '">' . $return_text . '</a></p>';
	}
	$text .= '<p><a href="./">' . $ind76 . '</a></p>';

	return $text;
}

/**
 * Failsafe method of retrieving $_SERVER['QUERY_STRING']
 * @return string Query string
 */
function get_query_string()
{
	return (isset ($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '');
}

/**
 * Gets query string, removing any Fusion News added variables.
 * @return string Clean string query (without any Fusion News added variables)
 */
function clean_query_string()
{
	$query_string = get_query_string();
	$query_string = preg_replace ('/fn_[a-z]+=[0-9a-z]+&?/', '', $query_string);
	$query_string = str_replace ('&', '&amp;', $query_string);

	// Clear possible leading ampersand
	if ( substr ($query_string, -5) == '&amp;' )
	{
		$query_string = substr ($query_string, 0, -5);
	}

	if ( empty ($query_string) )
	{
		return '';
	}
	else
	{
		return '&amp;' . $query_string;
	}
}

/**
 * Generates HTML for the form security
 * @return string HTML for the form security
 */
function get_form_security()
{
	$timestamp = time();

	return '<input type="hidden" name="post_form" value="' . get_form_character ($timestamp) . '" />' . "\n" .
			'<input type="hidden" name="post_time" value="' . $timestamp . '" />' . "\n";
}

/**
 * Gets the form's security character
 * @param int $timestamp Timestamp for the form
 * @return string Form's security character
 */
function get_form_character ( $timestamp )
{
	global $fusion_id;

	$total = 0;
	$time = (string)$timestamp;
	for ( $i = 0, $end = strlen ($time); $i < $end; $i++ )
	{
		$total += $i * $time{$i};
	}

	return $fusion_id{0x1F ^ ($total % 32)};
}

/**
 * Checks whether the given form character is valid
 * @return bool True if the given form character is valid, otherwise false.
 */
function check_form_character()
{
	global $VARS;

	if ( !isset ($VARS['post_time']) || !isset ($VARS['post_form']) )
	{
		return false;
	}

	if ( $VARS['post_time'] == '' || $VARS['post_form'] == '' )
	{
		return false;
	}

	if ( ($VARS['post_time'] + 3600) <= time() )
	{
		// Allow a maximum of one hour to submit a form.
		return false;
	}

	return (get_form_character ($VARS['post_time']) == $VARS['post_form']);
}

/**
 * Creates a list of page numbers, reducing the list if
 * the page list is too long to show.
 * @param int $num_pages Number of pages
 * @param int $current_page The current page number
 * @param string $url URL of the page to go to with the selected page number
 * @param string $page_variable Variable to use in the query string for the page number
 * @return string The list of page numbers.
 */
function create_page_numbers ( $num_pages, $current_page, $url, $page_variable )
{
	static $page_reduction_limit = 15;
	$pagination_text = '';

	// Replace intitial ampersand just in case we have a query string created by clean_query_string().
	$url = str_replace ('?&amp;', '?', $url);

	$i = 1;

	$should_reduce = ($num_pages >= $page_reduction_limit);
	$prev_page_no = $current_page - 1;
	$next_page_no = $current_page + 1;
	$two_from_last = $num_pages - 2;
	while ( $i <= $num_pages )
	{
		if ( !$should_reduce ||
			$i <= 3 ||
			($i >= $prev_page_no && $i <= $next_page_no) ||
			$i >= $two_from_last )
		{
			if ( $current_page == $i )
			{
				$pagination_text .= ' <b>' . $i . '</b>';
			}
			else
			{
				$pagination_text .= ' <a href="' . $url . '&amp;' . $page_variable . '=' . $i . '">' . $i . '</a>';
			}

			++$i;
		}
		else
		{
			$pagination_text .= ' &#133;';

			if ( $i < $prev_page_no && $prev_page_no < $two_from_last )
			{
				$i = $prev_page_no;
			}
			else if ( $i < $two_from_last )
			{
				$i = $two_from_last;
			}
		}
	}

	// substr to remove leading space.
	return substr ($pagination_text, 1);
}

/**
 * Parses field masks in given text
 * @param string $template Text containing field masks to replace
 * @param array $masks Array of masks (key contains field mask, value contains text to replace the mask with)
 * @return string Text with field masks parsed.
 */
function replace_masks ( $template, $masks )
{
	foreach ( $masks as $key => $value )
	{
		$template = str_replace ('{' . $key . '}', $value, $template);
	}

	return $template;
}

if ( !function_exists ('array_combine') )
{
	/**
	 * This function exists in PHP5 by default.
	 * Creates an array by using one array for keys and another for its values
	 * @param array $keys Array of keys to be used.
	 * @param array $values Array of values to be used
	 * @return array|bool Returns the combined array, FALSE if the number of elements for each array isn't equal or if the arrays are empty.
	 */
	function array_combine ( $keys, $values )
	{
		$num_keys = sizeof ($keys);
		$num_values = sizeof ($values);

		if ( $num_keys != $num_values )
		{
			trigger_error ('array_combine(): Both parameters should have an equal number of elements.', E_USER_WARNING);
			return false;
		}

		$return = array();
		for ( $i = 0; $i < $num_keys; $i++ )
		{
			$return[$keys[$i]] = $values[$i];
		}

		return $return;
	}
}

function current_url()
{
    $url = 'http';
    if ( $_SERVER['SERVER_PORT'] == 443 )
    {
        $url .= 's';
    }
    
    $url .= '://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
    
    return $url;
}

/**
 */
function generate_captcha_code ( $session_id, $news_id, $user_ip, $type )
{
    $captcha_code = '';
	for ( $i = 0; $i < 5; $i++ )
	{
		$x = mt_rand (1, 10);
		$captcha_code .= ( $x % 2 ) ? chr (mt_rand (48, 57)) : chr (mt_rand (65, 90));
	}
    
    save_captcha_code ($session_id, $captcha_code, $news_id, $user_ip, $type);
    
    return $captcha_code;
}

function get_captcha_code ( $session_id )
{
    $file = file (FNEWS_ROOT_PATH . 'sessions.php');
	array_shift ($file);

	foreach ( $file as $value )
	{
		$session = get_line_data ('sessions', $value);

		if ( $session['session_id'] == $session_id )
		{
			return $session['code'];
		}
	}

	return null;
}

function save_captcha_code ( $session_id, $captcha_code, $news_id, $user_ip, $type )
{
    global $error1;

    $file = file (FNEWS_ROOT_PATH . 'sessions.php');
	array_shift ($file);

	$current_time = time();
	$data = '<?php die (\'' . $error1 . '\'); ?>' . "\n";
	foreach ( $file as $value )
	{
		$session = get_line_data ('sessions', $value);

		if ( $session['session_id'] == $session_id )
		{
			continue;
		}

		if ( (($session['last_visit'] + 600) >= $current_time) && ($session['ip'] != $user_ip) )
		{
			$data .= $value;
		}
	}

	$data .= create_line_data ('sessions', true, $session_id, $captcha_code, $news_id, $user_ip, $current_time, $type);
	safe_write ('sessions.php', 'wb', $data);
}

/**
 * @param string $file File to get fields for.
 * @return array List of fields for file type.
 */
function get_fields_for_file ( $file )
{
    static $valid_files = array (
        'badwords'      => array ('find', 'replace', 'case_sensitive', 'type'),
        'categories'    => array ('category_id', 'name', 'icon', 'users'),
        'comments'      => array ('ip', 'validated', 'message', 'author', 'email', 'timestamp', 'comment_id'),
        'flood'         => array ('ip', 'timestamp'),
        'logins'        => array ('security_id', 'user_id', 'ip', 'autologin', 'login_time'),
        'news_toc'      => array ('news_id', 'timestamp', 'author', 'headline', 'categories'),
        'news'          => array ('shortnews', 'fullnews', 'author', 'headline', 'description', 'categories', 'timestamp', 'numcomments', 'news_id'),
        'sessions'      => array ('session_id', 'code', 'news_id', 'ip', 'last_visit', 'page'),
        'smillies'      => array ('smiley_id', 'bbcode', 'image'),
        'users'         => array ('username', 'nickname', 'email', 'icon', 'timeoffset', 'passwordhash', 'level')
    );

    if ( !array_key_exists ($file, $valid_files) )
    {
        trigger_error ('get_line_data(): Invalid data file name given', E_USER_WARNING);
	}
    
    return $valid_files[$file];
}

/**
 * Creates a line of data for specified file.
 * @param string $file File type to create data for.
 * @param bool $trailing_eol Whether or not to append \n to end of line
 * @param string $data Data to use
 * @param string Line of data for specified file
 */
function create_line_data ( $file, $trailing_eol, $data )
{
    $data = func_get_args();
    array_shift ($data); // $file
    array_shift ($data); // $trailing_eol
    
    $fields = get_fields_for_file ($file);
    if ( sizeof ($fields) != sizeof ($data) )
    {
        trigger_error ('create_line_data(): The number of fields given does not much the number of fields required for file "' . $file . '"');
    }
    
    return implode ('|<|', $data) . '|<|' . ($trailing_eol ? "\n" : '');
}

/**
 * Gets an array of fields and their data from a specified line of data from a file.
 * @param string $file Data file the line of data was retrieved from
 * @param string $line_data Line of data to convert to an array
 * @param string $delimiter The delimiter between each field data
 * @return array|bool Array combining the field names for the specified file and the given data,
 * FALSE if no data was found or the line data was blank.
 */
function get_line_data ( $file, $line_data, $delimiter = '|<|' )
{
	if ( $line_data == '' )
	{
		trigger_error ('get_line_data(): No line data for ' . $file, E_USER_WARNING);
	}

	$data = explode ($delimiter, $line_data);
	if ( sizeof ($data) < 0 )
	{
		trigger_error ('get_line_data(): No data found in the given data.', E_USER_WARNING);
		return NULL;
	}

    $fields = get_fields_for_file ($file);
    
	array_pop ($data); // Pop new line off the end
	$return_data = array_combine ($fields, $data);

	return $return_data;
}

/**
 * Prepares a message for email
 * @param string $string String to prepare
 * @return string Prepared message for email.
 */
function prepare_string_for_mail ( $string )
{
    $message = wordwrap ($string, 70);
    
    return $message;
}

/**
 * Displays the output of the control panel.
 * @param string $title Page title
 * @param string $skin Skin to use
 * @param array $userdata User's login session data
 */
function display_output ( $title, $skin, $userdata )
{
	global $start_time,
		$ind163, $ind108, $ind109, $ind344, $ind169, $ind272, $ind165,
		$ind107, $ind281, $ind193, $ind194, $ind195, $ind170, $ind171,
        $ind400, $notice_buffer, $warning_buffer, $ind358, $ind357,
        $errored_out;

	// Now sort out the skin
	$links_list = array (
		array ($ind163, '', GUEST), // home
		array ($ind108, '?id=postnews', NEWS_REPORTER), // new post
		array ($ind109, '?id=editposts', NEWS_REPORTER), // edit posts
		array ($ind400, '?id=editprofile', NEWS_REPORTER), // edit profile
		array (array (
            NEWS_EDITOR => $ind344,
            NEWS_ADMIN => $ind169),
        '?id=admin', NEWS_EDITOR), // editor's panel/admin
		array ($ind272, '?id=view', GUEST), // view news
		array ($ind165, '?id=help', NEWS_REPORTER), // help/update
		array ($ind107, '?id=logout', NEWS_REPORTER) // logout
	);
	
	$cs1 = file_get_contents (FNEWS_ROOT_PATH . 'skins/' . $skin . '/index.html');
	if ( $cs1 === false )
	{
		trigger_error ($ind281, E_USER_ERROR);
	}

	$row_links = '';
	$col_links = '';
    
    $row_sep = '';
    $col_sep = '';
    
	$user_level = ( !isset ($userdata['level']) ) ? 0 : $userdata['level'];
    
	foreach ( $links_list as $link_data )
	{
		if ( !is_array ($link_data) )
		{
			continue;
		}

		if ( $user_level >= $link_data[2] )
		{
			$row_links .= $row_sep;
			$col_links .= $col_sep;

			$row_links .= '<a href="index.php' . $link_data[1] . '">';
			$col_links .= '<a href="index.php' . $link_data[1] . '">';
			if ( is_array ($link_data[0]) )
			{
				$row_links .= $link_data[0][$userdata['level']];
				$col_links .= $link_data[0][$userdata['level']];
			}
			else
			{
				$row_links .= $link_data[0];
				$col_links .= $link_data[0];
			}
			$row_links .= '</a>';
			$col_links .= '</a>';
            
            $row_sep = ' | ';
            $col_sep = '<br />';
		}
	}
    
	if ( has_access (NEWS_REPORTER) )
	{
		switch ( $userdata['level'] )
		{
			case 3:
				$status = $ind195;
				break;

			case 2:
				$status = $ind194;
				break;

			case 1:
				$status = $ind193;
				break;

			default:
				break;
		}

		$login = $ind170 . ' <b>' . $userdata['nick'] . '</b> [<b>' . $status . '</b>]';
	}
	else
	{
		$login = $ind171;
	}
    
    $content = ob_get_clean();

	if ( !$errored_out )
	{
		if ( $notice_buffer != '' )
		{
			$content = '<ul id="fn_notice"><li class="title">' . $ind357 . '</li>' . $notice_buffer . '</ul>' . $content;
		}

		if ( $warning_buffer != '' )
		{
			$content = '<ul id="fn_warning"><li class="title">' . $ind358 . '</li>' . $warning_buffer . '</ul>' . $content;
		}
	}

	$cs = replace_masks ($cs1, array (
		'main'  => $content,
		'title' => $title,
		'linksn'=> $row_links,
		'linksb'=> $col_links,
		'login' => $login,
		'curve' => FNEWS_CURVE
	));

	//-----------------------------------------------
	// Do this very last to get the most accurate
	// result possible
	//-----------------------------------------------
	$split = explode (' ', microtime());
	$end_time = (float)$split[0] + (float)$split[1];
	$cs = str_replace ('{loadtime}', sprintf ('%.6f', $end_time - $start_time), $cs);

	//-----------------------------------------------
	// Blammo, out comes the end product :p
	//-----------------------------------------------
	echo $cs;
}

/**
 * Error handling
 */
$warning_buffer = '';
$notice_buffer = '';
/**
 * When TRUE the page should stop wherever it is in processing, and just display the error messages
 * @global bool $errored_out
 */
$errored_out = false;

/**
 * Callback function for PHP error handling (not to be used directly - it will be called by PHP when needed)
 * @param int $errno Error number
 * @param string $errstr Error text
 * @param string $errfile File containing the error
 * @param int $errline Line number containing the error
 * @return bool False if the default PHP internal error handler should handle the error
 */
function fn_error_handler ( $errno, $errstr, $errfile, $errline )
{
	if ( !(error_reporting() & $errno) )
	{
		return true;
	}

	$errfile = str_replace (FNEWS_ROOT_PATH, '', str_replace ('\\', '/', $errfile));

	switch ( $errno )
	{
		// Very bad error indeed...
		// Show a complete failure page.
		case E_USER_ERROR:
		case E_ERROR:
            ob_end_clean();
			echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
				'<html xmlns="http://www.w3.org/1999/xhtml">',
				'<head>',
                '	<meta http-equiv="content-type" content="text/html; charset=utf-8" />',
				'	<title>Fusion News &bull; Error</title>',
				'	<style type="text/css">',
				'	<!--',
				'	body { background-color:#fff; color:#000; line-height:140%; font-size:100%; font-family:"Trebuchet MS", Helvetica, sans-serif }',
				'	blockquote { padding:0; margin: 0 30px }',
				'	#wrapper { width:95%; margin:0 auto }',
				'	//-->',
				'	</style>',
				'</head>',
				'<body>',
				'<h1>Fusion News has encountered a fatal error</h1>',
				'<div id="wrapper">',
				'<p>A fatal error was encountered by Fusion News, and cannot continue to run.</p>',
				'<p>The error message is as follows:</p>',
				'<blockquote><i>', $errstr, '</i></blockquote>',
				'<p>If there are any instructions in the error message above, please follow them to try to solve the problem. If the error repeats itself, after refreshing the page after 30 seconds, please create a new topic at the <a href="http://www.fusionnews.net/">Fusion News Support Forum</a>, and copy and paste the text below:</p>',
				'<blockquote><code>Error: ', $errstr, '<br />',
                'File: ', $errfile, '<br />',
                'Line No.: ', $errline, '<br />',
                'Version: ', FNEWS_CURVE,
                '</code></blockquote>',
				'</div>',
				'</body>',
				'</html>';

			exit;

			return true;
		break;

		case E_USER_NOTICE:
		case E_USER_WARNING:
            global $title, $ind17, $skin, $userdata;
			if ( !$title )
			{
				$title = $ind17;
			}

			echo '<div id="fn_warning">',
					'<li class="title">' . $ind17 . '</li>',
					'<li>' . $errstr . '</li>',
					'</div>', "\n";

			$errored_out = true;

			display_output ($title, $skin, $userdata);
			exit;

			return true;
		break;

		case E_NOTICE:
            global $notice_buffer;
            
			$notice_buffer .= '<li> ' . $errstr . ' in /' . $errfile . ' on line ' . $errline . '</li>' . "\n";

			return true;
		break;

		case E_WARNING:
            global $warning_buffer;
            
			$warning_buffer .= '<li>' . $errstr . ' in /' . $errfile . ' on line ' . $errline . '</li>' . "\n";

			return true;
		break;

		default:
		break;
	}

	return true;
}

?>