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/moodle_esf_vz/auth/mnet
/srv/http/vyvoj.adent.cz/vyvoj/moodle_esf_vz/auth/mnet/
Upload File:
Current File : /srv/http/vyvoj.adent.cz/vyvoj/moodle_esf_vz/auth/mnet/auth.php
<?php // $Id: auth.php,v 1.14.2.12 2007/08/06 22:15:19 stronk7 Exp $

/**
 * @author Martin Dougiamas
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
 * @package moodle multiauth
 *
 * Authentication Plugin: Moodle Network Authentication
 *
 * Multiple host authentication support for Moodle Network.
 *
 * 2006-11-01  File created.
 */

if (!defined('MOODLE_INTERNAL')) {
    die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
}

require_once($CFG->libdir.'/authlib.php');

/**
 * Moodle Network authentication plugin.
 */
class auth_plugin_mnet extends auth_plugin_base {

    /**
     * Constructor.
     */
    function auth_plugin_mnet() {
        $this->authtype = 'mnet';
        $this->config = get_config('auth/mnet');
    }

    /**
     * Provides the allowed RPC services from this class as an array.
     * @return array  Allowed RPC services.
     */
    function mnet_publishes() {

        $sso_idp = array();
        $sso_idp['name']        = 'sso_idp'; // Name & Description go in lang file
        $sso_idp['apiversion']  = 1;
        $sso_idp['methods']     = array('user_authorise','keepalive_server', 'kill_children',
                                        'refresh_log', 'fetch_user_image', 'fetch_theme_info',
                                        'update_enrolments');

        $sso_sp = array();
        $sso_sp['name']         = 'sso_sp'; // Name & Description go in lang file
        $sso_sp['apiversion']   = 1;
        $sso_sp['methods']      = array('keepalive_client','kill_child');

        return array($sso_idp, $sso_sp);
    }

    /**
     * This function is normally used to determine if the username and password
     * are correct for local logins. Always returns false, as local users do not
     * need to login over mnet xmlrpc.
     *
     * @param string $username The username
     * @param string $password The password
     * @return bool Authentication success or failure.
     */
    function user_login($username, $password) {
        return false; // error("Remote MNET users cannot login locally.");
    }

    /**
     * Return user data for the provided token, compare with user_agent string.
     *
     * @param  string $token    The unique ID provided by remotehost.
     * @param  string $UA       User Agent string.
     * @return array  $userdata Array of user info for remote host
     */
    function user_authorise($token, $useragent) {
        global $CFG, $MNET, $SITE, $MNET_REMOTE_CLIENT;
        require_once $CFG->dirroot . '/mnet/xmlrpc/server.php';

        $mnet_session = get_record('mnet_session', 'token', $token, 'useragent', $useragent);
        if (empty($mnet_session)) {
            echo mnet_server_fault(1, get_string('authfail_nosessionexists', 'mnet'));
            exit;
        }

        // check session confirm timeout
        if ($mnet_session->confirm_timeout < time()) {
            echo mnet_server_fault(2, get_string('authfail_sessiontimedout', 'mnet'));
            exit;
        }

        // session okay, try getting the user
        if (!$user = get_complete_user_data('id', $mnet_session->userid)) {
            echo mnet_server_fault(3, get_string('authfail_usermismatch', 'mnet'));
            exit;
        }

        $userdata = array();
        $userdata['username']                = $user->username;
        $userdata['email']                   = $user->email;
        $userdata['auth']                    = 'mnet';
        $userdata['confirmed']               = $user->confirmed;
        $userdata['deleted']                 = $user->deleted;
        $userdata['firstname']               = $user->firstname;
        $userdata['lastname']                = $user->lastname;
        $userdata['city']                    = $user->city;
        $userdata['country']                 = $user->country;
        $userdata['lang']                    = $user->lang;
        $userdata['timezone']                = $user->timezone;
        $userdata['description']             = $user->description;
        $userdata['mailformat']              = $user->mailformat;
        $userdata['maildigest']              = $user->maildigest;
        $userdata['maildisplay']             = $user->maildisplay;
        $userdata['htmleditor']              = $user->htmleditor;
        $userdata['wwwroot']                 = $MNET->wwwroot;
        $userdata['session.gc_maxlifetime']  = ini_get('session.gc_maxlifetime');
        $userdata['picture']                 = $user->picture;
        if (!empty($user->picture)) {
            $imagefile = "{$CFG->dataroot}/users/{$user->id}/f1.jpg";
            if (file_exists($imagefile)) {
                $userdata['imagehash'] = sha1(file_get_contents($imagefile));
            }
        }

        $userdata['myhosts'] = array();
        if($courses = get_my_courses($user->id, 'id', 'id, visible')) {
            $userdata['myhosts'][] = array('name'=> $SITE->shortname, 'url' => $CFG->wwwroot, 'count' => count($courses));
        }

        $sql = "
                SELECT
                    h.name as hostname,
                    h.wwwroot,
                    h.id as hostid,
                    count(c.id) as count
                FROM
                    {$CFG->prefix}mnet_enrol_course c,
                    {$CFG->prefix}mnet_enrol_assignments a,
                    {$CFG->prefix}mnet_host h
                WHERE
                    c.id      =  a.courseid   AND
                    c.hostid  =  h.id         AND
                    a.userid  = '{$user->id}' AND
                    c.hostid != '{$MNET_REMOTE_CLIENT->id}'
                GROUP BY
                    h.name,
                    h.id,
                    h.wwwroot";
        if ($courses = get_records_sql($sql)) {
            foreach($courses as $course) {
                $userdata['myhosts'][] = array('name'=> $course->hostname, 'url' => $CFG->wwwroot.'/auth/mnet/jump.php?hostid='.$course->hostid, 'count' => $course->count);
            }
        }

        return $userdata;
    }

    /**
     * Generate a random string for use as an RPC session token.
     */
    function generate_token() {
        return sha1(str_shuffle('' . mt_rand() . time()));
    }

    /**
     * Starts an RPC jump session and returns the jump redirect URL.
     */
    function start_jump_session($mnethostid, $wantsurl) {
        global $CFG;
        global $USER;
        global $MNET;
        require_once $CFG->dirroot . '/mnet/xmlrpc/client.php';

        // check remote login permissions
        if (! has_capability('moodle/site:mnetlogintoremote', get_context_instance(CONTEXT_SYSTEM, SITEID))
                or is_mnet_remote_user($USER)
                or $USER->username == 'guest'
                or empty($USER->id)) {
            error(get_string('notpermittedtojump', 'mnet'));
        }

        // check for SSO publish permission first
        if ($this->has_service($mnethostid, 'sso_sp') == false) {
            error(get_string('hostnotconfiguredforsso', 'mnet'));
        }

        // set RPC timeout to 30 seconds if not configured
        // TODO: Is this needed/useful/problematic?
        if (empty($this->config->rpc_negotiation_timeout)) {
            set_config('rpc_negotiation_timeout', '30', 'auth/mnet');
        }

        // get the host info
        $mnet_peer = new mnet_peer();
        $mnet_peer->set_id($mnethostid);

        // set up the session
        $mnet_session = get_record('mnet_session',
                                   'userid',     $USER->id,
                                   'mnethostid', $mnethostid,
                                   'useragent',  sha1($_SERVER['HTTP_USER_AGENT']));
        if ($mnet_session == false) {
            $mnet_session = new object();
            $mnet_session->mnethostid = $mnethostid;
            $mnet_session->userid = $USER->id;
            $mnet_session->username = $USER->username;
            $mnet_session->useragent = sha1($_SERVER['HTTP_USER_AGENT']);
            $mnet_session->token = $this->generate_token();
            $mnet_session->confirm_timeout = time() + $this->config->rpc_negotiation_timeout;
            $mnet_session->expires = time() + (integer)ini_get('session.gc_maxlifetime');
            $mnet_session->session_id = session_id();
            if (! $mnet_session->id = insert_record('mnet_session', addslashes_object($mnet_session))) {
                error(get_string('databaseerror', 'mnet'));
            }
        } else {
            $mnet_session->useragent = sha1($_SERVER['HTTP_USER_AGENT']);
            $mnet_session->token = $this->generate_token();
            $mnet_session->confirm_timeout = time() + $this->config->rpc_negotiation_timeout;
            $mnet_session->expires = time() + (integer)ini_get('session.gc_maxlifetime');
            $mnet_session->session_id = session_id();
            if (false == update_record('mnet_session', addslashes_object($mnet_session))) {
                error(get_string('databaseerror', 'mnet'));
            }
        }

        // construct the redirection URL
        //$transport = mnet_get_protocol($mnet_peer->transport);
        $wantsurl = urlencode($wantsurl);
        $url = "{$mnet_peer->wwwroot}/auth/mnet/land.php?token={$mnet_session->token}&idp={$MNET->wwwroot}&wantsurl={$wantsurl}";

        return $url;
    }

    /**
     * This function confirms the remote (ID provider) host's mnet session
     * by communicating the token and UA over the XMLRPC transport layer, and
     * returns the local user record on success.
     *
     *   @param string $token           The random session token.
     *   @param string $remotewwwroot   The ID provider wwwroot.
     *   @return array The local user record.
     */
    function confirm_mnet_session($token, $remotewwwroot) {
        global $CFG, $MNET, $SESSION;
        require_once $CFG->dirroot . '/mnet/xmlrpc/client.php';

        // verify the remote host is configured locally before attempting RPC call
        if (! $remotehost = get_record('mnet_host', 'wwwroot', $remotewwwroot)) {
            error(get_string('notpermittedtoland', 'mnet'));
        }

        // get the originating (ID provider) host info
        $remotepeer = new mnet_peer();
        $remotepeer->set_wwwroot($remotewwwroot);

        // set up the RPC request
        $mnetrequest = new mnet_xmlrpc_client();
        $mnetrequest->set_method('auth/mnet/auth.php/user_authorise');

        // set $token and $useragent parameters
        $mnetrequest->add_param($token);
        $mnetrequest->add_param(sha1($_SERVER['HTTP_USER_AGENT']));

        // Thunderbirds are go! Do RPC call and store response
        if ($mnetrequest->send($remotepeer) === true) {
            $remoteuser = (object) $mnetrequest->response;
        } else {
            foreach ($mnetrequest->error as $errormessage) {
                list($code, $message) = array_map('trim',explode(':', $errormessage, 2));
                if($code == 702) {
                    $site = get_site();
                    print_error('mnet_session_prohibited','mnet', $remotewwwroot, format_string($site->fullname));
                    exit;
                }
                $message .= "ERROR $code:<br/>$errormessage<br/>";
            }
            error("RPC auth/mnet/user_authorise:<br/>$message");
        }
        unset($mnetrequest);

        if (empty($remoteuser) or empty($remoteuser->username)) {
            print_error('unknownerror', 'mnet');
            exit;
        }

        $firsttime = false;

        // get the local record for the remote user
        $localuser = get_record('user', 'username', addslashes($remoteuser->username), 'mnethostid', $remotehost->id);

        // add the remote user to the database if necessary, and if allowed
        // TODO: refactor into a separate function
        if (! $localuser->id) {
            if (empty($this->config->auto_add_remote_users)) {
                error(get_string('nolocaluser', 'mnet'));
            }
            $remoteuser->mnethostid = $remotehost->id;
            if (! insert_record('user', addslashes_object($remoteuser))) {
                error(get_string('databaseerror', 'mnet'));
            }
            $firsttime = true;
            if (! $localuser = get_record('user', 'username', addslashes($remoteuser->username), 'mnethostid', $remotehost->id)) {
                error(get_string('nolocaluser', 'mnet'));
            }
        }

        // check sso access control list for permission first
        if (!$this->can_login_remotely($localuser->username, $remotehost->id)) {
            print_error('sso_mnet_login_refused', 'mnet', '', array($localuser->username, $remotehost->name));
        }

        $session_gc_maxlifetime = 1440;

        // update the local user record with remote user data
        foreach ((array) $remoteuser as $key => $val) {
            if ($key == 'session.gc_maxlifetime') {
                $session_gc_maxlifetime = $val;
                continue;
            }

            // TODO: fetch image if it has changed
            if ($key == 'imagehash') {
                $dirname = "{$CFG->dataroot}/users/{$localuser->id}";
                $filename = "$dirname/f1.jpg";

                $localhash = '';
                if (file_exists($filename)) {
                    $localhash = sha1(file_get_contents($filename));
                } elseif (!file_exists($dirname)) {
                    mkdir($dirname);
                }

                if ($localhash != $val) {
                    // fetch image from remote host
                    $fetchrequest = new mnet_xmlrpc_client();
                    $fetchrequest->set_method('auth/mnet/auth.php/fetch_user_image');
                    $fetchrequest->add_param($localuser->username);
                    if ($fetchrequest->send($remotepeer) === true) {
                        if (strlen($fetchrequest->response['f1']) > 0) {
                            $imagecontents = base64_decode($fetchrequest->response['f1']);
                            file_put_contents($filename, $imagecontents);
                        }
                        if (strlen($fetchrequest->response['f2']) > 0) {
                            $imagecontents = base64_decode($fetchrequest->response['f2']);
                            file_put_contents($dirname.'/f2.jpg', $imagecontents);
                        }
                    }
                }
            }

            if($key == 'myhosts') {
                $localuser->mnet_foreign_host_array = array();
                foreach($val as $rhost) {
                    $name  = clean_param($rhost['name'], PARAM_ALPHANUM);
                    $url   = clean_param($rhost['url'], PARAM_URL);
                    $count = clean_param($rhost['count'], PARAM_INT);
                    $url_is_local = stristr($url , $CFG->wwwroot);
                    if (!empty($name) && !empty($count) && empty($url_is_local)) {
                        $localuser->mnet_foreign_host_array[] = array('name'  => $name,
                                                                      'url'   => $url,
                                                                      'count' => $count);
                    }
                }
            }

            $localuser->{$key} = $val;
        }

        $localuser->mnethostid = $remotepeer->id;

        $bool = update_record('user', addslashes_object($localuser));
        if (!$bool) {
            // TODO: Jonathan to clean up mess
            // Actually, this should never happen (modulo race conditions) - ML
            error("updating user failed in mnet/auth/confirm_mnet_session ");
        }

        // set up the session
        $mnet_session = get_record('mnet_session',
                                   'userid',     $localuser->id,
                                   'mnethostid', $remotepeer->id,
                                   'useragent',  sha1($_SERVER['HTTP_USER_AGENT']));
        if ($mnet_session == false) {
            $mnet_session = new object();
            $mnet_session->mnethostid = $remotepeer->id;
            $mnet_session->userid = $localuser->id;
            $mnet_session->username = $localuser->username;
            $mnet_session->useragent = sha1($_SERVER['HTTP_USER_AGENT']);
            $mnet_session->token = $token; // Needed to support simultaneous sessions
                                           // and preserving DB rec uniqueness
            $mnet_session->confirm_timeout = time();
            $mnet_session->expires = time() + (integer)$session_gc_maxlifetime;
            $mnet_session->session_id = session_id();
            if (! $mnet_session->id = insert_record('mnet_session', addslashes_object($mnet_session))) {
                error(get_string('databaseerror', 'mnet'));
            }
        } else {
            $mnet_session->expires = time() + (integer)$session_gc_maxlifetime;
            update_record('mnet_session', addslashes_object($mnet_session));
        }

        if (!$firsttime) {
            // repeat customer! let the IDP know about enrolments
            // we have for this user.
            // set up the RPC request
            $mnetrequest = new mnet_xmlrpc_client();
            $mnetrequest->set_method('auth/mnet/auth.php/update_enrolments');

            // pass username and an assoc array of "my courses"
            // with info so that the IDP can maintain mnet_enrol_assignments
            $mnetrequest->add_param($remoteuser->username);
            $fields = 'id, category, sortorder, fullname, shortname, idnumber, summary,
                       startdate, cost, currency, defaultrole, visible';
            $courses = get_my_courses($localuser->id, 'visible DESC,sortorder ASC', $fields);
            if (is_array($courses) && !empty($courses)) {
                // Second request to do the JOINs that we'd have done
                // inside get_my_courses() if we had been allowed
                $sql = "SELECT c.id,
                               cc.name AS cat_name, cc.description AS cat_description,
                               r.shortname as defaultrolename
                        FROM {$CFG->prefix}course c
                          JOIN {$CFG->prefix}course_categories cc ON c.category = cc.id
                          LEFT OUTER JOIN {$CFG->prefix}role r  ON c.defaultrole = r.id
                        WHERE c.id IN (" . join(',',array_keys($courses)) . ')';
                $extra = get_records_sql($sql);

                $keys = array_keys($courses);
                $defaultrolename = get_field('role', 'shortname', 'id', $CFG->defaultcourseroleid);
                foreach ($keys AS $id) {
                    if ($courses[$id]->visible == 0) {
                        unset($courses[$id]);
                        continue;
                    }
                    $courses[$id]->cat_id          = $courses[$id]->category;
                    $courses[$id]->defaultroleid   = $courses[$id]->defaultrole;
                    unset($courses[$id]->category);
                    unset($courses[$id]->defaultrole);
                    unset($courses[$id]->visible);

                    $courses[$id]->cat_name        = $extra[$id]->cat_name;
                    $courses[$id]->cat_description = $extra[$id]->cat_description;
                    if (!empty($extra[$id]->defaultrolename)) {
                        $courses[$id]->defaultrolename = $extra[$id]->defaultrolename;
                    } else {
                        $courses[$id]->defaultrolename = $defaultrolename;
                    }
                    // coerce to array
                    $courses[$id] = (array)$courses[$id];
                }
            } else {
                // if the array is empty, send it anyway
                // we may be clearing out stale entries
                $courses = array();
            }
            $mnetrequest->add_param($courses);

            // Call 0800-RPC Now! -- we don't care too much if it fails
            // as it's just informational.
            if ($mnetrequest->send($remotepeer) === false) {
                // error_log(print_r($mnetrequest->error,1));
            }
        }

        return $localuser;
    }

    /**
     * Invoke this function _on_ the IDP to update it with enrolment info local to
     * the SP right after calling user_authorise()
     *
     * Normally called by the SP after calling
     *
     *   @param string $username        The username
     *   @param string $courses         Assoc array of courses following the structure of mnet_enrol_course
     *   @return bool
     */
    function update_enrolments($username, $courses) {
        global $MNET_REMOTE_CLIENT, $CFG;

        if (empty($username) || !is_array($courses)) {
            return false;
        }
        // make sure it is a user we have an in active session
        // with that host...
        $userid = get_field('mnet_session', 'userid',
                            'username', addslashes($username),
                            'mnethostid', (int)$MNET_REMOTE_CLIENT->id);
        if (!$userid) {
            return false;
        }

        if (empty($courses)) { // no courses? clear out quickly
            delete_records('mnet_enrol_assignments',
                           'hostid', (int)$MNET_REMOTE_CLIENT->id,
                           'userid', $userid);
            return true;
        }

        // IMPORTANT: Ask for remoteid as the first element in the query, so
        // that the array that comes back is indexed on the same field as the
        // array that we have received from the remote client
        $sql = '
                SELECT
                    c.remoteid,
                    c.id,
                    c.cat_id,
                    c.cat_name,
                    c.cat_description,
                    c.sortorder,
                    c.fullname,
                    c.shortname,
                    c.idnumber,
                    c.summary,
                    c.startdate,
                    c.cost,
                    c.currency,
                    c.defaultroleid,
                    c.defaultrolename,
                    a.id as assignmentid
                FROM
                    '.$CFG->prefix.'mnet_enrol_course c
                LEFT JOIN
                    '.$CFG->prefix.'mnet_enrol_assignments a
                ON
                   (a.courseid = c.id AND
                    a.hostid   = c.hostid AND
                    a.userid = \''.$userid.'\')
                WHERE
                    c.hostid = \''.(int)$MNET_REMOTE_CLIENT->id.'\'';

        $currentcourses = get_records_sql($sql);

        $local_courseid_array = array();
        foreach($courses as $course) {

            $course['remoteid'] = $course['id'];
            $course['hostid']   =  (int)$MNET_REMOTE_CLIENT->id;
            $userisregd         = false;

            // First up - do we have a record for this course?
            if (!array_key_exists($course['remoteid'], $currentcourses)) {
                // No record - we must create it
                $course['id']  =  insert_record('mnet_enrol_course', addslashes_object((object)$course));
                $currentcourse = (object)$course;
            } else {
                // Pointer to current course:
                $currentcourse =& $currentcourses[$course['remoteid']];
                // We have a record - is it up-to-date?
                $course['id'] = $currentcourse->id;

                $saveflag = false;

                foreach($course as $key => $value) {
                    if ($currentcourse->$key != $value) {
                        $saveflag = true;
                        $currentcourse->$key = $value;
                    }
                }

                if ($saveflag) {
                    update_record('mnet_enrol_course', addslashes_object($currentcourse));
                }

                if (isset($currentcourse->assignmentid) && is_numeric($currentcourse->assignmentid)) {
                    $userisregd = true;
                }
            }

            // By this point, we should always have a $dataObj->id
            $local_courseid_array[] = $course['id'];

            // Do we have a record for this assignment?
            if ($userisregd) {
                // Yes - we know about this one already
                // We don't want to do updates because the new data is probably
                // 'less complete' than the data we have.
            } else {
                // No - create a record
                $assignObj = new stdClass();
                $assignObj->userid    = $userid;
                $assignObj->hostid    = (int)$MNET_REMOTE_CLIENT->id;
                $assignObj->courseid  = $course['id'];
                $assignObj->rolename  = $course['defaultrolename'];
                $assignObj->id = insert_record('mnet_enrol_assignments', addslashes_object($assignObj));
            }
        }

        // Clean up courses that the user is no longer enrolled in.
        $local_courseid_string = implode(', ', $local_courseid_array);
        $whereclause = " userid = '$userid' AND hostid = '{$MNET_REMOTE_CLIENT->id}' AND courseid NOT IN ($local_courseid_string)";
        delete_records_select('mnet_enrol_assignments', $whereclause);
    }

    /**
     * Returns true if this authentication plugin is 'internal'.
     *
     * @return bool
     */
    function is_internal() {
        return false;
    }

    /**
     * Returns true if this authentication plugin can change the user's
     * password.
     *
     * @return bool
     */
    function can_change_password() {
        //TODO: it should be able to redirect, right?
        return false;
    }

    /**
     * Returns the URL for changing the user's pw, or false if the default can
     * be used.
     *
     * @return string
     */
    function change_password_url() {
        return '';
    }

    /**
     * Prints a form for configuring this authentication plugin.
     *
     * This function is called from admin/auth.php, and outputs a full page with
     * a form for configuring this plugin.
     *
     * @param array $page An object containing all the data for this page.
     */
    function config_form($config, $err, $user_fields) {
        global $CFG;

         $query = "
            SELECT
                h.id,
                h.name as hostname,
                h.wwwroot,
                h2idp.publish as idppublish,
                h2idp.subscribe as idpsubscribe,
                idp.name as idpname,
                h2sp.publish as sppublish,
                h2sp.subscribe as spsubscribe,
                sp.name as spname
            FROM
                {$CFG->prefix}mnet_host h
            LEFT JOIN
                {$CFG->prefix}mnet_host2service h2idp
            ON
               (h.id = h2idp.hostid AND
               (h2idp.publish = 1 OR
                h2idp.subscribe = 1))
            INNER JOIN
                {$CFG->prefix}mnet_service idp
            ON
               (h2idp.serviceid = idp.id AND
                idp.name = 'sso_idp')
            LEFT JOIN
                {$CFG->prefix}mnet_host2service h2sp
            ON
               (h.id = h2sp.hostid AND
               (h2sp.publish = 1 OR
                h2sp.subscribe = 1))
            INNER JOIN
                {$CFG->prefix}mnet_service sp
            ON
               (h2sp.serviceid = sp.id AND
                sp.name = 'sso_sp')
            WHERE
               ((h2idp.publish = 1 AND h2sp.subscribe = 1) OR
               (h2sp.publish = 1 AND h2idp.subscribe = 1)) AND
                h.id != {$CFG->mnet_localhost_id}
            ORDER BY
                h.name ASC";

        $id_providers       = array();
        $service_providers  = array();
        if ($resultset = get_records_sql($query)) {
            foreach($resultset as $hostservice) {
                if(!empty($hostservice->idppublish) && !empty($hostservice->spsubscribe)) {
                    $service_providers[]= array('id' => $hostservice->id, 'name' => $hostservice->hostname, 'wwwroot' => $hostservice->wwwroot);
                }
                if(!empty($hostservice->idpsubscribe) && !empty($hostservice->sppublish)) {
                    $id_providers[]= array('id' => $hostservice->id, 'name' => $hostservice->hostname, 'wwwroot' => $hostservice->wwwroot);
                }
            }
        }

        include "config.html";
    }

    /**
     * Processes and stores configuration data for this authentication plugin.
     */
    function process_config($config) {
        // set to defaults if undefined
        if (!isset ($config->rpc_negotiation_timeout)) {
            $config->rpc_negotiation_timeout = '30';
        }
        if (!isset ($config->auto_add_remote_users)) {
            $config->auto_add_remote_users = '0';
        }

        // save settings
        set_config('rpc_negotiation_timeout', $config->rpc_negotiation_timeout, 'auth/mnet');
        set_config('auto_add_remote_users',   $config->auto_add_remote_users,   'auth/mnet');

        return true;
    }

    /**
     * Poll the IdP server to let it know that a user it has authenticated is still
     * online
     *
     * @return  void
     */
    function keepalive_client() {
        global $CFG, $MNET;
        $cutoff = time() - 300; // TODO - find out what the remote server's session
                                // cutoff is, and preempt that

        $sql = "
            select
                id,
                username,
                mnethostid
            from
                {$CFG->prefix}user
            where
                lastaccess > '$cutoff' AND
                mnethostid != '{$CFG->mnet_localhost_id}'
            order by
                mnethostid";

        $immigrants = get_records_sql($sql);

        if ($immigrants == false) {
            return true;
        }

        $usersArray = array();
        foreach($immigrants as $immigrant) {
            $usersArray[$immigrant->mnethostid][] = $immigrant->username;
        }

        require_once $CFG->dirroot . '/mnet/xmlrpc/client.php';
        foreach($usersArray as $mnethostid => $users) {
            $mnet_peer = new mnet_peer();
            $mnet_peer->set_id($mnethostid);

            $mnet_request = new mnet_xmlrpc_client();
            $mnet_request->set_method('auth/mnet/auth.php/keepalive_server');

            // set $token and $useragent parameters
            $mnet_request->add_param($users);

            if ($mnet_request->send($mnet_peer) === true) {
                if (!isset($mnet_request->response['code'])) {
                    debugging("Server side error has occured on host $mnethostid");
                    continue;
                } elseif ($mnet_request->response['code'] > 0) {
                    debugging($mnet_request->response['message']);
                }

                if (!isset($mnet_request->response['last log id'])) {
                    debugging("Server side error has occured on host $mnethostid\nNo log ID was received.");
                    continue;
                }
            } else {
                debugging("Server side error has occured on host $mnethostid: " .
                          join("\n", $mnet_request->error));
                break;
            }

            $query = "SELECT
                          l.id as remoteid,
                          l.time,
                          l.userid,
                          l.ip,
                          l.course,
                          l.module,
                          l.cmid,
                          l.action,
                          l.url,
                          l.info,
                          c.fullname as coursename,
                          c.modinfo as modinfo,
                          u.username
                      FROM
                          {$CFG->prefix}user u,
                          {$CFG->prefix}log l,
                          {$CFG->prefix}course c
                      WHERE
                          l.userid = u.id AND
                          u.mnethostid = '$mnethostid' AND
                          l.id > '".$mnet_request->response['last log id']."' AND
                          c.id = l.course
                      ORDER BY
                          remoteid ASC";

            $results = get_records_sql($query);

            if (false == $results) continue;

            $param = array();

            foreach($results as $result) {
                if (!empty($result->modinfo) && !empty($result->cmid)) {
                    $modinfo = unserialize($result->modinfo);
                    unset($result->modinfo);
                    $modulearray = array();
                    foreach($modinfo as $module) {
                        $modulearray[$module->cm] = urldecode($module->name);
                    }
                    $result->resource_name = $modulearray[$result->cmid];
                } else {
                    $result->resource_name = '';
                }

                $param[] = array (
                                    'remoteid'      => $result->remoteid,
                                    'time'          => $result->time,
                                    'userid'        => $result->userid,
                                    'ip'            => $result->ip,
                                    'course'        => $result->course,
                                    'coursename'    => $result->coursename,
                                    'module'        => $result->module,
                                    'cmid'          => $result->cmid,
                                    'action'        => $result->action,
                                    'url'           => $result->url,
                                    'info'          => $result->info,
                                    'resource_name' => $result->resource_name,
                                    'username'      => $result->username
                                 );
            }

            unset($result);

            $mnet_request = new mnet_xmlrpc_client();
            $mnet_request->set_method('auth/mnet/auth.php/refresh_log');

            // set $token and $useragent parameters
            $mnet_request->add_param($param);

            if ($mnet_request->send($mnet_peer) === true) {
                if ($mnet_request->response['code'] > 0) {
                    debugging($mnet_request->response['message']);
                }
            } else {
                debugging("Server side error has occured on host $mnet_peer->ip: " .join("\n", $mnet_request->error));
            }
        }
    }

    /**
     * Receives an array of log entries from an SP and adds them to the mnet_log
     * table
     *
     * @param   array   $array      An array of usernames
     * @return  string              "All ok" or an error message
     */
    function refresh_log($array) {
        global $CFG, $MNET_REMOTE_CLIENT;

        // We don't want to output anything to the client machine
        $start = ob_start();

        $returnString = '';
        begin_sql();
        $useridarray = array();

        foreach($array as $logEntry) {
            $logEntryObj = (object)$logEntry;
            $logEntryObj->hostid = $MNET_REMOTE_CLIENT->id;

            if (isset($useridarray[$logEntryObj->username])) {
                $logEntryObj->userid = $useridarray[$logEntryObj->username];
            } else {
                $logEntryObj->userid = get_field('user','id','username',$logEntryObj->username);
                if ($logEntryObj->userid == false) {
                    $logEntryObj->userid = 0;
                }
                $useridarray[$logEntryObj->username] = $logEntryObj->userid;
            }

            unset($logEntryObj->username);

            $insertok = insert_record('mnet_log', addslashes_object($logEntryObj), false);

            if ($insertok) {
                $MNET_REMOTE_CLIENT->last_log_id = $logEntryObj->remoteid;
            } else {
                $returnString .= 'Record with id '.$logEntryObj->remoteid." failed to insert.\n";
            }
        }
        $MNET_REMOTE_CLIENT->commit();
        commit_sql();

        $end = ob_end_clean();

        if (empty($returnString)) return array('code' => 0, 'message' => 'All ok');
        return array('code' => 1, 'message' => $returnString);
    }

    /**
     * Receives an array of usernames from a remote machine and prods their
     * sessions to keep them alive
     *
     * @param   array   $array      An array of usernames
     * @return  string              "All ok" or an error message
     */
    function keepalive_server($array) {
        global $MNET_REMOTE_CLIENT, $CFG;

        $CFG->usesid = true;
        // Addslashes to all usernames, so we can build the query string real
        // simply with 'implode'
        $array = array_map('addslashes', $array);

        // We don't want to output anything to the client machine
        $start = ob_start();

        // We'll get session records in batches of 30
        $superArray = array_chunk($array, 30);

        $returnString = '';

        foreach($superArray as $subArray) {
            $subArray = array_values($subArray);
            $instring = "('".implode("', '",$subArray)."')";
            $query = "select id, session_id, username from {$CFG->prefix}mnet_session where username in $instring";
            $results = get_records_sql($query);

            if ($results == false) {
                // We seem to have a username that breaks our query:
                // TODO: Handle this error appropriately
                $returnString .= "We failed to refresh the session for the following usernames: \n".implode("\n", $subArray)."\n\n";
            } else {
                // TODO: This process of killing and re-starting the session
                // will cause PHP to forget any custom session_set_save_handler
                // stuff. Subsequent attempts to prod existing sessions will
                // fail, because PHP will look in wherever the default place
                // may be (files?) and probably create a new session with the
                // right session ID in that location. If it doesn't have write-
                // access to that location, then it will fail... not sure how
                // apparent that will be.
                // There is no way to capture what the custom session handler
                // is and then reset it on each pass - I checked that out
                // already.
                $sesscache = clone($_SESSION);
                $sessidcache = session_id();
                session_write_close();
                unset($_SESSION);

                $uc = ini_get('session.use_cookies');
                ini_set('session.use_cookies', false);
                foreach($results as $emigrant) {

                    unset($_SESSION);
                    session_name('MoodleSession'.$CFG->sessioncookie);
                    session_id($emigrant->session_id);
                    session_start();
                    session_write_close();
                }

                ini_set('session.use_cookies', $uc);
                session_name('MoodleSession'.$CFG->sessioncookie);
                session_id($sessidcache);
                session_start();
                $_SESSION = clone($sesscache);
                session_write_close();
            }
        }

        $end = ob_end_clean();

        if (empty($returnString)) return array('code' => 0, 'message' => 'All ok', 'last log id' => $MNET_REMOTE_CLIENT->last_log_id);
        return array('code' => 1, 'message' => $returnString, 'last log id' => $MNET_REMOTE_CLIENT->last_log_id);
    }

    /**
     * Cron function will be called automatically by cron.php every 5 minutes
     *
     * @return void
     */
    function cron() {

        // run the keepalive client
        $this->keepalive_client();

        // admin/cron.php should have run srand for us
        $random100 = rand(0,100);
        if ($random100 < 10) {     // Approximately 10% of the time.
            // nuke olden sessions
            $longtime = time() - (1 * 3600 * 24);
            delete_records_select('mnet_session', "expires < $longtime");
        }
    }

    /**
     * Cleanup any remote mnet_sessions, kill the local mnet_session data
     *
     * This is called by require_logout in moodlelib
     *
     * @return   void
     */
    function prelogout_hook() {
        global $MNET, $CFG, $USER;
        if (!is_enabled_auth('mnet')) {
            return;
        }

        require_once $CFG->dirroot.'/mnet/xmlrpc/client.php';

        // If the user is local to this Moodle:
        if ($USER->mnethostid == $MNET->id) {
            $this->kill_children($USER->username, sha1($_SERVER['HTTP_USER_AGENT']));

        // Else the user has hit 'logout' at a Service Provider Moodle:
        } else {
            $this->kill_parent($USER->username, sha1($_SERVER['HTTP_USER_AGENT']));

        }
    }

    /**
     * The SP uses this function to kill the session on the parent IdP
     *
     * @param   string  $username       Username for session to kill
     * @param   string  $useragent      SHA1 hash of user agent to look for
     * @return  string                  A plaintext report of what has happened
     */
    function kill_parent($username, $useragent) {
        global $CFG, $USER;
        require_once $CFG->dirroot.'/mnet/xmlrpc/client.php';
        $sql = "
            select
                *
            from
                {$CFG->prefix}mnet_session s
            where
                s.username   = '".addslashes($username)."' AND
                s.useragent  = '$useragent' AND
                s.mnethostid = '{$USER->mnethostid}'";

        $mnetsessions = get_records_sql($sql);

        $ignore = delete_records('mnet_session',
                                 'username', addslashes($username),
                                 'useragent', $useragent,
                                 'mnethostid', $USER->mnethostid);

        if (false != $mnetsessions) {
            $mnet_peer = new mnet_peer();
            $mnet_peer->set_id($USER->mnethostid);

            $mnet_request = new mnet_xmlrpc_client();
            $mnet_request->set_method('auth/mnet/auth.php/kill_children');

            // set $token and $useragent parameters
            $mnet_request->add_param($username);
            $mnet_request->add_param($useragent);
            if ($mnet_request->send($mnet_peer) === false) {
                debugging(join("\n", $mnet_request->error));
                return false;
            }
        }

        $_SESSION = array();
        return true;
    }

    /**
     * The IdP uses this function to kill child sessions on other hosts
     *
     * @param   string  $username       Username for session to kill
     * @param   string  $useragent      SHA1 hash of user agent to look for
     * @return  string                  A plaintext report of what has happened
     */
    function kill_children($username, $useragent) {
        global $CFG, $USER, $MNET_REMOTE_CLIENT;
        require_once $CFG->dirroot.'/mnet/xmlrpc/client.php';

        $userid = get_field('user', 'id', 'mnethostid', $CFG->mnet_localhost_id, 'username', addslashes($username));

        $returnstring = '';
        $sql = "
            select
                *
            from
                {$CFG->prefix}mnet_session s
            where
                s.userid     = '{$userid}' AND
                s.useragent  = '{$useragent}'";

        // If we are being executed from a remote machine (client) we don't have
        // to kill the moodle session on that machine.
        if (isset($MNET_REMOTE_CLIENT) && isset($MNET_REMOTE_CLIENT->id)) {
            $excludeid = $MNET_REMOTE_CLIENT->id;
        } else {
            $excludeid = -1;
        }

        $mnetsessions = get_records_sql($sql);

        if (false == $mnetsessions) {
            $returnstring .= "Could find no remote sessions\n$sql\n";
            $mnetsessions = array();
        }

        foreach($mnetsessions as $mnetsession) {
            $returnstring .=  "Deleting session\n";

            if ($mnetsession->mnethostid == $excludeid) continue;

            $mnet_peer = new mnet_peer();
            $mnet_peer->set_id($mnetsession->mnethostid);

            $mnet_request = new mnet_xmlrpc_client();
            $mnet_request->set_method('auth/mnet/auth.php/kill_child');

            // set $token and $useragent parameters
            $mnet_request->add_param($username);
            $mnet_request->add_param($useragent);
            if ($mnet_request->send($mnet_peer) === false) {
                debugging("Server side error has occured on host $mnethostid: " .
                          join("\n", $mnet_request->error));
            }
        }

        $ignore = delete_records('mnet_session',
                                 'useragent', $useragent,
                                 'userid',    $userid);

        if (isset($MNET_REMOTE_CLIENT) && isset($MNET_REMOTE_CLIENT->id)) {
            $start = ob_start();

            $uc = ini_get('session.use_cookies');
            ini_set('session.use_cookies', false);
            $sesscache = clone($_SESSION);
            $sessidcache = session_id();
            session_write_close();
            unset($_SESSION);


            session_id($mnetsession->session_id);
            session_start();
            session_unregister("USER");
            session_unregister("SESSION");
            unset($_SESSION);
            $_SESSION = array();
            session_write_close();


            ini_set('session.use_cookies', $uc);
            session_name('MoodleSession'.$CFG->sessioncookie);
            session_id($sessidcache);
            session_start();
            $_SESSION = clone($sesscache);
            session_write_close();

            $end = ob_end_clean();
        } else {
            $_SESSION = array();
        }
        return $returnstring;
    }

    /**
     * TODO:Untested When the IdP requests that child sessions are terminated,
     * this function will be called on each of the child hosts. The machine that
     * calls the function (over xmlrpc) provides us with the mnethostid we need.
     *
     * @param   string  $username       Username for session to kill
     * @param   string  $useragent      SHA1 hash of user agent to look for
     * @return  bool                    True on success
     */
    function kill_child($username, $useragent) {
        global $CFG, $MNET_REMOTE_CLIENT;
        $session = get_record('mnet_session', 'username', addslashes($username), 'mnethostid', $MNET_REMOTE_CLIENT->id, 'useragent', $useragent);
        if (false != $session) {
            $start = ob_start();

            $uc = ini_get('session.use_cookies');
            ini_set('session.use_cookies', false);
            $sesscache = clone($_SESSION);
            $sessidcache = session_id();
            session_write_close();
            unset($_SESSION);


            session_id($session->session_id);
            session_start();
            session_unregister("USER");
            session_unregister("SESSION");
            unset($_SESSION);
            $_SESSION = array();
            session_write_close();


            ini_set('session.use_cookies', $uc);
            session_name('MoodleSession'.$CFG->sessioncookie);
            session_id($sessidcache);
            session_start();
            $_SESSION = clone($sesscache);
            session_write_close();

            $end = ob_end_clean();
            return true;
        }
        return false;
    }

    /**
     * To delete a host, we must delete all current sessions that users from
     * that host are currently engaged in.
     *
     * @param   string  $sessionidarray   An array of session hashes
     * @return  bool                      True on success
     */
    function end_local_sessions(&$sessionArray) {
        global $CFG;
        if (is_array($sessionArray)) {
            $start = ob_start();

            $uc = ini_get('session.use_cookies');
            ini_set('session.use_cookies', false);
            $sesscache = clone($_SESSION);
            $sessidcache = session_id();
            session_write_close();
            unset($_SESSION);

            while($session = array_pop($sessionArray)) {
                session_id($session->session_id);
                session_start();
                session_unregister("USER");
                session_unregister("SESSION");
                unset($_SESSION);
                $_SESSION = array();
                session_write_close();
            }

            ini_set('session.use_cookies', $uc);
            session_name('MoodleSession'.$CFG->sessioncookie);
            session_id($sessidcache);
            session_start();
            $_SESSION = clone($sesscache);

            $end = ob_end_clean();
            return true;
        }
        return false;
    }

    /**
     * Returns the user's image as a base64 encoded string.
     *
     * @param int $userid The id of the user
     * @return string     The encoded image
     */
    function fetch_user_image($username) {
        global $CFG;

        if ($user = get_record('user', 'username', addslashes($username), 'mnethostid', $CFG->mnet_localhost_id)) {
            $filename1 = "{$CFG->dataroot}/users/{$user->id}/f1.jpg";
            $filename2 = "{$CFG->dataroot}/users/{$user->id}/f2.jpg";
            $return = array();
            if (file_exists($filename1)) {
                $return['f1'] = base64_encode(file_get_contents($filename1));
            }
            if (file_exists($filename2)) {
                $return['f2'] = base64_encode(file_get_contents($filename2));
            }
            return $return;
        }
        return false;
    }

    /**
     * Returns the theme information and logo url as strings.
     *
     * @return string     The theme info
     */
    function fetch_theme_info() {
        global $CFG;

        $themename = "$CFG->theme";
        $logourl   = "$CFG->wwwroot/theme/$CFG->theme/images/logo.jpg";

        $return['themename'] = $themename;
        $return['logourl'] = $logourl;
        return $return;
    }

    /**
     * Determines if an MNET host is providing the nominated service.
     *
     * @param int    $mnethostid   The id of the remote host
     * @param string $servicename  The name of the service
     * @return bool                Whether the service is available on the remote host
     */
    function has_service($mnethostid, $servicename) {
        global $CFG;

        $sql = "
            SELECT
                svc.id as serviceid,
                svc.name,
                svc.description,
                svc.offer,
                svc.apiversion,
                h2s.id as h2s_id
            FROM
                {$CFG->prefix}mnet_service svc,
                {$CFG->prefix}mnet_host2service h2s
            WHERE
                h2s.hostid = '$mnethostid' AND
                h2s.serviceid = svc.id AND
                svc.name = '$servicename' AND
                h2s.subscribe = '1'";

        return get_records_sql($sql);
    }

    /**
     * Checks the MNET access control table to see if the username/mnethost
     * is permitted to login to this moodle.
     *
     * @param string $username   The username
     * @param int    $mnethostid The id of the remote mnethost
     * @return bool              Whether the user can login from the remote host
     */
    function can_login_remotely($username, $mnethostid) {
        $accessctrl = 'allow';
        $aclrecord = get_record('mnet_sso_access_control', 'username', addslashes($username), 'mnet_host_id', $mnethostid);
        if (!empty($aclrecord)) {
            $accessctrl = $aclrecord->accessctrl;
        }
        return $accessctrl == 'allow';
    }

    function logoutpage_hook() {
        global $USER, $CFG, $redirect;

        if (!empty($USER->mnethostid) and $USER->mnethostid != $CFG->mnet_localhost_id) {
            $host = get_record('mnet_host', 'id', $USER->mnethostid);
            $redirect = $host->wwwroot.'/';
        }
    }

}

?>