postfixadmin-2.3.7/0000775000175000017620000000000012301477472014266 5ustar davidpalepurplepostfixadmin-2.3.7/DOCUMENTS/0000775000175000017620000000000012301477470015625 5ustar davidpalepurplepostfixadmin-2.3.7/DOCUMENTS/SUPERADMIN.txt0000664000175000017620000000255310716665746020057 0ustar davidpalepurple------------------------------------ Recreating a superadmin account When you run setup.php you will be required to enter a super user name and password. This user will be able to login and modify any domain or setting. Hence, superadmin!. With that login you can create new superadmins (and you should delete or change the password of admin@domain.tld). If that user is no longer there or you didn't use the .TXT files, you could add another manually from the database. (The example uses MySQL, the syntax will be similar for PostgreSQL) # mysql Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8186 to server version: 5.0.27 Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> use postfix Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> INSERT INTO domain_admins (username, domain, active) VALUES ('new@domain.tld','ALL','1'); Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO admin (username, password, active) VALUES ('new@domain.tld','$1$0fec9189$bgI6ncWrldPOsXnkUBIjl1','1'); Query OK, 1 row affected (0.00 sec) mysql> exit Bye Then you can log in as new@domain.tld, password: admin (The domain 'ALL' should already exist in the domain table; if not you'll need to recreate it) postfixadmin-2.3.7/DOCUMENTS/LANGUAGE.txt0000664000175000017620000000115410777765753017575 0ustar davidpalepurple# # Postfix Admin # by Mischa Peters # Copyright (c) 2002 - 2005 High5! # Licensed under GPL for more info check GPL-LICENSE.TXT # If you want to contribute a translation, please follow these easy steps: - download your language file from SVN http://postfixadmin.svn.sourceforge.net/viewvc/postfixadmin/trunk/languages/ - search for lines with '# XXX' comments and - translate the line - remove the '# XXX' Note: The file is utf-8 encoded. You can also use htmlentities. - post your translation to the Sourceforge tracker http://sourceforge.net/tracker/?group_id=191583&atid=937966 postfixadmin-2.3.7/DOCUMENTS/BACKUP_MX.txt0000664000175000017620000000233311210564410017725 0ustar davidpalepurple# # Postfix Admin # by Mischa Peters # Copyright (c) 2002 - 2005 High5! # Licensed under GPL for more info check GPL-LICENSE.TXT # Please follow these steps if your mailserver is used as a backup MX for some (or all) of your domains. Note: The setup described in this file only checks the domain, not the full mail address. You should use "reject_unverified_recipient" in your postfix config or setup "relay_recipient_maps" with a list of valid mail adresses on the primary mx to avoid that your backup MX accepts mails for non-existing recipient adresses. Without this, your backup MX might become a backscatter source. 1. Modify main.cf ----------------- In order for Postfix to use MySQL for relay_domains add the following to your main.cf relay_domains = proxy:mysql:/usr/local/etc/postfix/mysql_relay_domains_maps.cf 2. mysql_relay_domains_maps.cf ------------------------------ You will need to put this into a text file for postfix to pickup. user = postfix password = password hosts = localhost dbname = postfix query = SELECT domain FROM domain WHERE domain = '%s' AND backupmx = '1' 3. Restart Postfix ------------------- When you are done make sure to restart Postfix so the changes take effect. postfixadmin-2.3.7/DOCUMENTS/screenshots/0000775000175000017620000000000012301477470020165 5ustar davidpalepurplepostfixadmin-2.3.7/DOCUMENTS/screenshots/postfixadmin-admin-create-mailbox.jpg0000664000175000017620000023643010676263533027372 0ustar davidpalepurpleJFIFPhotoshop 3.08BIMICC_PROFILEapplmntrRGB XYZ  :acspAPPL-applrXYZ,gXYZ@bXYZTwtpthchad|,rTRCgTRCbTRCvcgtndin>desc,ddscmmmod(cprt-XYZ q0DeXYZ a)(XYZ #XYZ Rsf32 B&lcurvcurvcurvvcgtu ! ! > %&s "]#%Q&(@)+5,-/V02635 6}79M:;=L>@AeBDEzFH6IYJLMXNPQ]RTUTVWY9Z|[\^_+`Wa~bcdf g/hTijklno7pTqorstuwx(yIze{{|}~݀.>N^oȑҒד۔ŢfJ-ǩ`=ϯyN$дn@޸wB ּc)t7¼y6ůl)Ȧ^ˉBͮdЍBҠEԅ$dקGي.wܿd ޭSNMSc{1S ?i5yS&r:c ] ;p!AL!Y"$S%'I(*2+-./1[24(568C9:@1ABDEUFGI0JmKLN'OhPQS T[UVXY=Zm[\]_`(aJbfcdefgij4kTlrmnopqrtuv'w:xOy\zf{z|}~~pdYQG<2&ݜɝa<٣nI&{U.°rK'ص`6 ⺴c6 ݿU%ēe7ȡo> ̞i5Й] ӐBի_}0ڛPܼr(ߑEi @gHq)YCw4n,b Zk-@[v "(.<R^T !"%#5$;%C&O'Y(`)V*+,-./01233456789:;<=>?@A}BmCXDIE8F$GGHIJKLM{NjOXPCQ+RRSTUVWXgYXZ:[\\]^_`sa[b:ccdefgphRi,jjklm{nRo)ppqrsltAuuvwxryKz'{{|}~jH&߃{\<ΊgAҐ_:ǖvQ+ڛe<꠿qL%Ҧ[0۫i?ݱdB͸zO"ǽtL$®ÎnO4! %Cfҏӻ@׊T݉ +efK~ndin6WeM((!GP T93G*6DSdu6Ro>e?l/a@6s7yL 9 % v  s x , ] O^?#"2Hj'U![ !I!"#A#$%R&&'g(()*R++,-a.)./01`2333456w7Z8>9"::;<=>?@ABCDEFGHIJLMUNOPR9STVW^XZ[X\^_`bTceGfh@ikQlnvpqsXuvxiz{}}L҈{ohtܝ9F]Ű$Xx<ŘN̫UӪGڕ޻ Q8i92y $/;HWgw)D`}$JpAn2e C}8wEh  S O Z  p / c4 yY@/"%3Ie$X*i  [!!"d##$%7%&'d(&()*v+E, ,-./Z061123456y7l8_9Q:D;8<:=;>ĸ:ˆeԳG۟IQW"\  /BWoBk(^"a+psn"}< ,  o S = 3 ahx I|ko$O F !k";# #$%&q'G(-))*+,-./012345678:;<:=]>?@AC%D\EFGI7JmKLNOOPQSTOUVX+YtZ\]s^`)abdSeghikllnXoqSrtNuw[xzk{}$L߅yZ[V R򜋞B𡥣b)lEõpM羵u'ň3fqQԽeضE}ݍނߟ sX(zX5Z"desc Color LCDmluc itITfrFRBnbNOesES,fiFI>ptPTNzhTWfjaJPtnlNLdeDEkoKR enUSsvSEdaDKzhCN LCD coloricran cristaux liquides couleurFarge-LCDLCD colorVri-LCDLCD colorido_irmfvoy:Vh000 LCDKleuren-LCDFarb-LCD LCDColor LCDFrg-LCDLCD-farveskrm_ir LCDmmod*MrtextCopyright Apple Computer, Inc., 2005C      C  " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?!~|ܾ.E^]LIGގ9*|‡z|e-lj6v7I0°ޯbcI^F,\u h߶fiNQR %eO0!H`ߒƶl]{m-ҿoϧWWiRjIGk`zKh ʪ3b[> x94BX讂4ewb)oBT:͞濠[8Viw8:ƞ1I6MY*>Z3 v7G-+OV>˦cE %6R} ,eKNV۱vW'+|WoW4P.q˜\˯yu_F,ZkYk V!i  93o/w?&e^_U1$mY$A [!xj%nۭ陸&>}Z/3{z{+Ify.D'8c3>(|8|MhZk|1O̍%]UH "[?<%:fk }7eY 1Vbc` pj5Ki} oWϴ; Kq=nom'o xK?Xi171\mT7s #?&T ,cv=τ7Þ;Ҵ|Gn#{in(ܖYCle`+ɯM_ϝusgʼn<$#%fg]۲AxwYxt/Cn&7W~V#;듛ڿlF4OoMAec$Bpy$6{_i%xw-^=}ߕ/򴞾Og=&?Ufexa9k:^ $; !oWLSh܏+sa)[~$xP~>e@Bc5ddY$vqA YKjQ]o[ҟڳu~ڗG?s>!q WOko.yF۰0bc?d$M4?zޟs$z -;[nV;mت.&/;9_RW_.?ڗELEKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKw\ -|mE{xXm-l羺qo&n3޺o5SFMNxX˫5c_Lկp㍠3J#>`#<"WE{ۛ_^٠k;9쮣BpqIR`T`39 [km_2 Fr-~r8;W^2^Zy/3s,ҜrҿSr]VjjOmZW'Q SVo ҿ:W&t-O WŖ|Ҹ Kqc! VX?&?)ejY/5{uѽ;whweY ;u|ܖ[-R[U\-M[+J?jjOmZW'V?Fw4;^cGRZVտN/jnmGxvʿLA Zi܉Eٜ-M[+J?jjOmZW'U߈_ |EP}*=ͅENQIM~}OqGH?ED -HAA de8Ӣғ:p:-M[+J?jjOmZW'W"S_&䪂ɿjjOmZW'Q SVo ҿ:S_&?ToW *&?i_G-M[+JO>S_&Du5o'6+U?`UkJO>oZVտNToW *U?`UkJ jjOmZW'Q SVo ҿ:S_&?ToW *&?i_G-M[+JO>S_&Du5o'6+U?`UkJO>oZVտNToW *U?`UkJ jjOmZW'Q SVo ҿ:S_&?ToW *&?i_G-M[+JO>S_&Du2fwsƏQծtu3O>S_&69~w4[Vt0B+%cDuC   MT©C¯_U6 XS_&Du5o'6+U?`UkJO>oZVտNToW *_Y? T|-kp?-տNDu\ֳoOLkh* -N]bտNDukj\izqYތ+ѠcDu5o'6+i#5 1Y[eaׯ +O/ZW%.E58,`Ԧ𾱯KooGǞn4Nh֛IZ^Iⳍ_y\SHZտNz(W]K]4{n{$a{ 46;c$|Z#F|Ir(c÷!"BX,JZV rkڟsw{u⏄/4jZL<-u}Y8I65ݮqf&X-oyx-o3wڟ#;mN(˳c*']W Ku,jz-3[y3+dMp8'ejacx(4Vkn2ƛ3`!I5O___ ^i~u]R־}BH](1F,)95^eN<^"K8h}RkOC,5B}ַZlp_/]ߏGxmFXF˟[+`)SsȭhQmP 8P3>A>$x}# F(Ks#o#8O]XSKJDC] <}KoE^]ݵLr236 Jn] dn^=D@$Q{16i#}łu'8,AyN<vP@GUCc S2Ke[?}CZ[E'í&s<yiJ<[b_}V5 6ۚڝE~A/ǖsuUMq%ٮQOdO/>nHXyuvZ3,!KFmhNX|7^ji+]{xKEkelcڢM=4˪(( GJ#YI\n|)!X}Eq_pD8I0n}zyMڽ,)QUJ%~>5~@3llmZky上)nblFXHU!HBd0(k? }Q-?4F [jV͇%#d5ǂ?$i<{yǕc `̓@?O9a8̳<ԦZ30爊QTX~cy/Z~ 5(Z{]j3?hoŰ*MNZW?CO-&Y`],xp?_t=f>'?LҼگ-GNk[/!e* :DHa/qv~f mOtHFuou)t`}j*X_N/ |co|Z]M[3] XY;VyEI}c|KFxkV_D,x^}G(Im`hV-T*+CTj4~Vw[دZ>gg*^RKYm{u~^ >:j Ѱu;ҚxYC^̊@"4V}hZ RcS7 [tk;km2hguit]^J#FIHnO?;||\V R\o5Inb6H"IIo+K1!']ta|"-'6b_u=Utx.K$mq3%PL'"muOZ|=nM#I5qem٭_ndrƪ&s0G _ oxmj~%z&%>& :XAlm>"[so$G@boޒlnWePQryyyѷ pi[ms5C.qvI"ClzPkĸ?#C}gIox;wjo|lmM{F) 4$nlR 53z.M}6u6ey~?^K#1'2tǍ|'b\|K|CǞ0tX>'j__ڷK>u'^yvA$n:m ;Yti]c+ƄmU-d;kmx' Wm(eMoN! F[ vίjl,˫1y1x,[fҿfo OmxH_uZ4{&Z5< `UM*5[㎅_ F4~׵sHnҬ}B*؉IW!zD> T|Qggaiũl"8̓b9#]_JovɬxVOxV֍[aku:˲|bTITyJt7:|޵ߥeG)F/>+ޡy!vqoS.#h¤dy[ƫ1(:-O_V|m>%躆}ju9H4x7G71mgIOZ9=<[*N q^;oiwhy,hykOu-u4(QV1%"s,M8ϭ~ԿωcGO|C?R֡]] HK"@LֱGVi>m T?ao|+O ӧ_^XK&^ydRbN>,|^{u+m3ڕιsg ]Mks1mnY> V1m}][?|3_Mw˽{w])Q߆~"&KN~"x2Z,>|OOLΓ" Kߍ57Ut{U*Q9 *#mFugo tkoD.P=^SբI l.-q%LN(|/.<3o [ k%՛n'i[  3ۚ+xZס5{Coj=QH-}5-i?h'NB- EƗ OS>!h:\<._IIK;m+y^X8C_Z'_^u#AӟJږY `b&9'HY^dVUBM?f'fܝaM'򒓲.NN+dGs`lWxp(@$|XOc\[mocL0 Vno+sG+*,wĭ+o~5:&o㵵&""Hb>>s%tO_-<O7x8궿:^s$ܺ'~$rwq',y`J˖N-}IѼWGmov?Rݩ$d~5KCEW^/&""["ʼ  oju TmkW{ߊ4vݮuif%hK A|I#?iKHoG?U{&;;HJMbʋO&,̠J Cr/O>}oڅ 'EsefV̸" wm젭62p]S7w֋m(GݷWKy2^_i}Tӵ .k,e-Mg-2]xⅼGT|V־"/|)VYnψO}ai&b rɅK m.{/8޳7Ə: KFMB]]_@-ZZƺbٲ"i'YF79څc­;+xIkڷ#aO3Ӵ7еH䕶BbVJӗM3 Iy1L˧4|7x^gċ}{>1xzo.=Htm/cݵ,,R1,F?' 韴@'xooxY_ Xkis >¦?]$a$BV ѿos~-ּ77ŪO<ٓό'J7=[@v`eflmm;=e`^GV5N|/oq>˯WԢ.a_Kw+mXmm=Tj)TU,ھֻFR|j95PʝvѷLUoN3W;>'Y @A-:;%KX{̸Au'0>ϳZTi_ ~k/\o ʱYnRTʶn4Q # *>?F>ǩx|Ps5=GGϊLB3l;mq4Zo h^ ťtr3K=  ?R_x_žVrGWVWRFZ$.y$Y:17=d}S9czw{5gk_Ee (~V< i't>׸"&5M5 &1ۑn23n Eu;n5ȷV*l9R HÅ]|wfLUNQW3Km<,} u\JJ6^{4얭ꝝ>r麶:ٯms3EǦMlhӵΏi$Pk[ui>ͦe~݈w$JꭠݍBqRw}j`ݵ{_Ŀ 7]5pϖZ}ZNoƱx#V:dckwxm2KH1rheJ+ [~i*|ogZdZ&|8^,qzll7;;W_íS>>> u/ J.-f{H4-&;Y#\c0۸3ϙ׎%ZJRR\O[MW RRw^.mewۋvyD>XWE~O<9_Ś6ᔽX\Gy)9HVk݂9'? -?ߊ3i&&u :ͮ$?h3DHZiϛ믧[|]]_罺w1!6Tᳲ*̍S4 K(1|Yu_]/᥋^ $S*XȶB}4[@"Qm7qF=KRt`<)x{\u B=Jks./n-%xK* )E!Ӷ_M{kJ=WϦ}?[|B>4v݌7$DIcWPFO5Ut[4{K[-H䩚઀^M@8qV=ivQ (#֤aEdzEdz_:YA>#I(iLBٛLr?ь>=j+HW<@?F8xO"/^:,.Ok~&ޟo2IlW?|k)fO?n 3׆ o+Ś>n~B_iqsgCop 9ApA1|m8/xxbom,la0ErُlWYڛ[eM_&'(_[Nf.cQz(爬5땟>ֵv,smfmw~_fhthRkDl5ִv4z2խs [y!ѼW,RGGF ^ERJ:$K#ӑB`šKMJ^E1 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=#Nu*# j?/^ExB: 8xJ[W^Ex--#k5?&5Gj&#A9]Cg %OPz:(?Ko/x =C ?^/z#н_$Gs<3L{ĿIGB?Ί3'=g %OPz:(?Ko/x =C ?^/z#н_$Gs<3L{ĿIN_0?ƊI?%uGvVMWڈ'ohlK PC:*/ MĿoi| sЙf :N SH2#9+k>>|3"m[K B Dh-g*Vϑk6/_.ůh8?੿L_`DA=jv#["ȓL@Tn0n;S\E8U\voE|^ۮ: A|5{: >[#,t$d~O7Sߌ?> ŦxM{u#PC:1,:$(PXvWeYS^6ߞb䲺t]rVk~+Š(((5о+oў84KP&mZpVH0 ~,xW㏁,|SSuO3ZèX]r4RyWFdD;I#": +)?E%]^mgċ$f J(.t80]HBgEfw#Y'zỸ_GԗqƣScTѮAx N +)े4 b y=jC,m!dlRprPEPEPEx+3?­KD^!PZkhh8 }fNF@EPE|٥~ο oxP4'Ί4y͚8WjU',8BQ^m.^|y?6zŕkqdH␐#L9_I((((((((((((((((((((((((((((((((((2[\2 ,@IW U7~֓! "C 9-HdMK\$?c?.v:3Mʖ~rXw_}b9:'gMO*[˴O[G / uoƺmzҠC4:.y)lj r_4ys[wua(k47h-Kbl~g"x Og7*ĚYLo2q9)p0It^.OJ+~0A>ͦ_6Z'wOb̤z?AIzs?|#t> nhַ%vx#̱[6_gk %|Xkh%>@FܖPBɴoaڟB?(j7>GiKynH 24&#t?XϏ YJ|&+ 'K}4M%)UeR<-61@?p?]  Zdˣj-uw(VesTU!VVaO8g>xg}* O9`66޲L{Vt)8Wk{K< ziq^\Fg#Xov BFs-M>_G.5k^?:GItf] __%ȓ'4w!=kjo>7%~|=y8W+3o{"ر%ϕQ6/???T? t/xΈlbմ{g*##mUm9g[oLƯi֬5 O6tPq&Hv*d;-8s ^D4b;ku ܏-Õ۷ }i|sk/uvσ&Iιx{T͢H:Hbؖk5dcx>z?cO .puIGW]BDI9|-/~/~k7 ^.N~Cëq`䀫` ^T~ f|kMynuMv`S+ʯ:s?I0_PlyMTde,wh uh$n%-^C<81.gP?'z7?J;(];Mm ?h'y|}z* o+·:ij&ik}UMđ?^f\6>.!B?o.h^o,sj8vBU=Ǎ? u]cᇇefm䥦kh' Wg>r@| #ύK3M|҆mg_P]m=kFn7{^|;MPKfNDc $@3|P!a\xg{ӹ|ζO<o4t6Z]:3Cï_ |'xfff3x_:i"XA$PW>i[uM>'^]659 < |RkQz<\=liLݓknT|w[N:ιKm|k݃ _f~q+n&k9%x'i@YYNH؃U;-i-f]_Z/EɲK2^̻GP_t|9/{c{E;V(縌cBc9'N_h=cfMw:հ+eI Fu%,Îu:Yy]>%>,JTjj`|Qx tɃLݞO(Kb2 f{Ee'M{Bm~dd7$rǕjE-0UUU9?]-"hC0e?=~Zs/3WWůxXo`[X`XcM xp rTunl ծSľ]mbJTwڿ|E:|OgǰZMh,-d{>S/&BeG 8~ys]-yj:CVQڣC06r7ڼEhPDN%dY_o>APqU*~׿ h-=~EFWd˂V;5 )v F fPŐjM߅?'w%hZSF0Yc/Āu@U>A?<V9UA*b_*vR}-^_#%=4]#]t;w-9Wξn]MԳ< z~_E;y;_z|mjM{JIu+}Z;Wk4kJn [€I&|+>?N[özm'$K$8'^EV4{OW:m ,N0Uс pA5 >8~#yOd4ַ

m3Gy3Zڴ&8 QT1'$&>cWDgKy>OtPx%1:φ|"axHմ/6vZk"$*FF+G2ևž}#MsdʨFY)$B hqr綽 ^4^T~ͻ߽Z~Ͼ/xB7SHkuk_60_ p8  4,>z?emv<*)XQg jآ9c|Cx֢ ƛ HGLJXcsQiͼGxC!ydHt#i$ $s8M;9s(_/U?i_:-<(\,j`¦ 3F??yY߽^k9&+{x[>4MOfiC ߘ̅T#@&³χ;iӡF7J7mq㩮?_ 5Y/C#iTd/TS*j( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( cJU(/KLJlt;>s:\1}Nӭ}> M&mmmcXa ( P5r?IeU#m ?d8o79| O=/(+_JhiG%?w4)9€>ESGsK ;{_W~w5|v~5XN NFtk]_'mPѿq?)9}uE| O=/(/%?w4;{_PTWȿJhi@]Q_"SGsK k~+iQ|[wX`3)o:~+G5s"qǗ&/x_%?w4)9€>ESGsK ;{_Q O=/(+_Jhi^1Qw}a8~ˏo:b=㾿ⶫIvy| BF+/%?w4;{_PTWȿJhi@]Q_"SGsK ODO͝!lӹȾgϧ4w%V_+# '%?w4)9€>ESGsK ;{_Q O=/(+_JhiG%?w4>=3gH}B4`2/ﻻ{{Y|)eH|BO"8[}q@u/%?w4;{_PTWȿJhi@]Q_"SGsK ?)9}uE| O=/(/%?w4 ˩A-mq;Xmmz@WȿJhi@]Q_"SGsK ?)9}uE| O=/(/%?w4FⶕŹwxy﵍?rh+iW:,yrn_N ׅSGsK ;{_Q O=/(+_JhiG%?w4)9€>ESGsK FⶕŹwxy﵍?rkiW:,yrn_N Q_"SGsK ?)9}uE| O=/(/%?w4F:n㼻􁧻B6ُP7}'^?PQEQEQEQEQEQEQEOЅqx@S!\}QEQEQEx+ARSz< ?K@)V}hxCYQEQEQEV= A5Z/Ǎuɫ EPEPEP]G'u?k_ OEgև=?A@Q@Q@X+m]SV4 Tb: +? ((((Ɠ![oWQOЅrOm1]G?BEQEQEQEWq*?5q*?4EQEQEV= A5Z/Ǎuɫ EPEPEPEP= A5oG]Gj&tKm@|o}M.TeU1WhԺ{"BƐ:wu-zhKȼe 8'hOoKnKWF5ַmuuˍ`1n r|j+F5i|e}hzUY $'1@A8?<['è4+m/gԯeY8e<@+?Wկ5a6ͣ4-Iqj1 EYt$o'n2MMoK{#tCbu&'ɛ 6>Esbxe̷?c@~|#ȯ,xpW'6}|;-:_]/q-#ëG^цwݿ:sҨ@񶫤h>۩[ɘ9vsK`"]ߋ1w:eΙk-^i5kZ/t"8yH`>^۾ uxO/-l(ޤ ȍ]_&;kW˨KGoO;?LQ?geci쿵:7swl}n՗q*x6nSP ͶZ=4ўrjZ9[ߍBui7[:/~ > }/I45>p/퓐km^h]\IPÆrtO^ tD o4ٵ/ቭ.rd2%ےs+Oγًe'rT%W>>AvAQQ|T[-#XI$:ME=BeB 8VEl=N5x7'QiW>Y}#\w78ʃŅ$~j]ދW-[΋_|G[a\鶚{#x:Ǝ#eW1mIVC:=c5_yy3nL 0T1>(|Ym;Q-⬖z3+¥Z' C/k}+>:+2()$qedV7@0܄=T[/Eս#>+(n`F*ڬ @YWo Iu/-wgr…`bۗ!ݗOyη/$ֵ֕}gYGoe|mn&eknq1T?ֹ94uf0xoI Zd`t,c%$p֭~~Bm߯=/WF5ַmuuˍ`1n r|j+F5i|e}hzUY $'1@A8?<['è4+m/gԯeY8e<@+?Wկ5a6ͣ4-Iqj1 EYt7_25 3l(@6 Ez'=?A_ jj-\[n-"\N.[tSu-+BxR1`>X\B0NEl4ǸXQ2ɳ.q)sAbp3WM$xJƓq-mrO'WyNAn8.k^%ƵWX>\:3B+õ]CFi_76,)ne$}A&88w|--<ݝ_~}.{mk~ \AsYR^<0<^moڎŏ5 A\^]y-n\e)YvWQk/ []WO{\@=2s2q^oƚß x7Ƿ^4/ f{.k`;Ǚ kčI~kzΗCZ7t;PNDa93avH8x.vA hT|ygNm+iX-2|J9ϮǎfB|o4m<4e>4&rYv' O?eK_zK|H״a}?wo7N2a4})miOV$f13G]\RXȯ6/xzΙsZWMZ?%;es~]i1F4[)5 0207)_*@TFFA~ȗ>+õ]CFi_76,)ne$}A&88~~# }'7S{bH]=8TM޼j]'?sG+i,W;G#@sʍ 5% D@u]*ZmΣu O $dg8_Zݟ}n_~3"12[]R^n?t>~_TMPNѭۡi%c }-9& 4: Ѵє4Йf؟<8+tEi| Ծ"VO׼ ;yI 1 qs(ot+.{Vm]6/-on|7JH#^*?5 ? iKorEA# [AW?q%xᏂob+vn湑$qFݕ@"h_4 _ᖟCQtmB'Hyr36Ფg+7?G߆,Gt3Qki"Rm57)V9E_.<9yÞ#tmVme4PDiBFS'e>%Cn^)u-/HӮ.^$K r1 [3w]'|Z;& ZǬXA|"vaF݌Wi[&6̕QG᧋I+g)/"H|揯^Ux拢Aq]CLm,$}aX kKS펹cM~k wRrHg ld=LX nVcCųZDžn5ȵ >0. _CI b݄a)7ֶVDjICu>c}hv6Z( nAT-ʜA52.>:΅ov}qڭ#1o*ǹ% ħ5{mB;Ye=$(J5=o#w _h5qmCNZ޴>ޡqg%iWv٥Fr<8POJ*??WͿgG'+jAwl8YdYs"PDєGZ_KyNߍVU|zE,4SK3%1̰dxl+O~+-^xWJoF62hF4y(UWg WvP_;oíKN^aj,Q"H iɘ s,|aC;ݐ $:V3Ԧ֏]KmLMF68v0I  mw[(aEPEPEPEPEPEP}VNH7ߏ=? ^ (^A!렢9A!^ (^A!렢9A!SDZ/3峷P>O;'FvguϵW^ (^A!ɾ!|y+K7HM9!Zqp1x#Vu\G$םW6Л9ٯ'GW5ћf/=/B׆KyhG$x/?3_B/=/xo4?瞋~&i=]Mx/?/=/X)h߳?.g G$ /߫Io??A#moIصX/k#޲ׯ G$ /߫Io??A#ܿף_z_zi=]M(z/?_X??=_z_z?ׯ G$ /߫Io??A#ܿף_z_zi=]M(z/?_X??=_z_z4{V79l`=}i=]M(z/?_X??=Uf|3:ګ O_ ^ /߫I_EW_G ~~k??G O_ G (z/?Q<_u4m?{  O_ ^ /߫I_EW_G ~~k??G O_ RZx3qK[Ǘּ'_EW_G4?瞋~&~~[; ߳~>lg +_z_zi=]M(z/?_X??=_z_z?ׯ G$ /߫Io??A#ܿף_z_zi=]M(z/?_X??=_z_z?ׯ G$ /߫Io??A#ܿף_z_zi=]M(z/?_X??=e_6iIc8_:KyhG$ _B/=/xo4?瞋~&i=]Mx/?/=/B׆KyhG$ _B/=/xo4?瞋~&i=]Mx/?/=/B׆KyhG$ _Bj,qdbqG$ /߫Io??A#ܿף_z_zi=]M(z/?_X??=_z_z?ׯ G$ /߫Io??A#ܿף_z_zi=]M(z/?_X??=_z_zS29ѿf~]As^ /߫I_EW_G ~~k??Gޓjy^ Ge O_ ^ /߫I_EW_G ~~k??G O_ G (z/?Q<_u4m?{  O_ ^ /߫I_EW_G ~~k??G O_ G ||DnB-k{m#"GsízzTSTzPjEN;=N_z_z?׮}/Ÿٗ3rz?p۞z(^A!렢9A!^ (^hǻi|3rwڵ((((((((((((((1THnOU5u8+_٧OP+8(((((\\%ܰHRǢ2M|?{_ViZ|&zkcR'u2,m2.ȥvV 0Bz|Zqi|}U~Fn/>j7"%ǁ>'֊ե$c b~{pjSiyk|;(*N[zk7źbjt0][˾#n9vu N A᷎U>Eض2jw^ej4bHAGtxk+tOYӯP-3dz)'E$` %&XxrFu-gU˲,$bi>ZKetC (wIv}6߮J{M鶚=rkwkדU:{j5L ѩ!M x<|7?7z޷%y4 71\lWx#]2FEy?C}R K=}\s.M8$2ƍ/3Sgo|_Lu X/0),0+3 MO~Vwiz^~*ko}ϫD ]oiZ H 8>|Z|:|Or@i o)VLc'Ojl#}g|0hq5D7V&B229!9p1^13%OM_@z/ou @M pZ$80ҝTTXѠUk-'|[`N%k_6)/qj~dU_\OX6H iv݁c'Uwt^}øQ4qyJ \q׋j?O]ŭ~36rRA"/$jfwGӠ ʨQN]I.vtesͧ&m6Gxwm"]Ķ򮹨"Zhݮ?p'@[~4Ė<?xg,~ҭ%-5= +)H;Boqv7~:MڅqJ$HFXђ /k~&?uxOh4;K{nZ;x"4Xn,FX ~~9𝏋7VYgpB骕d׽o׿£*pI4jމ'x=xgM4Z\Xjڬz%eW7gd/@#xQs kk] o\EiR,E &[%er9oc#]WV<[|c8x6e rPy2#:@;j[TN/['-|V/itW۩O_~â\j_ {]b% YUU䁜Sy_K݇\Nn#ibK mdnUz^ŧh6dV b˨sWʞ >$'Džy,Sؽj7Q\6YZ#qF;Q[&{igqod{ݼ Dxg.ΉG*;',"G)8FlFEdZ@~b֘by$3ƻS90qgsqr+>~Þ=oh~< <)TToE_5Ut njc!hm{ K/5SQh"2Ia@85`T5o%Ά<֛}][Em7[߶q+h_÷N-.+7̡8*8Fr|O`>j:&>!BK]Չ]"PsbM&h[\A]YH '59U** ~0ҾhWx!KE!^X̍&zo'#> ;]zi{軽WamT7yj{>m,Ҽj|;eu]¾Ž^H_zJCƟIeᴿ_&yooV\1PG'澂8>)_hxBhƉm8JA|7ZK^~QziݵnTa_}RE&uQEqaEPEPEPEPEPEP~?,_DZWW?,_DZWWXj_Ѱ?Կ¿$QEuAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPx><5 Fm)V $<<̌9 Ɵ.ehzմ5+Lԯ4Mͭ4p$yܱ*F tׂ5'!a_v4[y ݙl]dzB$N/g(oлqzP4v-{O3!-LC㶋o_xⶳB%[R+\\Go#I$MN/g/(oлqzP4v-{O3!-L&QvyiBZ?Cxۏ ?~?ֿ2g?Cǟ[_G † kǨ On?2W9<Z??AoeN'g- Ɵ.e7?]_=^ x }k(s +aiDl杹ی= N'giBZ?Cxۏ 4O ^֛m[y䑋#B* 14`a;??p| Ɵ.e7?]_=_RQG iBZ?Cxۏ %`a;??pyW%ݿi69 O.Alê7U^_ \iV+ץMRazPP[ ((((((((((((((((((f?n_x _ ='Hu5:Xk9Ki=Rգy"|H(nV޶_$E^&ۭCL5y/#{;eEW$ QD&&Nn|[65)%e4eoEd)tv?9h_~h?=9 }m={VH5+NXO_W}{vQEAEPEPEP_ v(oo<6KaKbqV[qP6p~G%|K5cx>>6MiYskۭo_Muq R Z$X$ @cҵٯf~-?xoA}rGkjul5[4;x놷i.)$ wzk#G($] *=kT1TxߧUU#v?e+[Mz Kߥm}eoy{7ɿL^%(i?|k%oM],\e $IgEQf.8 (>|eIDk-|Lךna#q_M/?5_WV<=/-]_KmEt[+uSuO8]!:k .>)ƫYseb/0~N8mʾFuPύ5:Mk=E+%٧gMMSN'jT🆾+kQS|^ ?˝c톏O M M$OXg>>#qOS;u\iu/ͦΨlK;XաkF6̈oc8fO/Dž1A `z}*߼ޖwmo{6oeWZ^NmM՟ldHYˉg/Džq ⧍|e;> Meq,NlJň Ǔ*z}vkIlPwww'-S?_~.Bzm1%]6+K[q,";g&haHUZDVdKړH{\ƏÞ$i/|w|C,ֶ^qZs4p.&_<%'T.T|<)n6nTZ+/ym/wmSiB[M__yYh؛6|moG~=4?"f_[_[=oş.f /~_~⏊+3o|q|w^\^AM{wtjIeOyλvFqrHΖltJ}_w/t.m/%ZݞǿOWW|qo |;.~t 6NGL);wl2qdG@Q@Q@?Ob!X딟*QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE| KPƛi;;:tM ]YI [n22#bpk,-XtD#!9;=MS>2ԼMx7G~՗ik ^Y1oymre,'|`>( 5c_+𯏼=>=|5mgxVaQF'Ρɷ)GW^PvDnMKә蒹} &VүӼM-_;>ݬ)E4i}\}}cz]toD?M)(Ad޿2/_t/_|7A}/ x?R߆|#\kQx&WmZWaqmyrѭa۫m_x[L>]|=OqEj͙Xt+_7-ci,ёzK2ѧԽ:ix-N2M$mw_64|~6h_<=$Wtۘ!2/af3$4~-~~'_e~-~)xG^Ĩ4xZsi~v ]]g)~ib>៊n|(uvuYu~-ۦE7ؕC"$1֙%9! š?ᖾ9'-?_ n(ZcD t-|1sOZk ρ?Ai뻢8Oe?N| O7G2'>m+o>~Ӟsm>+O?eޓv763qY?s_\ҽ(/L~|=|:{gI4 E'c_GllU 2ʋԁ^ zWo^`|nxGmO{ĺg]0Y\ORXixBK6ot?EӚ⵶ktrV8`-C36fP/?؟x%^5|cHm&VMڑD[6/ &P+Wѿ} kƋyM>-~ yuYyt]ÂTJ*MmNШ)J7D_KaAAlp =τO^ _.x׼\kho/Zj%۴%QڗOn ?G~Nm?M [#<ҳ<ҰH$F" $$ݝզדI5t |ۿ;GE_?,_-NjmOO֚owEuBH˼LC8 [Ή\MWM//|'qNIs`X;Jm_~,~_]|QCxFѵ! xEʹGLG7inGf-6/_]C?}CoP;[ZƧu.y%4]f-"Qfo(|5I:'}TV~n[/Witv]V/,nn<.|]f5:MwJ ]ikqhRT"m|&D;{W+xHd~,u Z_jO3[k)o)>8 кR+o'W;mqڇyKɴ=WW4>y .4!9^WOyq>"E |\[GP׾1g3s0~bMC_IBk %+[ʀ_V$|_Fr''~ttUKe1JE!%~(gᯆZׄ_Ӵ3ݭDGxɎݔ5˚G~ZU=|රNa}&$_-[Nm“enEbﭜB)8mkUvM|M{Y5#>'I<[*ſ $DxY`k'_#x]]<3esOU5MN.5Ihp|$pko~?6kC{{|S7Źcx.-9TE4'Y:٤[};K *6;qk>(BxW~4KQ-m,Z_JTNnbVE ?{eߚQoEc>]է},oC(?Ob!X딟*QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWm\ _ؿQ~?|i3ucOkO(|_6|rMFB,'i4 fXGZw~T|+߈ )-AMss mt`+p\n([zASMie+Y=Qo4WP|MyoW֮-BBH=.[񯍼GWöno%̹y +kX. % C*r_tɢ]]칟uY7znumC^ӼKsυ[}h[G \'K¿¯|p?<-BMw*ho/I.-So) X&!fx)d`%{] Md|>ß}J^nM%4 kk r ^Ykx ![Qn؄vuu_eۏTxG.{0ω&]~.aM{#<#_=gĿG.{0ω&ފ]~.aM]A>%z(?u|K4w k/$ 3_Iw<#_=gĿG.{0ω&ފ]~.aM]A>%z(?u|K4w kYkucRu<=%Ł_6WYv4V0G^\'15_JtIeu^i[dӴ[Fk8Z+rB="(tT(F)$J63i?h|g?F,~%ÿ>x:?|"ϥ ]m~&_Z6s+/|Oim,0DǏs?Cdǜ<;o˳?q+OoQr?ᶀkͤ(͟4CĿ|k|w𫵏65ݭ%c֦I8V)l+m/崌 uz8e J[h98횚[ջiNOI$weQ@p*Ẉe?z?Pk&~'xWLt?eN+Ku}%Yc,cvym'=h질=>VHwϮNiLk;[g I*zk0;ׇ”w3x)f/#PZi M 0$`Y=X<]@%j?Jx?KW”w3x)f/#P^ S_FĿ@E|-P? >.ɨxUD">x7w":ٵ+PS>T1X E{Knۓ$85QEQEQEQEQEQEQEQEQEQEQE^_ \iV*IҬPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPÿ7Y/o20О jš5EjK`aGgi|Cl~&x/N/u B2 6{ &kH qOM}}<37"|YZW~9շur,: hdǷ:HP%! |Q>ϺiKnG<7g/kvvWeZA}7MK#rCd Ҍv^Vuի4(3Vm+y4z4myx7YxC%%5WjXZ_fkVVM3<[.b c#?V-w>]? !.~w"]AgR$kI| e~/^oi~3Գ}riմd,~Y/.kշ쟉?^+Wc_隝qXY[x>Dz"G pQ|n޷ͨMN/ONxgχ#QxXҼKg^1[YbRIRqʾ^iq|;f49jZWGq\\\%s; ⟄' K֧Qgo |B]Z`E:ē[ M8}h%H?|G}ž!XX]2KR D =[JMq܊gG{5_&[Ptv-WjGXG{@m r-̞bme?c·$ukxm4kfYEr'HL d@XO+>8x?]Q#/еO.xz=ik3̦HR.ԙDكb+x>_ s_Z5=-sź]ٿ$IV$u.sUO lmmdEjԼM}h`Ὰ޶դӾVHeɨn_}ݶe$iwvo{Wֶ:AC~;04s3J|69žr!e{Yp!sl?[ ڗ[O5oOs-^-0B'~yvIhPqvoKk/g5GϽxqGo|bKiO +Ѭ4? xk-t%y!%MHGoS6/ ~↏HHVw }iσ~}kEu=z>Y>q6qbځAْ OxS ='=bK=gzŚݵ?j졚ݾԷX[w'.jj+_sOMlmNpEQO_Moo?|[]~a3elm%n$?J 7?d,MFsx%o$ZAIf̫XErų u~ }-B-SXϖO\goda؄Ž{P*/qq~AA&("!|/g`0J5[b}ѯMRIKd(((}5_._ϗ~g4?ۧ~j_4 V/;|/(|jD yP~"T~'|%>6C񿉚Ỷ 5vO/gÈmۗ_oO j73ׅn 4uPA\,i&ln$6`"@crs>s2o-|Iݷ2 m{YoberVHDHO?|bּ-᯴xr%+x"^0i$$yĀ9+^olZΌQ>g7-E~|?/?ms{x[k6ELxw_n_ѿD~Xʃo٧:n jI4ouETQEQEQEQEQE|(} S 6je&)qXm'*ee8<GjO;jm_|)"V&|RlYݸbvU YC|WgÿeOJ{ />^&30qy֢]QXKk_z'*>߈ q+^Gw_]au;;K G+!!:,iŭW:o?xB7#m_V eIƁd2vOv~>Vu}Ze5/Vwzu(.cƒ,XB10>a^ ~ |Hռ3azƞ#w,nκDzxe-Lj5m2'BC4Jqȃ ϾcΊګWkᏈn| n.Ki3z VBm3nh“YzW/_ S)3CmjC{xNk-nZaCs+4GDa+//|Kvo[Ey?ړ,5BK_Mqo,ڕޗ^YG\XM0EMze6)W4Š(#4?~|idBkhs5$I,ĒK3ĒI&cZ+a>9~t? <*H|n8 {}n_g3@h\V,b 6UC@="((((((((((((((((((((( V'JU?Ob ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (>7c/П5 W'ñiV^/Ʒ- G|I'28U*+HV4[k1b|05k ӾjfyF%p-,P1&fp<(U#Y~Z543[j'Q7ORr 1Ļ/tVVѯ_2I۶kg%ed}^˲>/5><[>[OߊơekɩI=f X#D|@s_>|0^1>.|u?ZmnVM6KkׂiD0d+޴Uʤ輼LI.?Eh|=~~=]?4Oռ[w ]jdw5Mqu5i⸞ϱU!Ƿ7u|Keό>7xWVp=HVw*B.F_2@cQWNTXkJL4y|107m3oxK7oeuH$՛P~'QMn}<-d!S~57??jx=H|M<7d[N](,*ce#GmJ }IN d4?Ըn;G COH'/x_^ lImmM>2n1gGl T"AYǚ׋G{w$iIm$8HUWj ҿ3nO)j)(˾-WxbJiPG/n%kS_MPG%ʫ˿(/й799QExcǺe晪s4&%edʶ8e' b[cMEQEQEQEW櫢xXt?ii3G}YVh"!L4OUѿ}/!^E toKtD]z_>!WFG4OUѿ}/!^E toKtD]z_>!WFG4OUѿ}/!\/7N]WNL/tnQs mEPEPEPEPEPEPEPEPEPEPEPEPy+rXV'J@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@[$BU}'AV?QEQEQEQEQEQEQEQEQEQEQEQE/?8g>ŌӦn[TqHk|_%oH-+|_&9o_ku~\_A<ǧyAE2#*,2~\ Wۯz>־_Jwm4]!WVg[N[}TRuCH#r6`cE]|Oм5Fku Bcm: YG9A*+X4[-"^Nfܫ1ͺ66d<%<~~;x ?NSӿ6Zg \yvrHAyv(l?5o6iMV·AԢZo_ۀ|%}ۺ!5AOMk"Z\]"-\LBD *7π3Zshŭj7Zyf/ml6˞rYL;## s?bjOuW/c6AoJ,lkUv sSQoyz~/y~_5k;]+Od׆+^9VU,6'j(5W~t$Ro*4Ukfx856x|CojzS\*dcGuQAs $}~sv_U֩='Ԭ4}N6zo%ReH (G9&UDnڿ RmNkk]5[uasm%G,jgH NÞ/Ӽ]ụ]:tVس X>9.KMGҾvH|K Pd$0s|b>xQ-:ZE6CK(>n- HkM칞_2;şCg^^g2;şCg^HaEPEPEPEPEPEPEPEPEPEPEPEPy+rXV'J@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@[$BU}'AV?QEQEQEQEQEQEQEQEQEQEQEQE'KGV^."K46b Ẃeb_뚧 oCg+EL<V?G3- +2?f[v8=*PEPEPEPEPEPEPEPEPEPE_j>7E[1>cxݢ_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9h/h9h_Y"Y";+/h9kd-漍"X˪1X>'(_k_h<_RwXA{+)dH[xlKpCX68#T.cUwlEPxC> 2/P>R]/ܧ7n} ͨheԠh,nms߀Ng:֝YҞ-Z+Vkin~e(%f!H# Īh^0>QޫG̑hcm!}1=yluæj {}7KRuq)oR['4.hpvm:F`l/' mٮ-fxebѸ! '(ܜUi~#I񥆙ټӬ\Od?t紓׆4{;=]R6iZOn9 `V?qzM/ZfwD(4AM]7:.O_7k^$6Z| ޥkf`$UF#sqe+k8䙡^;R c4uK塩X(,[dX{YKg(m<]Ш<[Ui6=ynЦD[^Mi,O+$.>Wq@~?i>.lagmp+|#Aqt `?_%wf`` _[Dz:f-'g'C3xVBʶ.atSwwqu>sB#?6I5fO5ZmNmE/(*WAZ~:z_nՍޝXmS%[1-嫅,@~|Lu($.,,-Eڢ:I"$°Wvҟ|t}5/pXK١[].#&rF1_O6(ƾs]\jMu9]O{[4Z9^)}"Ϝy}k]/^DhbM9 GBOB>Rx>xryeV@ʭyYlRܕL:-߄,/K``d# ud䜚S- >_麅\uq4ql+ I?z >7(%I8<ؾ,yK-]\y!˞UpQ@f6v<-cwi5mfHjW;%x2/]HZr|1ky,s[]YUr\zpE?NrڗgV:C,gm-Q@4 @?(|4sVM헃-NdI$7c1cFxp;L'óɪp--HaepF9'9*xi_QF* &FPsR7~`]mּtǸNFogHn՝_;K`?4j4zAz4Xƫt9m䏙6eX0|9yZޛ![㷻toqӥ6ெ[3o> :jAkwrxmIM9VW`ry!O{LmgLX~Ip(Y+oB 6w.]&5[--O"DCd"9R>\Um7n౸ L=/gBX#~: _oW_E[zp(G,24r#b+#dx}?Ƿ5։=YZY@ vB)b@V{gsdkp.ı}P}ϸAj?Ús yqDk]%EPfYCiAs )&ӶMu,j|9 .}꺒ėԫ!'uPd=꿆~{7]hiYghUQcS#VIO7<8Y|ExŖ2Poo'"ixuބ=/ļz}&`{']#(-N1ݳnF3ȵMbZo,4++ Xd2L=)VޛsJFj}GmB1oFqQZ|Ŏ-'vB ,aJeO1TaWO?? `?ݖ6{6ipj&L6Q!9U+J$ ,&7z4SKm4rRp<.*r{~xb bc ř7" !l,pEnxkk}.KQZk 3cq{riwu }?h'O G},I3\\DD@sI9 5Y~ C@KiM4$+F=?-í3KKPIiV7Sb pkOȵ2=b{h[K:=H6N9U!CFqڞi\ͩB%O #o8)#}q\KÚ5hF#nbEVfD5,*0*vM!]3;m|exNmaQ) !s V_6mZ6v}zy=Ć0ǾU$IbKπ,M@A%(ڑ0sE&#bTm\]R?p6^Zqӎjݛ]7ev?EYռW.k+$r#G"9V+6JgwO"tb 5w2i>c,T,8]I[ZCbF{0n u Ȕǂ11T&i{<Y 4É,Z&ZB'dbJ8灅|OkF]F_e ss{2WlحA8s[_Ld\UpKY_q_F#t ٠W;D%۹fj|=@5јH/&Xܹ$ᔩ`A;$J>bi_~}M;M֞,F8DVmq3Aܓ!SsSIBZ7G}$NbBީqki;i Jg,Hry9VQTҤ0Mw""۴Q!߹py{jb%.%Ju[>dgKU"($WA'-/!dH ]mI 0G'4_Oea]xyvOEZVq(AM?PltAiq>l#gbvw"m6O9 ?<1 oH9I*HV Ρ@#T<;gi{J[[n/gk<ؑc$%~.72uNu{izWbim" a]N('3C"Yj=F-m yY27.&W'-2Ϫ[],M缶HbXO cER$g,m/EڽSB.w!9$niâ+ Zf6.vS &ʶ9!~Zi\^ǭ{sj,}I6C%e,8SiCun9#6TJ dQ`NsY|𽾩ݭ2:"UW1& p8-k:o_aEPEPEPEPEPEPEPEPEPEP]Ɠ oW]Ɠ oP( {HoM?:k>6o~U(M[߱dϵV( 6o~Qk>X+dϵGM[߱bk>6o~U(M[߱dϵV( 6o~Qk>X+dϵGM[߱bk>6o~U(M[߱dϵV( 6o~Qk>X+dϵGM[߱bk>6o~U(M[߱dϵV( 6o~Qk>X+dϵGM[߱bk>6o~U(M[߱dϵV( 6o~Qk>X+dϵGM[߱bk>6o~U(M[߱dϵV( 6o~Qk>X+dϵGM[߱bk>6o~U(M[߱dϵV( 6o~Qk>X+dϵGM[߱bk>6o~U(M[߱dϵV( 6o~Qk>X+dϵGM[߱bk>6o~U(M[߱dϵV( 6o~Qk>X+dϵGM[߱bk>6o~U(M[߱dϵV( 6o~Qk>X+dϵGM[߱bk>6o~U(M[߱dϵV( 6o~Qk>X+dϵGM[߱bk>6o~U(M[߱dϵV( 6o~Qk>X+dϵS,`*`KEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEw64HvBA㨨n5߻3GMտoCѼ=zZNswvr?8VR2]q5y|r.8`amea-X9Ci7~Ѩ}CQ<#_-VM]`6D / @EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPgMտoN((postfixadmin-2.3.7/DOCUMENTS/screenshots/postfixadmin-admin-create-alias.jpg0000664000175000017620000020362510676263533027030 0ustar davidpalepurpleJFIFPhotoshop 3.08BIMICC_PROFILEapplmntrRGB XYZ  :acspAPPL-applrXYZ,gXYZ@bXYZTwtpthchad|,rTRCgTRCbTRCvcgtndin>desc,ddscmmmod(cprt-XYZ q0DeXYZ a)(XYZ #XYZ Rsf32 B&lcurvcurvcurvvcgtu ! ! > %&s "]#%Q&(@)+5,-/V02635 6}79M:;=L>@AeBDEzFH6IYJLMXNPQ]RTUTVWY9Z|[\^_+`Wa~bcdf g/hTijklno7pTqorstuwx(yIze{{|}~݀.>N^oȑҒד۔ŢfJ-ǩ`=ϯyN$дn@޸wB ּc)t7¼y6ůl)Ȧ^ˉBͮdЍBҠEԅ$dקGي.wܿd ޭSNMSc{1S ?i5yS&r:c ] ;p!AL!Y"$S%'I(*2+-./1[24(568C9:@1ABDEUFGI0JmKLN'OhPQS T[UVXY=Zm[\]_`(aJbfcdefgij4kTlrmnopqrtuv'w:xOy\zf{z|}~~pdYQG<2&ݜɝa<٣nI&{U.°rK'ص`6 ⺴c6 ݿU%ēe7ȡo> ̞i5Й] ӐBի_}0ڛPܼr(ߑEi @gHq)YCw4n,b Zk-@[v "(.<R^T !"%#5$;%C&O'Y(`)V*+,-./01233456789:;<=>?@A}BmCXDIE8F$GGHIJKLM{NjOXPCQ+RRSTUVWXgYXZ:[\\]^_`sa[b:ccdefgphRi,jjklm{nRo)ppqrsltAuuvwxryKz'{{|}~jH&߃{\<ΊgAҐ_:ǖvQ+ڛe<꠿qL%Ҧ[0۫i?ݱdB͸zO"ǽtL$®ÎnO4! %Cfҏӻ@׊T݉ +efK~ndin6WeM((!GP T93G*6DSdu6Ro>e?l/a@6s7yL 9 % v  s x , ] O^?#"2Hj'U![ !I!"#A#$%R&&'g(()*R++,-a.)./01`2333456w7Z8>9"::;<=>?@ABCDEFGHIJLMUNOPR9STVW^XZ[X\^_`bTceGfh@ikQlnvpqsXuvxiz{}}L҈{ohtܝ9F]Ű$Xx<ŘN̫UӪGڕ޻ Q8i92y $/;HWgw)D`}$JpAn2e C}8wEh  S O Z  p / c4 yY@/"%3Ie$X*i  [!!"d##$%7%&'d(&()*v+E, ,-./Z061123456y7l8_9Q:D;8<:=;>ĸ:ˆeԳG۟IQW"\  /BWoBk(^"a+psn"}< ,  o S = 3 ahx I|ko$O F !k";# #$%&q'G(-))*+,-./012345678:;<:=]>?@AC%D\EFGI7JmKLNOOPQSTOUVX+YtZ\]s^`)abdSeghikllnXoqSrtNuw[xzk{}$L߅yZ[V R򜋞B𡥣b)lEõpM羵u'ň3fqQԽeضE}ݍނߟ sX(zX5Z"desc Color LCDmluc itITfrFRBnbNOesES,fiFI>ptPTNzhTWfjaJPtnlNLdeDEkoKR enUSsvSEdaDKzhCN LCD coloricran cristaux liquides couleurFarge-LCDLCD colorVri-LCDLCD colorido_irmfvoy:Vh000 LCDKleuren-LCDFarb-LCD LCDColor LCDFrg-LCDLCD-farveskrm_ir LCDmmod*MrtextCopyright Apple Computer, Inc., 2005C      C  _" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?!~|ܾ.E^]LIGގ9*|‡z|e-lj6v7I0°ޯbcI^F,\u h߶fiNQR %eO0!H`ߒƶl]{m-ҿoϧWWiRjIGk`zKh ʪ3b[> x94BX讂4ewb)oBT:͞濠[8Viw8:ƞ1I6MY*>Z3 v7G-+OV>˦cE %6R} ,eKNV۱vW'+|WoW4P.q˜\˯yu_F,ZkYk V!i  93o/w?&e^_U1$mY$A [!xj%nۭ陸&>}Z/3{z{+Ify.D'8c3>(|8|MhZk|1O̍%]UH "[?<%:fk }7eY 1Vbc` pj5Ki} oWϴ; Kq=nom'o xK?Xi171\mT7s #?&T ,cv=τ7Þ;Ҵ|Gn#{in(ܖYCle`+ɯM_ϝusgʼn<$#%fg]۲AxwYxt/Cn&7W~V#;듛ڿlF4OoMAec$Bpy$6{_i%xw-^=}ߕ/򴞾Og=&?Ufexa9k:^ $; !oWLSh܏+sa)[~$xP~>e@Bc5ddY$vqA YKjQ]o[ҟڳu~ڗG?s>!q WOko.yF۰0bc?d$M4?zޟs$z -;[nV;mت.&/;9_RW_.?ڗELEKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKw\o7kkj6BCIܰ"(bVq[^x#U&}/òhi[jmY%?"/13`(@xGc+c>$xi>HGF;MCMӧW(ˁ!I$ >8ω<7Gmx^kwHJ9dSta ĸ>P$)mo> S׵y} x-]2V jJ[+ Р|3|,񕿞ۥq}{v 62qN*׉ax~HRy7 1^E|Uؿ hWue/vQn.5].TVQbHqҽHHHHHHHHHH"4ۋǎ࠲^9]Xt-^A0 qJQ hj~%Լ|Z<qW5lsc3*̬WEK a$_F[ ]q%br,uvX9r~G_?f_:ǿ߅.zEkxK?+ϳy[Eh䕷M"~ sL۫ICC٫.#,Рm'V״k% OHe 8 ucǧx&ݢC$pC#1@5Ϻ0Ymd-}Se7˻o@jrkOk |[7&jOfůd7(.&KC'ڸQx>ms/W.m}Z-7Fx-2H@O~ڟX(_UVkx6ԣt :^$Uпl |?~b}/) t4Sٲ+BA)8k=>%Ė?w i-iv/[A5b2~!?io_iW?|Ѽex=WZ._vməi~DFA@2?o%w ~[}CL%3O tg.Ȍ13|e?k[juϷ¶!Ug&їI‚OEe<>ٗ㷄>!q? X;Iu9Oq3CF{ͮZ<('|lo_|2xWhWשQZ}g%٦Kyn7HAkOڻ i]/GO]7ow8kUK{ 3X'OhVY1kvx!$E"w)=wkCV>w_/tolwp1|yOs_>}۝Sɧޮˈ h 2/D#r;{wSioſʀ1>-~ן>j<;e y%hpI@~/g[o ClY0'xckW|@=cGhh~ؚ/'vgӼY}3T%1}Ύe/G9\8o ARf/+{o'W4ݟ*?m9 Q]h!g/qwE~?n1 {Gu 6V]RKr@aN̠8Hn߉'o>Vzyfk Z]Zg\ªC(s=A"xSK,g_5E_PQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@|!dNֻӋ :cZN/@So$_ sfը m$_cLڵs?/%ZM}ukzy5kk`uI0A*oH_xK ;ɨ;E:u;6VQ5ظu[xe}GH`/?1Njw5b|govJ_0bE||F04#n<9wq\vRG|f!BWƏL7|U *H6Tj٥uAkiܕ67o!x:Co+OYm#zu)vGZ{;ÿ>9x3wOτЮ!qd.nmB٘^K,kAPJ)Whߊ/v`$C[-HnxxyG,p]~moi:n`=;} d:d.Mg&MQK ?1^˭t:{mKLOo#!]> om~վ"jڦxRjwNOr[l*8]?>?}ڣ'_mƾ$}|ɷҡRIdle<d˓:(((((((((((((((((((((((((((((((((((((((((((+ 'Zt^d0Oiqz"Wc6ESo$_ sfը((!m9pl >+YčV> Acآ=?G|eq">¢=?G|eq">¢=?G|eq">¢=?G|eq">¢{O7 o2ki?7_umwnw'Ny+q_) ]N( w_(w>( w_(w>( w_(w>( Wϋ_;{>P^H'dR鵗keA<^C|IVgx X6o0XeC: vWǿ2CG(P?}}PTWǿ2CG(P?}}PTWǿ2CG(P?}}PTWǿ2CG(P?}}PTW~?mM{?g&nmo=c<+TzE$ I)/%*r'P_ŽEE2C@aQ_ŽEE2C@aQ_ŽEE2C@aQ_ŽEE}UTm˃g\iZ$hl/̸bG#P(P?}}Q ;/;_(P?}}Q ;/;_(P?}}Q ;/;_(P?}}Q ;/;_(P?}}Q ;/;_Tm˃g\iZ$hl/̸bG#Wʿ2C@aQ_ŽEE2C@aQ_ŽEE2C@aQ_ŽEE2C@aQ_ŽEE2C@aQX,othv#7oF*ơs|͖s| ;/;_(P?}}Q ;/;_(P?}}Q ;/;_(P?}}Q ;/;_σ4w>#}o-ZOȥk.ʂ0x9懬6eQm+W=4l<`ʆu:(G|eq"QG|eq"QG|eq"QG|eq"QG|eq">|C yn:xE.YvT4U||&լ-jy?gY&PÎC_6ŽEE}E|{ ;/;_ŽEE}E|{ ;/;_ŽEE}E|WĿ Zo~ xmWHEjSs $ኞzc=E}#@Q@Q@|!dNֻӋ :cZN/@So$_ sfը m$_cLڵQ@Q@Wտs\Uo\'F8z( ( ( (:f66Um!Xm@QEQEQEQEX+m]Swm8;&kn4~u-MTZHgp4ʭ}_3\/xΝV)p]M,H$EBNTp[%hOx{He2MGH`ܙis>ЁnMe}|`uKkoKK;9o+o=ĠM`O +)0wum^G@On`  =I}s隓=4(Moq,#2 WAȌXa>S?Vt]cűuZS&'tfo%cV###5wŸ.)5߇+WM[ )5DjhrNfEwew5\?3 m{ّD^^z!D9s.Bcmkdo9*7+o$oyᏌ?~lXﭵhgF#<Ŵ:FXυʀXFXAcLjC{M;crmהc|HBB9'8M][Uމe$"=o]E:ݰ9򊟔}TgPmC_XK=N)W O2֚ \[ZXfG NHS )?{.m&"gJkvz֟=ťO )xJco5xWXl-ZFGX.,{vn$#vy3F;W@m.<]B[G@:Kǿt,t[Ҭ<5"[4E@_b|Ż3ɻ_yOuۯ][Ԟs:/u'/b+F*:0(`dMOX^[_4uCȨq MˍwTUP|ekz-7fnf!no W׆-rYif{h0Y$[y?QF~NZ۟ ^xUӴK9W0RVel`[ ?o [Ej#ZlM@0M.0w8ָ ~}`Mϫi7&-+C69t1# %έmT]Nn,MR lhı19 ګEoUiN;v_#x7zn`,k4nK(#;4AQPo;F,Yb̩9n)F7&ZGϴ @[SY~#uRŚRElq(&tX,c 8O ]i)[ pn帊{k} TfLf66Um!XmLlh)a1Ң#ԚjXgIHfXWFXJ{}o:]Ӵr98|jm0*L7?ki"iSJGF=}xǷov9湿Ij5Υ#.I"kP l@:~?~@K/Tw7?%gi%ƹh񥜆\1BlVٕ+pF@0koD]dr}̶sf$s## Ƽ_^GxmmY {kqJ"/(OpQFpdGÿV?t9/H7&ǼWi%''iᕷߧĞ' a|m==kđi4*ƁWtXW$&?(<2N-ŅP0}Ϳ6ݙ}kf|:3y*k=ƙ"hOo*M,!*#5~ ĚUAlDa>-n.1/dS?rah߯<9+.GdpRE 2 r+5o\'F?r௄mf]]ܮPK7咁 RTHpտs\oF~wcBotMp_h#dM< Bqj//F:6w6tqy6D_*' Rt2@nỶ#l69?w#!躼SY:oika6Hœ) 63e7a'F:k1%T.#+#FFs[~o^Gw-$Q'3W]V֓;}n/G/NE 62G1f}Y>|![2}G7qJe*E ]NDp`睙*[_勵ߊ=i/i:xcNi:Eն{iW ]=+ B@$}'㏅jLdС6%İW )]w"1aN8fZUuֵkNOҼs3[љwX ~W4ע~ԯ5]6l6\`V[!"}m";yߍCko4׀gj#"C;s".\͊׾  s?#~ÿ>gvss*#e,E{ٛt*fmL3 K}{=XxFU_vzUZqs<\40176iA徭+Xܖ6+edpYYYJkoYƧu'ޚg|~ EWө^/o.df2s۞qJ7֋M*?51]д'F\7g$pO,0wdM[AW?)u ݵϐo_Bו3f.~(^5^67qiee`IUeVb2rG]x{a-{2E>h ۜ7gcdvko[gy_OVm\ /x uliIw(YQK`{`{'AV??C.L E;!Ø)s*eHȖV_ןȸ;m,aዽ5[&sp֓vHRIPx[5-3]xeSd̒|>g5~VZ֯4u%MY昼#$pa-gmvu=U6; 1٭mѸiݷnonJZjv_"?_kB :.+bBUeb A$`t':idI3o]Z8fk{U 2r+k}C¶ЗYUcy7Oq4o7g_nw 5{#q%1K,"yJB^Re'CJv.Oa[Nw-X!:v4\\4 qdif_PKos%@Y6: ndσ4 II{0]-DѬS a84 LԼ.sI>hmm٠ t_,&Ny%~z/ +kZ~mDe%4LіVV WeOЅp 37X7O-Y8>`jcK h-'2Iax 7*kpk [m^dx~^gtdEː]4[L 5բ5wgZFډf (嘞#O'\߆{mO~?;-O_U_jk'᯲KTf;50m!O<#,78y KwRְ#LotGK8Wʩ'Qn%B.ί%4exSO)c%;w_6z:io0K &5%[qأpRm=?_4~KGJU"כI[loy;F#094Y5ugky/N-7C9?;WfB9Fm/+h쬴ҿs)Ķt7vT?3i u{e4[h-kAo$b[ǵ:C`yw/3ѧ'N+˛}PLm.eLnQcafPHi^L."hrJuk|1)ׂ3{ɴ$0y-XդJ@#_e} v=b~-կ"F0fMshd  uV -C N-jL!O6M pOGq]p&c 9aT,A=fǩ⩍QH(_?uLk] C֝1w )/93jQ6E1mZʊ((q9 "81O1  ?  آ1  ?  آ1  ?  آ1  ?  آ):$Z?fgq}3TVU2OqW Bm?Bm?¶+יwq!6G!6_5Wgh >wq!6G!6_5Wgh >wq-HrѰa9I<3 ^Jg3?3G.?g)f'w?  ?  3?3G.?g)f'w?  ?  3?3G.?g)f'w?  ?  3?3G.?g)f'w?  ?  3?3G.?g)f'w4-3Hf3>ޙxz ZIrҫ*H'q?O4Wghwpoa;S_q}_q}q?O4Wghwpoa;S_q}_q}q?O4Wghwpoa;S_q}_q}q?O4Wghwpoa;S_q}[ͼHY\[3?3G.?g)f'w?  ?  3?3G.?g)f'w?  ?  3?3G.?g)f'w?  ?  3?3G.?g)f'w?  ?  3?3G.?g)f'w?  ?  3?3G.?g)f'wn 6G!!dRpF++_q}q?O4Wghwpoa;S_q}_q}q?O4Wghwpoa;S_q}_q}q?O4Wghwpoa;S_q}_q}q?O4Wghwpoa;S_q}_q}q?O4Wghwpoa;mnIX(\&z\C+\~*SUA?N>&z\C(&z\C+\~*SUA?N>&z\C(&z\C+\~*SUA?N>&z\C(&z\C+\~*SUA?N>IZ6 2>~5Gr_+׃_,Wgh >wq!6G!6_5Wgh >wq!6G!6_5Wgh >wq!6G!6_5Wgk?f/54=}ۘO١?vk=+ tۿц(bC?  ?  آ#1  }-HrѰa9Z($m|d^fk=.?Eck=.?k=.?Eck=.?k=.?Efx^NIy&pr1ZTQ@Q@Q@|!dNֻӋ :cZN/@So$_ sfը m$_cLڵQ@Q@Q@Q@Q@Q@Q@Q@|KPWU|KPWUgU>_<ΧGEWQEQEQEQEQEQEߵO>4iZVK/py$)Gd:x,.ܪޒB(q 骱u~tt]5;׽m/mms'V?l3Mkj-*]\. H#$ g ݝdx{ K>1RNGpȁ%$0 x[J*_Zxo$12(P%y'4~_?~/A_ ^awmkVW7mݫ꒒]ok]5x{^Z׵4<{u[4Ok&+A3.$IkSH"G/DcR𶳠[iVWrxxbb@A,Xa?x+S >U5k4AaXtQi+{{zmbpQ뷡?ď:&ohE,hݒcG 6 9oE玸|uZYMwźw+ѬmaI3;*gw?்7Z =xJꮤ6Qϙ<```Pnh OKwig<ٞO{ߏsҼ?0hņ|?kwfϷ_3/7e'-n8o)7nl@|a=zKƅ&?2q|㚒oVZUΪu6kyfo /`IqNHMB]R՗US𝦥{oC z#c+ez7)xW-짎M"e}7`*Q{]M}k);iutM[fđx>+/5D K(W~۾{O @5t{]FKObmodcO4|rKgmA{Px|G,]s`jDž׊4 |P_FH}86%eJGZJrm]SҲ; a.`wf]1mO`%s~y5Ow~i?4&kib;_-q`/j?9YO|s _r,rY|J]XmV(Q/}BR$w|œvwI:#畴G˿7Ή5=7=j7:m$1P\N8;Կ*x?z#P4^o?S>(S#V_6}sg{o\ *,xmK%8oz7ngjo ^EqB։) % uۻ?mȧLO?JWİ.|kz]xr_i4 &i`q[̟[S7*_;q}`o8H٩7[ߗE;o !dd^Vx89 G[ GS|N? x;ÚM学fơ0{9`Hk-%څSIŽiyc`27k'._|_>EncbJVAW I<,wkuvZj ¬~tۚ~|?POCO>%Ҽ_xV+{#SVQg8"2d*gdq]:l:; .tUkVЊ̖V8X搡;泼K$i3ռU+M4jqVO E4 ܸw_= t//;ؼ|ϕpSZ(mwʌp\?ܿM]}]in{xW=2]5=7MW s|HlH 9[lֺr`-MoMm+H;YPsC|alm; k+|#O!7f_`dwyt^[ß[^?=׌58SUf%Wf@ڹqQK~&"4ozOM4<ߡEsQ@Q@Q@Q@Q@Q@z!sz/C7ukўEQE}EPEPEPEPEPEPEP_/`:Ӧ?|!dNֻӋoI¿j("Wc6E}eEPEPEPEPEPEPEPEP^;vj])`[oO$ogc`F$*/__|DKD}HZh[OPs/ :[AsrGo!#E*u|.{uVN3*k^s Wşÿ7Wşÿ7훤4&cir{nKH.-çMu$pjqYcB1wUu? Çd$"Ch!KBO4,\s\O"gK]zˣiӿcT4z:g Q WWy㿊߁|>6yukSK_nG2>t}b`l2?緇2o1Y>2'L|YK(.5aby,|Um?|F'!k?g4~Nmʞ[!_s-L<ߖτ_UQx{g/*+ۗ t>iuᄘx}XN__[E's'$|=yjk{Gq,~QHo_m}ߧ~6y^ <LE\_E}C|d#>*Jk"5/!ؠl݀ 80+xcG|MvO>&[ϧ=:=E3qy^ ?0_ظ?>:=E3qy^ ?0_ظ?>:=E3qy^ ?0_ظ?>:=E3qy^ ?0_ظ?>:=E3qy^ ?0_ظ?>Hτl|kAx7 5mJwie5]YƑl*8Oj|Y=;P~?uJϿbWşÿ7Wşÿ7>a3_e_odbWF-R[Vr"*<+gg<ԚBW!$ظ%.a3o+S>WG)}^|Cu}Go;/ge#qK2JQ'w%Xf@; SD>յcYJdXnD.a,mV188?pM_{.}/ӿs_+S>WG)|1S1kx;75ojw igYSGr˓*85owǎn'-3=L!%&m O{{=}ebZz<+τ_UQx{g/*+kڷuĽ7w<54'WÑ4Q[<<ʪJ ~7|M_Nj |=ßSuȳaKFP lԬ+SK0JjMi~їݣLE\_EW|"®/"?tO|CXAk6waiQZ_B+$3FJHrI ~ |cY~"Zχby_ַ2+ŢHeU.ؘ+oנMjOWgW|"®/"+S>W_C|7dCwOSkufuUgM(UgM+(ϿbWşÿ7Wşÿ7>a3_e_odbe_odbL_.}/ϝ|Y=;?|Y=;*?0_ظ?>uUgM(UgM+(ϿbWşÿ7g=[ᆧ}/$ӟAX&<'v\z{6跭n ?iJ~f2>|gVX+ ( ( ( ( ( ( ( C֝1w+ 'Zt^3H?ͫQGI¿j(*( ( ( ( ( ( ( (  U&?wJl%>>{w?qiͧǡIw;@p j[_.Z_ j>!x4լgl,N739Jn@ EnNO^|m.m5;Nov^JzY[[&|Ӻ+'Ii&A. ^ͤs+]0Dj(VQVP|m+ᾑg×~0קt+[ԱZow谼bFt X q5y'%?#}>~ygNsv㚙TٗNnw_Jy jo ^ |A +J5[1$,Ay C-/į\mnmٚצKH]y lA V.WU,֤Vܺ|-ݯbm>2VZ$KK->b[7_=_|,uumf_(3- S-w|> o~4QcWVu |:}ĂHd}Yt] 篮iJ. ihgugW j/K~6iW7^ޡH;Ka`Fv+Ľ>-Ӽkڒ4$m-Ϛdy>s3\eYu!iʛwwwjMvsMkV8+md7JoQ3|1G_= U#[?ߊ Ğ!]߅_ Xޓ4V rbKO 4Qq51HҫxG\eYuU*: 38*O${p?G\eeExG\eYtW]p?@E|sYB3ŭ6{x!nxRyoujx C.WU,?w.;ϋP~?uJ4/_Z gBel9g^gwmjz(+k FI׼s4->!PbF ⠐3z+,~hOzM&QAI\Iq(FLf gU`jӨN3[WÿŨ|oKW<}_hI/7#"[ mZ}iiK"DE ?WM|Yq}-)_{_wVZǎt-w1q,pz}l.wZ2jW?AEOǟ T^ ]ZMrg$J\mJJ1KHG''_ii?:慬кOJ]P]GHm)!`{XG2Yu&Fc}[ 7m^ŅEu>c}5x1kVBdj[?4_WQ Ty/+O. n[.ﱷ.YfVO;dhIQs/k׿hn~-.LZ^iu)LQQ%E,ϛo  M;WW|KM]&WWf"I"E`Z'ھ%gį[Zy| <;cMry5c?4_WV4Fbckҍ&ѫITW,)[^YҫɴI]? uxCM?G^=K:|Eynf.%Of73Hm__wSL^xR~A Eմټ?ѢKͼ*n̦yL֨T.w} Ty/+E*~<Ms^ә=I]tJnR[s|w~]c(|P+:| |W{G>Y[{(?2&d}7#2d9B|!XAEOǟ WA5k;ߌ8ͧaV9bEfln!TBVԕInxN*+~J>9<a|F$O=.܈٬t--dk8.ʿ꡷Fo5oƋ%~<_Erf}Uׇ~]jז7層2$F88mK3ỵ(((((((*|SެU{EX((((((((d0Oiqz_?uLk]7 m$_cLڵM|+V>((((((((7|Q5换j'м'>x*WFCźT#[1"<ߔʼҾv_$r5ΙC1tpcimcWPVRC4ooQ[~6#(Iy)'_/|yM NEtVDΥy?`i'K_ZL}?5mhGM~?hǜh]oލەZھo+%V4>.bf=t ?׷d[mQ)wWeg_Nv _aƚM2m 8yVi$C?1<$09y֩7lqd>S}Pkkj,j]50}5?FNy~~F7n6M_NVNjTKeW>^ _y K61t G[[>"'7[[K=ۻ[H+6ORǯ?n>K*/ xrOLZ޸7$ZqW||Q|)ߋWm|1񥌚nmKr%q#'o4b +8s5k{@x~m:|?v)mFHf!_NVkUP&8_ Go| V~lP\@tyP2p"MjZysF}W3nɫh5mt.kʣ]4KV?g*io.?T%?+jLAe{e qA4o9 5-O^;EWzqj?jdIVS$,EDh7fspPicg)h 4UKΟ|EK —E#>L#*|͂x?U=-KWG—6,t+DѼ%5$IuqyuL hl (bϭ~~)]Ŀ#/|ObM&[A?<:6۱eeךx&Ōz&?gzVᏊ:߄kX M6;v3C RQzZƕϷ6mkeromek{'Ro+%V4>.bf=t ?׷d[mQ)wZO e3:7|a'_~7m7oq!H43mycY|9J_jxKWfIc:ۿl#C6c /<#s?%^~?[</SMUi^T$k1N*Rݷjwihk/Knj</<;xAwxU4кV+A+.k 7l5j4NJAx ).2/A[cDe+( ?৾?.*h6>2.4{>ћXD4(QU2C*s}^?O{?-1B>[S>ySsLx.fRp!]ti.wזOUQim徺;>&䮚WG 3 } O6-πt;öQ\j!Ǘ%pX/1$H{?߄ -B? ľ,?FiCH5 Bte` ̍36a g^o  kW=S]jWw_7xծ;g~Ýax y{KJ>h6E|'5{$&hΰ]O<DGIT}+>9>%Eᯆv:6_ͧK7;;o";YΤGG^t?S$i^ dE侑&cV<0ډ?aKo~#kt]OЭE^\yIďuq;K1-U9.ɺ{_zm(߯~k-xৎ?hO |>^ W-Ɖ0MeK+| _|p?j MIlm&x'TG k"}6I5WVCwc0~ӀۈfH_0t&O4:]4] ~QsnN-I+1@ZS\RN-/WOw%)umGv潮hi{O 6xVtH^_^ ;EkYO$QN 2Xx?'O jgƗ%gM4[JEu/Ij{+Hdi: ?cּEqCu^im",s6{21hBf”;&^x^Rҵ~8OibtmM;aF7|Ĝao?v뾷Oɭrͻs_Xzk$5/ ;5MCY{{{Ć+XIhhĒ~?R A+;WZoo ;1k[/Gt5 >ŌIu-YF+:p_v!񽟉S⟃|M'|3jShxmlpZbv1^8c_%M:xJ >};Xִj`c%x⸍9f=(׃~qv{]rsvnVM(N\G~_Ǘ|vfۿ@&B]cvn쮍ͺۺ̒UE )Vn;Y~9wšͿ/~!׎uY1x/Z˦N_-xdMBH嵚yuk;BlmD{|[n~շ s_x^Q*~ Gs%]9tu=KM+I]E:e݈dk|[Ჿ|r˛|}LVo_i{_յKÚFϧ wkwe{{H`2נ~_#5xvz KjU^Iy+*Z?`;ʼnu!i}_P#?JCCifBnh@~_Vth DtO \Mj&m\k0Kgs$ܫ=*$>B;-zYg)]>vo{CᗁivkZk5Mnu{nml䵒u K5i&6Q$_*4)A'jz޷]+2I֓s@tId o/i_*/; t??<czֻ-ɴn-wc5&X--[$@vv~A|'Ak_|WWKmnb"N1;_޳v|utEu ~o?aڻĿ/=<hMZ[KTVK(M=`w1q$rq1_VK_mW$>!I|X;kTV,CRgBYПm%'WxwHž֏&`pA%-$1*aZs,'t?:g9{_>2xkSFwYE{+"v}-XFL Vo-%ddo˯-r^m_KH$sW2mCÞ-.xMŭK,NcBQԕ`t k~Z? 3|SaxJmCbʹtu2Ҥk9Tn]V35}z|(U{EXi]OzEPEPEPEPEPEPEPEP_/`:Ӧ?|!dNֻӋoI¿j("Wc6E}eEPEPEPEPEPEPEPEPUo'j_ a)j? A+ ]sT<jl.ʉ,ȒjDLv4fd$nm7˭ݼyz}OUo(ړÿ4/_x_|xė4.t&PI>GyG19o_|r xZw6Z=Ʃo.-iyl^O!D#iY!nc/iڿ{OJ^4ȅ$vt&t~_|3?› i>|As9K A"mI/bW,cNZNۃWX<;O𭇀#x-_^Eh2lXJڗ2j]1kcE&Zi.{~)~ߪiO'^о"|Atv)DouHP$R3 }k5|i\_VKwOH nH5Ӕy[LNJ7FJ%]Kew!NTѹG]hUFA k_/fo1@O:?ᖾ9'-?_ n(ZcD t-|1sOZk ρ?Ai뻢8Oe?N| O7G2'>?ᖾ9'-?_ n(ZcD t-|1sOZk ρ?Ai뻢8Oe?N| O7G2'>3  i:&Hx)V" eʳ$w(((((((((((((((((i]OzUb((((((((_?uLk] C֝1w )/93jQ6E1mZʊ((((((((i1m}48k{"><,lo1w`IdzY?cQǟ|Gbh_9FmVvwE,L|$sbTSo+|qmǿˆ{x%sxceBu_֖wwַ2tZG?Z.kj ]CT4!9 D6bBn9>~ ~x\W<1 WW_jW%`nNO5Q m/^ ~xGMí#K4-,46;[KPmH04P ( [Dr >h ?kVw_oin_s0@Afnm2sRQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@9x}yheٛp8+q@P_-]x665C `Dw$Eǀ3hz6*){HcGRHwh\x{:7Em? @6&Kf-̣1-+F(?\x{:7E4W~-áZDs%Ky$(8jz((((((((((((*|SެU{EX((((((((d0Oiqz_?uLk]7 m$_cLڵM|+V>((((((((g{7uF5Xg{7uF5X(((((((((((((~2o^ߵ,#߅v#G̯n dB!IIT~t_~0uOZDI',F"}\n? ''}~7}cxi-"}zK(&gFoT"" 31WĉG>>MÂ-g+,!M:#>>~*1Gi$4ovxu2]7>/RjAA+nwNkcvH:%ψ^6EAkv>-o4I"ydt9R ;NAVAq@O=}hm?<Ӵ{_m?HiWu*I b??iG+3T<?e_wj:׵-&XIe-e48rcpAO7S>_QwpwCPm?oV*|Sހ,QEQEQEQEQEQEQEQEW'Nk8}A_/`:Ӧ?6E1mZ?H?ͫQ@YQEQEQEQEQEQEQEQEU}3=U}3=,QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEU{EXi]OzEPEPEPEPEPEPEPEP_/`:Ӧ?|!dNֻӋoI¿j("Wc6E}eEPEPEPEPEPEPEPEP\N˛{'Pps*~nQz|1QPU O O= O O= O O= O O= O O= O O= O O= O O=#d@8Py'hy'k?_hU[O_\x[xSswgqZ\jQn6"4i;Xzgx{n^߅bV+gm{3oq+ɻKy]F_%򗝣'l?}Cko|ko|fx?_<{sL@ Z],V]ZMV< f1S%_*'[m==nSӠx1"\3lP4~\gߛIwz-F[~7oWW&_?G&_?_$ZTzϏ xxgkA?o6tmZ[T^&{wq:&g'|5|7-k7:)hOcZ3H^`UќƳɀ7e٧grN[^yj[;?n} O O?W/|8l&tYnc doۻ]:FxRK3So$-ߜ-}2܇k[1D衐E9+?؆{iz7&_?G&_?_1|Qx/]|&:Nm+JդZ7CYJٛ~R/?Ɲ/V ck!ռ%x4[_Mkϴ١[:VB2f"q5rnK~)'>cko|ko|j GUĿ2YMc htU*kd\mn2wlVO?/@χ$n Ă"P_=cOM)yB-RuwKjp\~?f} O OϟTy{7iac]-cݣ5귐줮ڊHګCx77ZoK*5EC,̖W[(4nޣ—4'7dؙ.U46v?6vOm_M?>FṡJu94-i(- 2oP)' ~o^(ҴZK%onSt1ߝDoݙ+\/MJj^/>޽-܎e)ZӭNmu<4mu<5OO[u'Ǘ/\$Hڍ-wr\2$ƅeDD|%U⯃7Skvw~4R}rn)V+PNQ,qEI9)&U綾R潜eݯ՟fmu<4mu<5|'߇Z.?xZK\5ݱWeypw+++ t4MI]];];cHf&_?G&_?XP&_?G&_?XP&_?G&_?XP&_?G&_?XP&_?G&_?XP&_?G&_?XP&_?Uܾ'-Z;.␅;=s3T*^Eu@EPEPEPEPEPEPEPEP_/`:Ӧ?|!dNֻӋoI¿j("Wc6E}eEPEPEPEPEPEPEPEP^[-J5 ?[5iQEQEQEQEU4-ck|22:j~[!5(=DzK෉|uO|C<;'y_&UHqF#zYuӯV\5;俉E~u߶o7/ٿŗMS H/uŰt:lVw"sk8*vW39a?|yO_677l{n$2caYg-h?:X m$MjE<_A,1,na7X U(rj?zV*iY.)-u{+0i!xǾ>{6z_#,܋9"iA-A!I;P>.|W}!ӯQw[}V+SQѵYi5tcEܙdE($۾l?mOx𮓯|PX>Oh>+QaK W0·~ɥqu4jt;;)%uO<1o}kUaN2jZڔۡx.f1@$Bݦ׬o-ۦ>9ž^5:_ k?;S/?Bɒ(Kh g5M CN>l.| q3M+Mbo+-DMh/E0 ʤtƿf/N&?W s߅-6.n5`Φg;_ߌ> ~w3|) /9-}.&XĒ&4% H%C{qXYS<:3Mm%MwZ$}r6֍3G>?b;6> Ѵ}ZDRTqWsIčsq;K1-\/)KZޱx_'ω}}5mV1k)"o 4pP:o>2^5~ Yum̾ ~!jrhKQ5]^KfH/+C Ցis|Cf F?Ҿ |PԆI{j:m$(R$A!IH)&\[NRZ'\)75B*w^ZK媺nC/7xi]jhVӵ=2THݤGO2)]Ya-<3 9(h>i%SYմ魞&WVkH`r%]_s>aimŖwUt,ZahĂIW{N]g߉Wįx}>ޥhd=֛u^~,nn )X^~OjtV)J7/e'tMN&;@}pxU>Z3tH-Hn#lmMDKs߱kiz?~%DԼiw:\f)y,l-ѣ ܝkHWaK#>|oY?t-^4TΩ3myb{Ebͨܒ2$\k| k/WI9o5u+>9QwK :K߱K"4yp#")V?7 ѢMxoGѴxEn:tKTҤkk orM67'XGh|sFGE@u/l&ѯ_\ak p&423|HW<@|_G[u㻯-/6ao`hD.ջFB) [tN^ٻY+yIJ\ME(KnJտ#|;ޥjԦ--BŢ}"e1xҽݒMߦ/+z-7T*Kwz?iOdڌi=L){j?Sy~ V|?^i>Ȯ 2%\#>8k:u/5K GXME2#xCL'ɡF~,Kvis$h4d!+}2OlK;"[_OW,4K}Ok.s_ 8Ef_5.𖍩aֿ+_c8W2ڀvoE~+㟇?|]涵O ꖑP>=qJZsA)7 e1\Ҕ{+dKWuMuOP񆑤Miۘ-#E繎1D`@ɫ>g-*v7q`edsk q1pAeנQ@{k UTt` uz__|u[x$n)LFmFcm:2E9DݝԚ5gVeR˝Gҽ wvKyfv1sJY rH~4R@<߲|RǂxH%ιe[70Q3 vi'-g8koڻv9ǦkШh[ zDjX*n &^EyK* .@8fE@kh=5Ī:0:Չ-*E@p^Eyaݻ_>+(?+(?3ׅ?#/]WQ@Q@Q@Q@Q@Q@Q@Q@Q@|7Gv| _xSZ]6VuƝ\qcdL`}@d'FO{wg0oM*u @ n܌Tg$0;@KEpx5bZ`sۧ::8daة;?ä|#~oxn]2{Qw d lcrT^CסMWM]vQhp7hJtA,$APCrT[os Mmy50P9nG\_qZWxg^=>i!J#qL` 8!ݬ=m5S$sktUCkCpL>cda<=o%*2Oj^[]L PI}p1vx ɻrݜN>/?+u;?>$Au6p2;^ N$q~-OCu"ĺU"5!8Tf T*'h  i^ *Ȫ7p9S öXbo߆n"kKi䶒WG])Z$!|O~`ػ6=й8mniwMF_'vEKж)6aik[9R[fK1AAwR:_ў+[[']M#WyvrijKЊv&]sOspϑs!?ˎGO~!/-@%w#sH z++᧋}w_tK Ÿl`(DnCC@ WGc-6R{6eqD_ˎX9GB}3@ROv ȑ0ya>_ۍ":?b_.{kݓe &@)ٝH0Bij:}0WKLcxW~^q6,#j72$0g%1$( p8 i|H5Yn>"}FVlq 2yAPBy Oφֿh cP6RAt<-6r? %G>TTvi <:vێ՛zirDYJ"Ƨhx<EDԻ{,3 2~O{[_w6#J<IA{z*隓YŰYQ>[$CY~vU&iNz׬ &8hV}-u\ooT<u=Zk5k.AX# V=ijc¹+PxPSE8i|,H% mpH LR;+[u+ u揬GyYBN#IL0:('go@SxgYJϴ[ +XPDQ#EP ǹ=W_5NV,mp "lwXDlMvA/3'NtǬxwX`՛Oጭ_6g4t=5d}>h?ڭ1o;\|#h? O >ot%y7 ɋK[Uo*Ad\yz_ mi/Z|kmi;ѢԠBSE0?-|icP67w\"(hf,B?xފOW"|SGsitK  >r7q5C&[\Et,jybeI"H:!sIh[~vkOo'GXx#i }m6kl0:KqH{g s[u/V_<6RYCȏ>X|Ka=_\F^84ؐ QY>,D[S&B )޹|-Ѽa}W;[%ř I /" 6g:FromM 9YȻa 8PK8oÿ6ſt}n6asonm6?x S.npR_٥֛Gosj9;I'El\|Uq[B ^ܶۆ֯vV*Lo){ǔS+rr-hSEp|G^NKtŽ˙#6fbL+3rvPy ѷ-k^xHnTM M39C(Q {|5<)}DwIV|;Rp CPNn,&X3^Og,rqK+_֗)_B߅>#[KԭlEYDU@9bAy}ƽ69mlK&cO2AxAm$&]'z-.tXx&t4'QGd/QK q}~_]<P  𶏪\jWw2[IXӍL THb6v` PqQN,|6aac=櫦ZIal柩| α]jv75Ή>Lr2$ՙ AG5KQ-5{=BP:=6o;m]DŜ穈HXwUEGVjwjd]R%>щ?1̛8ttbxē)jE1`K(HArF` ]pT񌑡Fx;EѯlgͶsl9v̹(Xv}FzݲC*F,?{ ' 2%Yض`UH,~hH5I @RdCPT3-vS٦ZG46Moas0¦IBvcm8r{&PTUƑYF>J܋NK+F<9tۤcu/qqvfS̑l(֡&ڄwf"+㩫_W;_6p^Gyi5w\\K$2$v/9ן<3jwW2=vx3eIYA>??߀iw[Ǣk%ٶ!o; ȇ>gV⩟_ÿںM:Ʌ~.C v'#>ZPrjO0)a5 {5,9 @vysɘHel|t!=IYb$crGN(^~_ ˏ_Nuլ.}cx Ty8s]RZүΒ,xbYw.(s#MgjqLo,cHsw`N;XsT.v$K<Ktq*KWg?#3947n^_J>xQj8mgi\`?s,Nbr1m_Ö7PkvyI D`6\xKwR . n&i(QI˟h𩼒 /n L܈B"mK7yi׿iCjDO2 )i,213{]?YNk1&YZ8 ́HBVȌA__|5Ɲ_ v©8^pyAso×ZԖ g$Is*[s CK#t ̫yLhm5K8aL t@,۲p8Cvzh.-XλS{fc]wEVOx]66wXl\ybݙT$m 05g _]4WhiB #qv4r)E)\A<Ӟ4ѫօB[i:=ݬh-,UЇyhe,@9P-rdQ]bY0e,sZ?/- ,`8u>lac< UDXke[IC$sȧ}=XuOWIMbOY.`mL~k.A(pV?m~"M4V~%ƭ5v&7l0# p5̙utI5 L&$i ƾbmP8DgĘHkmeeFm)Y6G_?wi mE&M:V 4 s~r"élq῍o|g65:m-DZGm62'9 &V t۞sP_|Ƨg-=3Oy9)gWYZ5߈ d8\͸pk_> ks2%ܷR&M$~TAP߷osZ(AEPEPEPEPEPEPEPEPEPǂ+'r?jOGI%ΗI$33[!f%$95+'r?k_ 4woX)o^fZ`@G_H4M[~ߥ0֯LQ:{C v1}A([/]cÞ0Ĵ[{/ ךəg9EFVBI3postfixadmin-2.3.7/DOCUMENTS/screenshots/README.txt0000664000175000017620000000013210715711016021651 0ustar davidpalepurpleRandom Screenshots taken on 2007/09/25, using a version of Postfixadmin from subversion. postfixadmin-2.3.7/DOCUMENTS/screenshots/postfixadmin-mail-admin-login.jpg0000664000175000017620000013240610676263533026524 0ustar davidpalepurpleJFIFPhotoshop 3.08BIMICC_PROFILEapplmntrRGB XYZ  :acspAPPL-applrXYZ,gXYZ@bXYZTwtpthchad|,rTRCgTRCbTRCvcgtndin>desc,ddscmmmod(cprt-XYZ q0DeXYZ a)(XYZ #XYZ Rsf32 B&lcurvcurvcurvvcgtu ! ! > %&s "]#%Q&(@)+5,-/V02635 6}79M:;=L>@AeBDEzFH6IYJLMXNPQ]RTUTVWY9Z|[\^_+`Wa~bcdf g/hTijklno7pTqorstuwx(yIze{{|}~݀.>N^oȑҒד۔ŢfJ-ǩ`=ϯyN$дn@޸wB ּc)t7¼y6ůl)Ȧ^ˉBͮdЍBҠEԅ$dקGي.wܿd ޭSNMSc{1S ?i5yS&r:c ] ;p!AL!Y"$S%'I(*2+-./1[24(568C9:@1ABDEUFGI0JmKLN'OhPQS T[UVXY=Zm[\]_`(aJbfcdefgij4kTlrmnopqrtuv'w:xOy\zf{z|}~~pdYQG<2&ݜɝa<٣nI&{U.°rK'ص`6 ⺴c6 ݿU%ēe7ȡo> ̞i5Й] ӐBի_}0ڛPܼr(ߑEi @gHq)YCw4n,b Zk-@[v "(.<R^T !"%#5$;%C&O'Y(`)V*+,-./01233456789:;<=>?@A}BmCXDIE8F$GGHIJKLM{NjOXPCQ+RRSTUVWXgYXZ:[\\]^_`sa[b:ccdefgphRi,jjklm{nRo)ppqrsltAuuvwxryKz'{{|}~jH&߃{\<ΊgAҐ_:ǖvQ+ڛe<꠿qL%Ҧ[0۫i?ݱdB͸zO"ǽtL$®ÎnO4! %Cfҏӻ@׊T݉ +efK~ndin6WeM((!GP T93G*6DSdu6Ro>e?l/a@6s7yL 9 % v  s x , ] O^?#"2Hj'U![ !I!"#A#$%R&&'g(()*R++,-a.)./01`2333456w7Z8>9"::;<=>?@ABCDEFGHIJLMUNOPR9STVW^XZ[X\^_`bTceGfh@ikQlnvpqsXuvxiz{}}L҈{ohtܝ9F]Ű$Xx<ŘN̫UӪGڕ޻ Q8i92y $/;HWgw)D`}$JpAn2e C}8wEh  S O Z  p / c4 yY@/"%3Ie$X*i  [!!"d##$%7%&'d(&()*v+E, ,-./Z061123456y7l8_9Q:D;8<:=;>ĸ:ˆeԳG۟IQW"\  /BWoBk(^"a+psn"}< ,  o S = 3 ahx I|ko$O F !k";# #$%&q'G(-))*+,-./012345678:;<:=]>?@AC%D\EFGI7JmKLNOOPQSTOUVX+YtZ\]s^`)abdSeghikllnXoqSrtNuw[xzk{}$L߅yZ[V R򜋞B𡥣b)lEõpM羵u'ň3fqQԽeضE}ݍނߟ sX(zX5Z"desc Color LCDmluc itITfrFRBnbNOesES,fiFI>ptPTNzhTWfjaJPtnlNLdeDEkoKR enUSsvSEdaDKzhCN LCD coloricran cristaux liquides couleurFarge-LCDLCD colorVri-LCDLCD colorido_irmfvoy:Vh000 LCDKleuren-LCDFarb-LCD LCDColor LCDFrg-LCDLCD-farveskrm_ir LCDmmod*MrtextCopyright Apple Computer, Inc., 2005C      C  " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?!~|ܾ.E^]LIGގ9?>ׄ_V:gZ:yk`^̌RApFg0mvoݼMwW}z]gӾ1C؋H zgE|>8vVE,n G,rƥ2>`2Fw?~4wCtZ/ lH8yH,[l2ASܵM~J'Ft 㖯Lԯ%z~E<# 4-42i֒{A$JYĒK0A 0> G"?;(.ukL}]6+g"Bx .1+zwz/V/1s^5TJ t;[Yu++-0,;w+\nwIqtU Y>^x[<k~eGHm-[xl '/ 0k+]t׋,K)A-I[M4D ;wde\X.w/vRz?};\4QV V7{_FP}hOmzgtiZdD-SY`ǵ@FF]͸1ݸp@) ǝuڷ]u__D𿊭.A7|H|oqjyR۽4X* ?Rx]6]Fe[d"I0Ҿ~ooϱMY/PnȚ>?]~u_ÿZ]9#izQis5y-P3h"ɾ-ĸFjywi&:%D,fxH/o15]UZjc>uU#"kj|৆]A6ɧM]:iJD,c+1׸wiErU ֡<+sãG*p-n̂YU U ӊ_wo+FGjϜ}ո<񇋼T~$C +m&#H#6 >V4l/x.&l5 %)RyH6F#m˵KM7+/nrN.Kkm=O[_ [ғS[awĐ1I-#gN8i_,՟8}yh|DY=NhΓ'Wmg]9D,<_+7|b->'Ȟ!7BOT$C6&Vs$? U}ƕkwWż$owa ` v__I?}';}}=b RzjNY㟳ܞQ? 'o}s\iWo]DqeTk>ES.~97mjN+Jy=]Rlnp*Jku(z?cVskΗRz̟,K>|!YqK;=!,t$2)|&!saL|뮟}]y48.y$o gʼn<$#%fg]۲j\['/kz'4zHVl-Kkf. OcorqLW%rݺ审]6}P6{W6и QF1]Ski?_RFb>[?ڗKwU"QcRzq=nQcRzq=nQcRzq=nQcRzq=nQcRzq=nQcRzq=nQcRzq=nQcRzq=nQcRzq=nQcRzq=nQcRzq=nQcRzq=nQg-ƣw4!Ydpǀk/D~^.zZ8REMVxR5;ösy^0 RMԼI"v;)?#U`>)D(µVq^)J@mΡx!ƩkcQG Wh+k!Ӯ$E)FC)A"#?½Cp?$eV+s)eW)xR?;VR@A%̲CФOn;PG k xEr_E`A&6Yе={P7 HHHHHHHHHg#K37!ggx$WohV>+Aū%ThDbC4N*:n/\Q_Px|5>wMq6mwáfެk4gO~xoE>7KkWIt0.F8J'N,Jᾧα /h]Ԣ[4F߿E|QEQEQEQE| 36|`ng_?~.j.=g{Ⱦ%-m..+#4O Öꚍ܀6YQ=+wWh~>1)~7Rb,Zuߐd=IE~`~?r4GKRMcg~ߴy_I+;睞o}7QEQEQ^=l~ `EZ=/n&.\Ǒ{9h?:K|мm/%fݟ+wݎqQEQ_/|Lº-ϴjnb g1ͷPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_q&~~͖zE1j:]/WjŕV;q ;s')>5#^]r <*?ڎt~'r!t0]g[V6FDF!r-d}9,eWNF_~Z-CWvgo>=}C& *?GM?PF/5b%FH*?W\5;?,O !Av}YY^ȚY(.[( !}{s2o3 ~zX&[ Ror!q3!`A!8O QZ֟VO?/# 'Vڏ%M|YANv3׉~?-ڦ/ ?źo;v+K,mb}XN6+Io&~:x[ƺ.{/*E Y/4J&(W)!aHӾ%xoojV!nxQtKdl<|?rv?׿>B~O|YoshFTH꓈̉z}eL$x} s__~:~gzu4{mdV&x[Ku-G 5e|[W^ 䡕9G|ŽO~Q:7E=xgƚ~}`xYB/ c := >3QhO/(V}Yh^"|/{4pZ3,$0Ky7(!Vq ;7M <hI%ͤ/-V,v+)ݬːhJ-c& ^Kwk  xbP,DlIc#y7t@?xgn^jht?O!TԮUk̫ |TĐ_ߊo ߅._b4WV(8 AkO_^]/xnΥA`aXLq1XrM{(hԿT'>~)'oh]|wf^nwJn id$ijD8,AV+~oo׿ ?i=^yf1EV0>rEڧ_o \e/)Կk'PgKw6_ӭc4K `+.*[l/3M__@EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_ G ־x7 x^]7|kWn m$B/庹h$3 I e[Et/ f8f6* ;^lXQs_NMO/g9 X3ON;Ik:NI<4OEEsӧEh?/c@}NtȿtTW; :_ƏO"4Q\'?>OEEsӧEh?/c@}NtȿtTW; :_ƏO"4Q\'?>OEEsӧEh?/c@}NtȿtTW; :_ƏO"4Q\'?>OEEsӧEh?/c@}NtȿtTW; :_ƏO"4Q\'?>OEEsӧEh?/c@}NtȿtTW; :_ƏO"4Q\'?>OEEy7P?|]}|gqgg5_gS㮅@'ʷofM`}}EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP~W=~PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPFex_MƁyumNd`3~fa=Y|{o᥯>|GE;h=WnGtB@ aʺsy^ukoֳ{*+?Bs w_x?[įxS4|s [ (C܀>>8^+]-K>V{UwV2Dž*[[bDSOt-gW??ൟ>|Y}"Ş5Aqyd,-2: ^.~ه/OjS43%ßi^5('[Gn@0C3BnQÿzK@O*KTץ+[g(? 1XdHGEEo 3 ,1< ;Kqe:\^,n>^|#5T;"B h7 Jstrgg۲WziY(r_z/J|gw)MX\t+S4q\;|SWnYW#@!OZlt6G,$WpH6ܻq*2yO>@~ݾ1n/c|cֵ;M[< v΍o"ʫ,:q8? /_~/hci[>15uD0Amk|NY0_A3[vڷ[KЪثEdܗ8o'xK~)WmO%Ѽ'5օa |hVO0V#f  kV? ..b^k*Y#BIrGJ]h[pn64Y(n߆u_)~?X l|x R|-Ty7m=ۍ[3,h@-ᘲb\KiKKM%] J:kRҗS JxmxƗ_&|?=uYkh"$|*9u// ~Mw ;x'QФM[@Ֆ'Kk\ m2r붏_5[ '>6{V|$ |7^xo^Z-n$QAld`c!ax+1| ԼKGLE}8Y`KloiđI9.03Lh:?o>_߰!O#־Wm;2]w=z,w 6ݐ-qe;Xy mz<)B7t)5|=&}}@YHI0wC$kuI MB_4_w>q>8^+]-K>V{UwV2Dž__ F֥b[3VhXa7*6@$ktr__ܛ~kF_mO/ -;i^Z㿈z{Du[dc찖y{X7S{[(v|YUWk:jL5^"0Ha8KoRynݟWſ?~M=?p>^BBߘmpܣişW >~^(S::4&5zgDU}Z-=t`Io+_hoɶ 2 rNZwIIokyrnpUc O./گī/]xᗈ-<%vv:Hi"DS!\1\ti\|Z(R[hN_`_h?]OZ;-> fO {huݤwN.IW'9ЇO /7䒻)ͤ|n+ M{1I⋘+{ۻOF<#ZжQ>\wD'{]Oɚxܿ޾4]s_eFkxc\ &ѳ?uhl.o2dEh6 쏐~L`W{?2Ş zÞ<5k{O j恩AbmSVؘ6oߴNM2v괶æ+QK}{S Gf"oi!Pú$9"g,1]#z >:k߲u⯅2V-ՕZ{X;e%{V'2+܁p _V\VsGo.h P[r\4~z|[KDn/YJ[6Y' gb6 げoF:}oJC~L^]d$gP-H6R\&_V/XtQF2g/BB_8'+~ī٧Hl|A+s,wوaY.%^+B_ߊzG@СoA^[iQ$P;XPdخʥT,cU)5Q7mSV%||{vxf_S>j"hﮠYB<Ϙ񁑂y_!x9E/[Ŏ߯u[A fR)*H/E*M~~ktO֞Ҭhˢ޺4;+?jnh?~)}|6 uhXZ)ǫ0~{oXb Ϗm_"/oOGi'=xsG㿾I,e{{ڸEag Cː..ZQ_v0QVIUuc9wxS// ?)b7E<3yj!#[ cX ~жz:{K0ŏxZmb崯 Mhcn )gWŸբƿ#>ss'I5 q(v`'檧Y/-{K茣NF|=~gzc~?ox_-u;6/|Ee⹉^p#9p z6@>ε|eӾ!\ՓFM0yb[k$qW><O߄0ӯ]}S^|?=$ZOuG[̶f+;1#|#n)R^1VY|%y}DIw'}397̟+ZeCᇋ<''|/"zgBώyxL0տh}ues-b^դI̅w \1<װ[KDn/YJ[6Y' gb6 げB' S{8aʜ4eYҔ93/⇎(_[ҼA4f,חbY5, Y R ԗ$ItzV¿$7O\ρcmT:(!&~,;c4LJgOxgPu uwMf,olva6!PH=F|>?ekO<?_ψ5˙_s}Zp  V$ܑ^G!E%_Z說m 9-oޛuS |S[ٛ↥?L]Tؐ#䯂Dψ~.T< ?xeϋWզԙwL#*ᘼRrEDqvmtqwj:u".n[+~ oF~TKXߴߌ>ih]O޷htbiPLQol61o "j|g&߁]=<9qƩq22Or';gD 少`sE)B2oQTjJ2ۻOz/\Vo~zy 1c*J׼ǧ_\iI%+1&&~n}ۨQ՛ny8*QPX(KO%_M5_kL_O( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (? ( ( ( ( ( ( ( (?.?j$o!~?~l;%V҈ah].vBj#Hf2G%+J{ЗzqhD״V7ߞ??AO?1z?4|)yM_YPAm%1\h.o_#|Q𾷥ikw?&Y.ĒkY@Mө.HJ+ZNG?ߛzHp% ~p :'qk>f -b/kyjF4m-<`OS^;sgq17B[&k mޑX$nU7)Ir94>S5^ܻQR0(((((((_f2/.?_}~7Q3Oۗ[ƟK>h((((((((((((((((((((((((((:z((((((((((((((((((((ɚxܿ޾4]s_eF'K)>mM]B~jvw1w@W6k/p!q y,HMmfk扺wExO_9|֩Mnϣ_[G87ym"c⿏z~>gk cϊ|U\ĪPīe]0f8TYp[T$sU/-_{i/6VG?Q6⫨t &C,-5 &~OqnZ&S3ٴс,Gv%UPOq犵g+?u~ Ͷُ'O&mXħiwJڿO?O[]"W{iV^.̊5f-;b'whLj|ycH!lzimCլ"4pXݿI"eIT WZ+àһ{~O>_'?@𯈾"^Ipֺ܋;T0Ia|cVg*7M|(VGs&~+ ˒R;$R18 rk^Wcc* O???\y^ȕP"D@%{u?4c(ǟE^Ex. ?</XJ?piz"WQ@# O???\y^ȕP"D@%{u?4c(ǟE^Ex. ?</XJ?piz"WQ@# O???\y^ȕP"D@%{utrNĶ:|9XE4PK<lnq]=WaicDgQExkL_O/ 5&i/rz u'o}~EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE__WZSǺo 5/[Z^H3%0f!m*7d}E ݗ2o?"VOKlW;S|q3SA#xfmx+TgC%aj;i.q-!!"U?cc?;WlnT4t(;ˈ,ʪ$GjdweBÝ-M\[v]_$nM׫\6~I7n<'L~OIωΩ s߁1k__['~xNĚv. OX.#}k.,wVx&MJ1tm݌SQ>k~Om\4g? 7>x*r.Qw?-.A!Ȑj:;p?'?֟ϧOZF'S&8y|_hyũ'VgdȯWRV~739CUk0jRr#Gڋp\dk*#9B ]_-Kj~߲/ xOֽq-W7ҡP[鴸. \†.hwnBOv[~mႊ(0wĿUq}J*d럵eqc<rDYetqE#8!Ez? x Mc?cǟZk@Ex)?<X?O%Q^# OǏ??.Si6冣-ωotZ{QP'y7yrȹېz((KO%_M5_kL_O}((((((((((((((((((((((((((n+n((K?8>*xNq^([B-ާtֳ{EK*#,U^/?i:κY}J*kDڮakFN\n(/]?M|RV{}[vU_xėv uDHRX預X%ՔUoC珡ҍhkƗekjZ0Z5PEŴrL+*9Rv;iw o[jzsA~EC>CЭ4 uD)"Vux&oO]實E| mW_%ލw51eEڮ/oE쮅Hl6~C{-x{Sx7RKKwPCcr\dq K )BN<}-WW}ٝQP0(O<6MQ%6V/$V+tw8Hbqֽs%+3T_@%4c+ۨǟEG. ?</XJ(piz"Q O???\y^Ȕ"Dn.7冝-l.uIZ SsPi'x7yqHݒzDƉϩՊ((KO%_M5_kL_O}((((((((((((((((((((((((((n+n(({ƛOƗ6t-Z͢Miyyto-vswQJN/|LWj_?j!xWƚG4ԼoEflCi#VԛԲS'FQ4qw^OJOA~IK$\M4Jb^=n|qH4iZ gD.#1I-5)T#xbi>;3eM-OEt,ևcykaUK+?K.ɯb.HGDECm I->e= ݴVz %V_+}#Q'xQKZxA[}Lj:ƥpцhЧ]oGZOGbk^4{w/$ӳO +h՜U|\/kt| |b'GҾx+X.,ڎ/B4F-E#^xİzf%ƉdbZ6l-FiUܖ&` Bc (Sq_(R앖is=QREP\1LtUi9u߷?kx%䈲n),FpC+O% OǏ??.=Sk(KO%_M4EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP~W=~PEPEPEPEPEPEPEPEP\4.{i ZMܨV)+*G@_. Z%F)1×ik[c&ɡs8e## @_4/]kf]K3\ޡA\woȇd/ ߱*Al g$j:oJh((((((((((((((((((((((((((:z(((((((( ?[5zy>>q| _]]Fj2eI@e8'x|ko>4 WM ^Y[Aj<g3!`r#ʖ9|6Me_Q~ѠjvFnwI Bh8r FxH\VM;Ì1%i[ktiϜh Kz=[m)N$0R"ܡ%Wut{υz.K i-C6/)ābӼ8 V`J)w-R|5/<}A{Z<)%gOED# -k(KO%_M4EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP~W=~PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPF1?4ZLoAHLJ> 8} i:SE,W"74K cUA?(_+BW\oWZπэ+=F B)d3s_H:ٕX;O$Jh-ھj]̈ʑ3OxD_pE4v^!}c_X6ErVA~mR{iJߝZ.>$XeaxmѣTlGWhVi26v0+o_v;*+|?Ɩz[ 爼UivwVʺh{H dܱ*E)q~x'å5[.{6-m;$Xds $N2evvɝm_>;x_χN7˩>%Ɏ Eq Pd˺s_&8M2Ov>%iבHڕߟJ,U^[-mkG^'|HF @3K67jPXheF vgTgqDtV;YYX|[<q7-ecԨ /O^]u)ǂX5hƲGl|#aHkZiW-jL { mi z"vl$ :+,u;m+M5[ 6X{hKE6OHV.2F)v_g^/ߋk(KO%_M4EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP~W7:Y"R?_ +G=C}??_ +G=C}??_G^]گ=j:"9giܻ]Iy|2ݯ[_4XmE,LHI.H9u>~GK.4 v}V7HU:prz <5㋋i|gVb,b p=+OP}ƏDhXlCOc[_Y\5K,R#5|+Ƒ+Úk"+?.mjm 7g8'Ͽ>G"z4|4h5EXPIe\,w d՛e͔nͦۛKGa8Q208q]"z4'Ͽ>@uGmOOmBY`G70 ؊L?y'r>vY ~#5wz"k)Bu>sKJnt۝3ONiխ9]133G$j? #E~t[$@3ׁ]/"z4'Ͽ>Fqz Q΁ru[.\ir; 2kkJ4-. PH8 DhOP}Ǝ8Qރ;h,"oਇ+0+_╟5˙% mv$4cyKv_>4j~º]OaAgiʞ]؁Ë2[y1|!qy[cm&{Y7Kk{Xp8ks=C}??_},|iit]& #XD@D_-qEPx<=&ıV!tI]wdsӊ?_=C}_ŞмyxFҵ2{iT88=:U?Sձ8t>e6۔ c]"z4'Ͽ>F0=.B蒻IvSiv&oqĀ`*@+c=C}??_Gy\%kaakmm8O%̌>@;< } jrioAUT̖7UpTC'Ͽ>G"z4m2iӬ$\O4{<#uǑqTVcYZYȅclnXp+s=C}??_ +G=C}??_ +G=C}??_ɚxܿ޾4]s_|~ڟ|Skg/iơ_͗p<0ǒ:z߰_caO|Kn7?vsy{>Hg9wA=rxɠ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( _׭=#WW_׭=#Qjʜ¼ 8?7:N++b/IvGp, JXaP1Pp}?sݿ{C^_GOkֿ_3~&cm?IA}F Tb}0, 3k>4g}e2s}Eyu$ \{٫%}[o z5=Z{/F/iik:RMG94Y<^Ysv< 6broGow 4|E,ƶo.aLA;;:ZڋoO׭=#Qj#<z X溞KĂ Meo}(O㿌^"zwOn@'fai XpízOkֿ z5s|UxRص΃|-)6w*GT;sq\Z5xQ|I%߇`]CU7+!f`JmPU v.zOkֿ z5y_i ٭C~⽵L=לŢ!2n|B.>1iךڅJ w@qJ+o 06Fykߡ_=Z{/F'5_e^, Ljږyn%7jR_B㣅Ebk>xQ񕷉&BMoyi}[g$ۉ<3'{zi^4v_=Z{/F'5_ejw^)[ɦm XDDj&յ/oE=Z{/F'5_ejj?{C^_X~o^$i K&rR2~sP_׭=#Qj]gV71"ŚY ũ5$f2pU^)Yl/< zoc4]R;7{,HWr_I_k޿=Z{/F'5_exe? iN`8y;e,;T͵F:?$-^E6(u.m a%l* ICJ.k׭=#Wx  چyuug^-y@\60U*v?+a淦 _gI"E$1+lfK c9h?{C^_GOkֿ5R)glzkbʊdfN;:W_-/\]I\=QEfA2.XrFx%-Z]{C^_GOkֿq+Cezd#=y4-Z]&@{7ocs'5_ekb8!I||..5)/,kռgm5{XE-"hJ }_q.wiw46;oW=c'5_ek)~0_+MqJ[@ضO!p ¡2p ϏYxRմ=_JΑo?╡EԐ-V, sn*q5oInǬk׭=#WX~:ֿ/Í y`Ė`-GtNy$gVW}[]jh<;oyaغI N8*ʃ H TC{Okֿ z5x>2N>ىl,ن /o+x?no^h_o\$QAm"3*.d sdߕƕw=Z{/F'5_eZw <7q.˹t3$K [f,C#uŝ_Z꺗nc`6Ӧy!ˌuei-v=7zOkֿ z5yͿh&x|W.uai?&i 7Lcك}#V;u/f -hm78nRUVsXB]y~;[@k׭=#W@:o4 YOԯhHpٞ3ǚ5}2:vu{y)ace+\Y\4tbY>f?po7~#?׭=#Qj>SWz_")^Lǹѹ8ƛVW'5_ekQH =Z{/F'5_ejj?{C^_V =Z{/F'5_ejj?{C^_V =Z{/F'5_ejj?{C^_V =Z{/F'5_ejj?{C^_V =Z{/F'5_ejj?{C^_V =Z{/F'5_ejj?{C^_V =Z{/F'5_ejj?{C^_V =Z{/F'5_ejj?{C^_V =Z{/FQ@\?M\߳Q@?M\߳0ZGG+8o{IR" [»(ɺkƒ]0!n?wPu>7_q~WqEp7_q~Qu>wPu>'=|ϔ»(ɺk웯g+8웯g*tu5r#oHUTϲ+h&}? ?n]ReDI2*n{~ug&}? (DmgG)NtG6wP t1YKu>wP t{Y:(Rdϵ?]緞}݄6Y X}jEs[3Q@75,v~>zg?]dϵ?Ucy-nm0bSWG?M\߳"mn? (hCR"FLWqEp7_q~R峺s]d]ces?GEkq~WqEpGŬ<?Y+YmsnQn&}? (&}? ?nn&}? (&}? ?nn&}? (&}? ?nn&}? (&}? ?nn&}? (&}? ?nn&}? (&}? ?nn&}? (&}? ?nn&}? (&}? ?nn&}? (&}? ?nn𢻊(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((ڗ~ɖ+kki˸w34p<)z?foٯ@{R&`bXR2pONbo{/$k[BM'9"!ǵx_=h>"׬^絼I\sҀ=~  'BZIDS1=G<_g@@tW7tY/v'=O.d_O'z?]g)OygG k_g@ȿ ؟O?#~?!'u?া>Mt)OygGhG"'bMtDS1=G?;bzY k_g@@tW7tY/v'=O.d_O'z?]g)OygG k_g@ȿ ؟O?#~?!'u?া>Mt)OygGhG"'bMtDS1=G?;bzY k_g@@tW7tY/v'=O.d_O'z?]g)OygG k_g@ȿ ؟O?#~?!'u?া>Mt)OygGhG"'bMtDS1=G?;bzY k_g@@tW7tY/v'=O.d_O'z?]g)OygG k_g@ȿ ؟O?#~?!'u?া>Mt)OygGhG"'bMtDS1=G?;bzY k_g@@tW7tY/v'=O.d_O'z?]g)OygG k_g@ȿ ؟O?#~?!'u?া>Mt)OygGhG"'bMtDS1=G?;bzY k_g@@tW7tY/v'=O.d_O'z?]g)OygG k_g@ȿ ؟O?#~?!'u?া>Mt)OygGhG"'bMtDS1=G?;bzY k_g@@tW7tY/v'=O.d_O'z?]g)OygG k_g@ȿ ؟O?#~?!'u?া>Mt)OygGhG"'bMtDS1=G?;bzY k_g@@tW7tY/v'=O.d_O'z?]g)OygG k_g@ȿ ؟O?#~?!'u?া>Mt)OygGhG"'bMtDS1=G?;bzY k_g@@tW7tY/v'=O.d_O'z?]g)OygG k_g@ȿ ؟O?#~?!'u?া>Mt)OygGhG"'bMtDS1=G?;bzY k_g@@tW7tY/v'=O.d_O'z?]g)OygG k_g@ȿ ؟O?#~?!'u?া>Mt)OygGhG"'bMtDS1=G?;bzY k_g@@tW7tY/v'=O.d_O'z?]g)OygG k_g@O<5rt~#ʚ=F78?;bzo}P \iw{$ޤs^EHt_ |5D/nki]jW"H,HTP*3>[# jFGg .Ve\V{P-sEA96mՊO-ߍ|]ׅui.p$Aat1#}1_w6\PVMЬj PTEpostfixadmin-2.3.7/DOCUMENTS/screenshots/postfixadmin-user-vacation.jpg0000664000175000017620000026546010676263533026175 0ustar davidpalepurpleJFIFPhotoshop 3.08BIMICC_PROFILEapplmntrRGB XYZ  :acspAPPL-applrXYZ,gXYZ@bXYZTwtpthchad|,rTRCgTRCbTRCvcgtndin>desc,ddscmmmod(cprt-XYZ q0DeXYZ a)(XYZ #XYZ Rsf32 B&lcurvcurvcurvvcgtu ! ! > %&s "]#%Q&(@)+5,-/V02635 6}79M:;=L>@AeBDEzFH6IYJLMXNPQ]RTUTVWY9Z|[\^_+`Wa~bcdf g/hTijklno7pTqorstuwx(yIze{{|}~݀.>N^oȑҒד۔ŢfJ-ǩ`=ϯyN$дn@޸wB ּc)t7¼y6ůl)Ȧ^ˉBͮdЍBҠEԅ$dקGي.wܿd ޭSNMSc{1S ?i5yS&r:c ] ;p!AL!Y"$S%'I(*2+-./1[24(568C9:@1ABDEUFGI0JmKLN'OhPQS T[UVXY=Zm[\]_`(aJbfcdefgij4kTlrmnopqrtuv'w:xOy\zf{z|}~~pdYQG<2&ݜɝa<٣nI&{U.°rK'ص`6 ⺴c6 ݿU%ēe7ȡo> ̞i5Й] ӐBի_}0ڛPܼr(ߑEi @gHq)YCw4n,b Zk-@[v "(.<R^T !"%#5$;%C&O'Y(`)V*+,-./01233456789:;<=>?@A}BmCXDIE8F$GGHIJKLM{NjOXPCQ+RRSTUVWXgYXZ:[\\]^_`sa[b:ccdefgphRi,jjklm{nRo)ppqrsltAuuvwxryKz'{{|}~jH&߃{\<ΊgAҐ_:ǖvQ+ڛe<꠿qL%Ҧ[0۫i?ݱdB͸zO"ǽtL$®ÎnO4! %Cfҏӻ@׊T݉ +efK~ndin6WeM((!GP T93G*6DSdu6Ro>e?l/a@6s7yL 9 % v  s x , ] O^?#"2Hj'U![ !I!"#A#$%R&&'g(()*R++,-a.)./01`2333456w7Z8>9"::;<=>?@ABCDEFGHIJLMUNOPR9STVW^XZ[X\^_`bTceGfh@ikQlnvpqsXuvxiz{}}L҈{ohtܝ9F]Ű$Xx<ŘN̫UӪGڕ޻ Q8i92y $/;HWgw)D`}$JpAn2e C}8wEh  S O Z  p / c4 yY@/"%3Ie$X*i  [!!"d##$%7%&'d(&()*v+E, ,-./Z061123456y7l8_9Q:D;8<:=;>ĸ:ˆeԳG۟IQW"\  /BWoBk(^"a+psn"}< ,  o S = 3 ahx I|ko$O F !k";# #$%&q'G(-))*+,-./012345678:;<:=]>?@AC%D\EFGI7JmKLNOOPQSTOUVX+YtZ\]s^`)abdSeghikllnXoqSrtNuw[xzk{}$L߅yZ[V R򜋞B𡥣b)lEõpM羵u'ň3fqQԽeضE}ݍނߟ sX(zX5Z"desc Color LCDmluc itITfrFRBnbNOesES,fiFI>ptPTNzhTWfjaJPtnlNLdeDEkoKR enUSsvSEdaDKzhCN LCD coloricran cristaux liquides couleurFarge-LCDLCD colorVri-LCDLCD colorido_irmfvoy:Vh000 LCDKleuren-LCDFarb-LCD LCDColor LCDFrg-LCDLCD-farveskrm_ir LCDmmod*MrtextCopyright Apple Computer, Inc., 2005C      C  " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?!~|ܾ.E^]LIGގ9j)M7މ_7^!f6v-k2ЬR;R8 ^+y_ׯ^z Fm7~Gu(2hZ%HvuY-k9F_|]Khob7ZeǓ,s[bv7]{:&JMIy1WmiM{omxtPKrV69Q"S~ o|4 ^i )#78>[;+p敬}?K_R/vg'Կڗ45_|@INȡUQx323׀YTJrn;ioO}~]I[)meANqZ}r}A j>ږƷUo2"~g~õ|m&յ/_Z$if5œ\(+v 7n$ xf)];[|M|SCn'1He9g/~;)?nkKq=n?e?g_ }hm٭-Xe#Y~Ov^;_kYxvF[GF$2ӌ|zO7_qVfR[_ϭ&_hψeI';9/Zt6-kg'1Fa yb擩x,zvq𽆍pMw۵C&IU m-4[&6W}-GڳbkzsG55wi?,IwĀ+ 7rK<_ MJ,m 7^)M2ZpKD葲}H0ʄ1!Rm8na4zo]Q>q]g5O 6kw_<O maR<1(LFmIK#2 =ᇈkKO%νeM}g lյh0j#b ƛ]wĆ%?rzaRRo:;o揱?.?'ϝu\-PvqQn,.P8~+Pom7M_š?_EMNiUs=FWd+y'%AX;s]5gjz7++{Kn|MپeR8EbW.|5MNo]<_eslŒu$+?kvijNYڗ+k|ejzͺj[X#inQ(̱"6 -l2|c? N "Q'ߴv+'fckm/eη~-m﮿n ]u\- }u "y;#Y[?, xvu9Km7WZ'Ut҄$Ր.Ѷ>9,4oKxI&éhze͜IԤ@gT`DwU(rq)%?NލwſVcHV|κփZk>]пh%e5Qj_8.53nlch0=oljc⟇ MJ-OEI[{zt[XN_BIvjgfޗRzxSƞ~xRVZԇDV_2:u>l,*(<_kW?oV֗ׯG88y$4׉/WA =#E[NE9b9);61ݴ_|~Ku-kAkRzq=nQq=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=n+g-ƣw4!Ydpǀi^yVxR5;ösy^0 RMԼI"v;#L?v{/ jPH=RXY{":ޞW[UE\ׄhVPh 7ZOmx*G ]çS4[;Qw'@ NHF) pA#|5P\E$q6Bcw|m9ZTQR4cheWb1зo[-1ۥt|MHx(PqZ uM☢O|4ϐcw}Q28#8Я᷎^\j:uĨP&z8wCWK,FXY w)6 SVo ҿ:ZV^EnYȲ*r ILcDu5o'6+9ZVտN-~&hu_Ebe QF3Ux|Ec)g"7#O?|õ{N)*(E>g0_])?*m+u7%jDu5o'6+u2k gBdYi+,-(N12arcVVr^ڧ]ӷ}ևvU`Q`kչ-U][տNDuixăLqocKv%O$goj{7}NW9${)+?i_G-M[+J$w7a~b զȔ\]տNDu]EQG_ }/Gҡ3TQ$$Xw$i t=TX$I Ԍ}/HO,]0c\M:-)3Mhz|տNDux/zxrr'{rf#32}7Wu Eԭg#<ey1Md jWI/cpU#5k殿fտNDudj ɫxſ>>{.(@2Yr ~,㮱qoZVտNToW *U?`UkJ jjOmZW'Q SVo ҿ:S_&?ToW *&?i_G-M[+JO>S_&Du5o'6+U?`UkJO>oZVտNToW *U?`UkJ jjOmZW'Q SVo ҿ:S_&?ToW *&?i_G-M[+JO>S_&Du5o'6+U?`UkJO>oZVտNToW *U?`UkJZ W~:&7)r/ԒNuP0SHTZV*0|*5%Q   MTtuW^T'{/^6tֆY<,3kCDuC   MT©C¯_UA5o'6+;߉g-KcJ!ԌӺi~7G*0|*5%Ri5f TG:-0Kkh"V8#E _pVjjOmZW'T?~7G*0|*5%U6ۻ /J]>m6sƯտNToW *U?`UkJ5o'6+?i_P©C¯_U~7@տNDuC   MT©C¯_UM SVo ҿ:ZV*0|*5%Q   MT7-M[+J?jjOmZW'T?~7Sx1<`67.5˧ZNJԅRq&'{5o'6+?i_[_f;X;u֡)8.^X]N@?5o'6+?i_]%]0xB*gHZCmnIu&1?jjOmZW'Q SVo ҿ:?|Q~kaa?_gik{ky\m#r~w+.O  xJpͭE%s0UZk FGִ|%m#^| .nLSnf;# ?i_G-=[+J>7ZL>6Ym87x9APN<_6?:F3qg4R]9w em?xV8K^/|w5_}ܖOv* ~ OVo ҿ:ZV@ Zks& 8KY1V#"X5{KCU u<毬bRҰP;_ ~ûۯ|!xvRa'-qldCV/0E(I \;v5U5^n{Ϸ΃ğlyK1jwQF],W,I8OJd_j7e[gTo/$)ȱX;"nI<$ ,xwW {Ğ7EA[tD4ٛ,rI~RK𦣪޵D1G4]aNy.*u^DZzeYRmMcj|=  }\j7w6\ (Ϲ[JtEo#B3o]O@) #ij/(HM1D]x#UXQ|<I}OJ_ź]WW$BBX [xF-c)(UǭrUrc&v_&GG2%&cGgw>0|=ት LmFhHa, 8ǁ` QRqۃ+}[AukjQc?IZa㝿p5O'8GĊ(UQR֥k{ pj\^Y뚜0g 2X%1-ݺki/: xv-_xUtzۮ:%:|Ya& q#?NeO=k+ų빣MI2\uL!cw|a>e K2B  yp9M(A%86ڊJ/7Տ.`,48NND)Ji^IM]hI~#_a-U\]70E1_#3 X _uFw]2-ByX'P=zg\z~?J8F>5[~=O$UN횗k+$O,b^,8,~Y@'z~bC܌y9^q9~k6݌&>Lĕol*ݎ3ΏEk|ӆF zۊŦNoOxOkET' *a½Zφni3[SO2TIؕVX0 ~,/*a-6 /n<ӭhLk.VvB}$:~ytrG%֛;d \4h%oDr! TIZX+[(Ŵucg[w~o.TG]QDEhU?8<QJsLl ?ȗה-)5H&Lts]?K?oeJ<ҬVI+߁3:`gm],]Dד%QKseeH7 3uU#?lOv^oiw:-Q*bC,B"B!F_yO<=Yi6٢7hZRl?)%Xt,݉<#N> <9ߛEn<`eU`ijly e>֥5jѝGN7'|4MKn{rB4{KcVRpGjqx[|I;ox¾'IxWG2]khmfyD9o$mǛs{Qv4oXvϽ#~,' F襮=$ܺo_=J~,|1𭦃o9Ķز#*K__3ZR8'|w_tcmFH"k[)~ |\2!?:A'߉:luϊ|BԀ_ NlcGwgyܼfhJyJ?|4~ w/BHm+FF"oP&ZzQo}$>9U^kۭŏW/?UfޔT dRA~^/Ҵ[B_ǚOh2CY[iEs=#KQ2M Gp|9 ?|g4[JĽnW%Y cB$vI _i,z7qofG|9|K+xDl{Inqu MqtȎ.k-BV.-{u7j][eUi7t^*sxs_~ _Oֵklj收O+g+y"8| +wRoB>w<3~;u{Cd!f]_Im3Iře؅GShZuikwڮu>"//QL6 h6 |"Uxk ƾBh1k摠]iϥXmK,UI$,2yH*uusv׷5J_[owd)ە};M_yS}WSδ-D'li炵hz徣KsDQMKyZ\Wt:˦ o i>!xsꫦ[uv𭘊Y#kc,VM$rO0<" _Wᾭ x>D&-w^O'41 . ^.gi;vvOK6+F;IuOPvG 5YF!0yj?#o9/ OE5W+ΚEW6R8o}:J~~,~ru/RpUyݿ}O>gC>g@Z~ֳxvX~?i 7ZFX5\\]d8ⷔIlPZ1~m{_u^_M6?2Y5J%ϒK؄ vV'>0 c߇+[i7Ԭnu˛;6Wk[ h{rXJ!h;z硚mk]O;۾_K 3/4>jZv 8Gx&-B;Kbk=ѐ ½"JS?}uwqn^Q$ X@ϙ9|,U ǗWx/v7iJJMT\I+-7OVqr{?|P|HC|!qៅ5/6`&Y.#q;JV WwxT׾ Xszֽh+}KWy"AolI@? wbhJ/4Zxoq FqmtZItOHO*Yci[/%W rмm?&i ֜UԲϨ[[4<@'Wi7;6 i?wgu9VVIqo_;#_wM—lux#[;k{ I'X8~;'uw>~^:,? |,4ku,aܔgU`P8k+UïJk_ҾTѣu[H1-GDFPXJpO_)JZC>1ګ4FTznm#fTXy0?_σfߴNJ/ ZH|Pis_Ac,hbk9nalS-G$0:ⶵvx OVZw|B{ H켶I4F;hc>L*XOisx7 4|a jZ54jop5͖Y3I=1+%߄i ]ǺN^ռA y_VᾅͰG$0rw]V*iZKٍe.]>Y'?~ >$[!=^#|1q YQe6Ci{QagBe21=L?x=CzJ]'3Hx\A1 # "mxGÞo|>V]F-Uy̞|f18@Ut G S/76cmhQ+լ`9z*)EYEɶJ7}6WV1Nqw]|;im/_W=7^Am;ߎ:FWW3ݮ=lfKf!H\?ğ ׵_coq|xf-nNgxb7m#fl3(o$߇?Jr~9&{mxn6poxeAXju>;}L|Ei]|Fھs R_$o[h miuQOofV2Vɯ7TRgxw_i x7AGoZ%pji*Z+7e >'} sTVx-g&OjvW3Oa+I+ǔsw; 1=Kįč[⅞?>|Rbeֹ؃kFnx'HGA其5ݤ9nz9"ߑs|_#/$Bi)WoZx<;M?V~ǏY|$r>MkKtx=[[hl-c8jcP0@8x>ă=oSŴAti5Uֵ&ZTRLȀ&1^㷆 ѵ --\I GrlnpiyW$+̼9B:㶹T֧T-56AOd x`YtEY`NxknOgmZնϟpل"J1JܻG]}ncdpˊ?64xy<[Zﳀ~~aG?|~iX&:{~¬I4fe)[ 2F ߡ+9OE{ľ5mR(v4 TH;1A種G>|l߆~%x-uMs02E5w]̤Z[Dc8*ad.%wx?EŶ׺ <ڝ R~ U|1_:5*~~|^˦SǞ_Gj^6GO;yn%hC)XvGN8|}/M[ڿĝRK]Aymqw)y +/6#<|d3|ln5 2=CNt:2X3e!9ȏ L,N|o뺯Mͩ%͔Nk%4FGm* dZᦋsnʛl|'x+o%mȴXJ[r?nhTVIpɴ)iG퉪V%ߍRPմˍY-߱y"V[yͿ&[`<}NĞ*pĦ[e#ZQ`PIPb*DI~&~^1ws_PkLȒ$4"cA_גo4{[mrǎ5+]&–0h^ɵK@p(# N >7|~<X[Z[KjsiWc[9d# -UW͍D!As|?m3xH4=*k:Ķ[Ix˽dIb*z^ty->'ILkeA@EāFr$]z5%II?QFG@Š2=h2=h2=hϿ>|U_+Mm'J6%1=lM7jo@,`n%O|2 ~6 }.OӧWlI#^ gdA wo?db6Q + |E(|Lu7<.^M+Qw9me!d@;n6}[@CG/#u> uk$OYi$M4 *9ϨVڢ(_[Nf.cQz(爬5땟>ֵv,smfmw~_fhthRkDl5ִv4z2խs [y!ѼW,RGGF ^ERJ:$K#ӑB`šKMJ^E1 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=Bum 1׈w1DOFw<'_I<7/$=?bмQz𮠹( G Gڨ63˾} o g{x ]C(^(WPz?'??Š 4Ro/x =C ?^/z#н_$Gs<3L{ĿIGB?Ί3'=g %OPz:(?Ko/x =C ?^/z#н_$Gs<3L{ĿIBMCA?ΊI?%uG4š#׹Q@(7T|Z5?^&5GjV!u@G_<~Z?<:ރq{yl7A1*WK^Z2E).y'/T qs1BjQkGE#0A )WWx L]kG߄UؼEG7TvRQ7$X 8wM97 YӴ~(x5GxBj:,6i"-% #1yRXd}Ox {:< |7n4جu:鶓0*﹅C"GY_}|+aTִ]VgU VS ~x7ZiGƿ|SS>+KeA-k hgUd."Y?S?G?K^.|I_ϧ_I $c $,W`|$% Rj}ޏϡpe,fZ&ӋއQEu<QEQEQEQ^_w࿍>2^*YKa!$a$BK̠(ֵgQս/sss<8E,xUUxW_{Nգb>%,iYaӭgivL6|7ooae/ߒ `XdCk' $+j>%%ΟXM\5_-Л[#u*qqe#ؓ/_jsz׊q݉IDOo*ǞdE F 6QTk_rK?P~^ ~~OiqĖ6*Mo2nTG\k_+ԢG*yJ%ƟjeڷZsM 0g{]R,-@}QTb|! P<}1t<kz׍m|7<$Kylom!q {8%o#Jm=߳Oo|#Gxu:[ʷNn1YL_7;q^,eWNF_ȟ[o~Zxw~tãa!.tS#npۭ*~~}j߁e{_i]yiHu6f*cN+O9i=E?@Ke}EU6a#y^ im QZ\E>g@hKAI-?P{XESxt?n3Dg㟀ÛCKssI=m7uFS)[ gK8EZ(ivXI(0XC%$%@-~?p 7 3><>W^&`Me:̫H'qO~˨h?h>0~-꿴?>wyi%ӴB<wˬJ sPK#aG3}M|P>jSG$7mMJb. ;p7@ߵGOGy_ѮK*n+?8]A*3# 0??/?5@=9-_?f i}nWkFzt#)#yjB03rpwߴd ji.V%gAop$7y7,N923h_E.W6 ;X|1`N=+qxgB|kb]n :}YBFg>c6,򃱗<ocKޝox\WeN 6XUg r1WD|P4xj>4FosΦ9!i Q uH%Oh *),1]foJ۾ g _ אj0{9"M-ż-fbF} xzvxD5+tKDCs{" A*JAy>9i!ïx]Ӡ&Ym֜KpLO?W~KO!lJEA`4r?AP+5xslψ/, q+$Jncn@ ~_R/|nw㿇t_hđ,# $;uB1k"k'UR{ُM;g_5E_P|rx7Ci{0\Gao:⺏(w;ƿWƝ/ßt jNJ$y# AIiLc_U[:K,OIo%7|E4o&v.o5$)e% U!k 3X6p[3 Ia_sXSbġUF`W؟g?4#=(((((((((((((((((((((((((((((;P  :~{JH>XYp[oO5?]S?\O9)Y7gz lBW˺ l\}~w6%$c? _MuIOR['DVw_*#_oUG'4w7pݵ.KmnSn"ܪ,=kO-6xNZ}m T8 'iv`r`go -C?<^mGēkrTp+y`mL?G/.c>xVo/|QWUv 6aERLJ՞?chLxWľ |""UKnm(R(e%eǍcEǏ j#z g18 u/k}v⾘^oa5rUhܸ=E8N?/>5"|1M]b/t_K/l-DiSb0Ui0 ~~?mjxS]C z٭kO(:LϨ7d_Wb6?y#rr8>W+c {Fd5o+H5R;.Yag}@tc %C_ׅ?0>[ӳ8J̼($v,w GIz[?G>WρΰfE :aotCtSs8`@~-t[XXXİ[[[DCo*"(T`\7o'Os7/xo oAe] ѭ+(Env3#uP>/Ú6xy᲎;&BD0U˾9ɪM_jgw>Cion۽qS]'j_9?},Ft-%xV(^4*TiͼGxC!ydHt#i$ $s8M;9s(_Skk=g KMA%Qo iFь`Qo QRҠ# ygb{QEs;M_?e;Cw}wTݱ3ghA[NiiVI4U0X ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( Bg|0T8?[g_*C ^[ cg_Unٽ?S<>$uOXq<_Цmg?;]}%$c? ^..s޼D%}7% /|1b+JJd@͆''(((((((rƺwCΠ1\xGӟ4WȿJhi@]Q_"SGsK ?)9}uEd|?RZ#W}>?/3/x\/%?w4;{_PTWȿJhi@]Q_"SGsK ?)9}uE| O=/(/%?w4;{_PTW˟I> w0wy׉,$m!_'~>8;{_Q O=/(+_JhiG%?w4)9€>ESGsK ;{_Q O=/(+_JhiG%?w4)9€>ESGsK .?Gή| |~^g1>_| O=/(+_JhiG%?w4)9€>ESGsK ;{_Q O=/(+_JhiG%?w4)9€>\ODO͝!lӹȾgϧ5IeU#m ?d8o79uWȿJhi@]Q_"SGsK ?)9}uE| O=/+kEn]o;cm\.((((((((;P  :~{JH>XYp[oO5?]S?\O9)Y7gz lBW˺ l\}~w6%$c? _MuIOR['DVw+((((((((*??VcAQQ9z( (;'AV?'AV? ( ( ( ( (,i?u)W/Vx@S!@}Q@Q@Q@Q@Q@Q@Q@Q@Ɠ oW]Ɠ oW@Q@Q@Q@Q@Q@Q@4 Tb ++m]S((<-!?_ &; ( ( ( ( ( ( ( ( Bg|0T8?[g_*C ^[ cg_Unٽ?S<>$uOXq<_Цmg?;]}%$c? ^..s޼D%}7%*FFig/7ծ|oM"O%R -N;pJ p a-͞q]WךYjik!w-YZ OiMEoWexH/`gkaHϝ$T00 Ű[B1+"è܄JOf^YS 6uf{*\NCס> 7Z%%pdZ[ $vkVBm~_{ oWx_MrA o%4R kt[$BWë>oWickšۊ,ÆaX`0n0eE_]-ѥ|P :k6ܵډXgK判vb޽)9ះZmZ `YE@ӓ1w`AX\:HT>֢"֯tro#y$v(eRA #֥7/|'&|PX}cj`h1 Ȍt_"5z>g _.:ŪyXy¼rц̼CV'įxĺ>{Vss62@#IDp$\w>x'!@ֳk1j1M#7N<ĪIw(K^ws]~j6Ic}5p!Ѵx 䫝ʰ%֟]moZZo/ |=OjZDZq;ა {sZOZwڦ>o=qw#6_'rk/rZfzuΆ֖z֑oqlthbcbHvRm3\dTZvzm̆fkIg 'k'U;~:a+ú_FW9kc{Jc m tCbu&'ɛ 6>{_A+5K-3AҴ:_.vd$[DVm܉B ü|er_Xw6WNQ "umn \*$NW:S~'z$>h2 4y^Xv`䎵^)U=֧H'H5k֖6f4>\@%IYR4]2NI`$Bvi,pI_ZmH#۸9Ieb__⿆Jnu+y^92"9^#U`u>FM2R٤"7[[X#@ j._~?ro/'MRΑXj"ЭDI,忉%W8F eOŢk,:{ؖܨ`"ۉ):^S:-ݥltjvqX@!<?'x5ֱ}{gĚVm3G6̆Gh#sb ]m?w0|H׋A״i59vN;A~{gMoIw sIl#*T9v' h^-ejiOymtiC,Ь.w oڭ5ޘ(%]I}& &BXvPfPφ/ݯst_ֿ=Zm7_Qow΋4*X4? ``UeA}}sHMf<,1s2`0 3ǟ|5.5Va&X'~Vhh䗰־k~2b .[/I,f>DqMU1v6.[?i%ӥ &XO2o˯&Tr66z4ѼZ/um3SkuFZ]$ -F=?iPݏh&u[t{c|U'y{_ S?E{}:+`0Lvlc9$iGUw|۽W5o]]hWd5+f <`Y.9W_}'Úfk{k-^}D\GŰ##:ޏi}tKKA6% WR\ (Jp5/?gy]g~/@]"-bi㈼VqNl>j%qpG1n9iv_eOoMFr]I_JlO$ݴ;s+WkW3i=4녆{_6fΜz5^Z>?j^>h09_ gB?ului"GQ./(ʛXљqd !hl{\, O8ј`k(~ΚŞ|*xr;;nnu'vVDr7FIBxn=~i2K]be%G76{^K*X_ɚ凊4S3O ך񅘛OdC<9PWr'\$ݮO]?;S/i5icxCMO36`mo} U>4xO@&~;H{o5Uu]ű;zҼl=߃IՓ x2vZM+EX1/S|úG9uWT'|/ Ѯfv'ʅ-RF)N|/]_߭IU熼9C&mm|nhnkOB৅n< _ 蚫-֏cge3I8 2W@S!ZԲؘj> vq-O= MsA\: 浤Ů\n\aX;J(x/ķ|1OPhWm_Zo^j64p˜y' W$>xPWXiķww4v2[)6VBɵdq.k>z<;umMr?-fpbݻӧ43⇆:A:'ɛ 6>¾֛k;WH5}f}]4{n< B}PI&(S[OK dxxkN]/~I_P3,`O81 '#ު׷O_?&[I;_ZKW hOk GIJ I;.!طb"vqݥaʅ 8`G gύh֣X<'kmGak ax,&RU '~O:f/Co)(aʣR\Ki_N(((((((()&(Cu!_RD?R@1u\ _53OTe f|C ޹_F<#`[?? ?k_; lBWxRSaԖQ>CøUo?]袊,((((((((*lZ^ggn{W(_z_z?׮ף_z_z( -Qgwsg/=/tP?/=/BAEsB/=/tP?/=/BAEsB/=/tP?/=/BAEax3qK[Ǘֵ5[; ߳~>lg * O_ G Q@  O_ ]Gsu&K#0@,N'܁@B/=/tP?/=/BAEsB/=/tP?/=/BAEsB/=/tP?/=/BAEGimb; c8?A!렢9A!^ (^A!렢9A!^ (^A!렢9A!^ (^A!렢0<[N-cpsZoٿ63z~bף_z_z(_z_z?׮׫_?/gٌ>EQEQEQEQEQEQEQEQE:`p?οD+ U( A?:ξݳzx|I"Ʇy쿡Lψ~w?/KHDŽ g']]_bwcy/#-JoJx:?'xwxQ_Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@^ԯ-*]{}6HbPT7%w (2: $n`2G0NuQo+>azoaSQ;I mxF[ʬ`7e);4(wѴ۶s+ljwZ?xk˦6Z ?nn.b)<:I[}#G?<_DŽ</ j,4[=Z}GM7HY~֩I7dIoouך~+d_E{y77r36r%x~#%E{j:1O-VͅSeD#$6 @ ?|24h:-5-2;Kp# Ah5Q5Igch}W_ukOGlO?ѣmsKmfSteKE|> +^D+-fQeh/⿎OSl5]f{bX՜G PQ2t+O;5m٫=o~[A`wy~_h|^<?df>Ӵݮǟ5\в}U+s>  ZVi}h7Z iۦ5'Pq:kaXԚ=⽇J?hzXc+Fq+#)Fƌ?|3s[B.m/!e`` D̪8B1RjT'˭~v~=U̫aqG._u$SJViIK1>'ԺO_ i8ԾxUg[i]^Z})\y+B6Jȼ^_|d==;It {}kTVxn9-dtJR&Gȸ!An|eYiwz$PL(޼1,N$g\ǯ|1H#xg\D:w~!M6f N[F'OhOi4𝟎ukrmbu[oԿ;H1=yO'7mimiuHhfW2+2yZnZBVս$[E9`Ylq]4QՓi)&xO_o:W4I5 xZO4YuKNx湴9sy'3TRDŽl~a[-foW;xtMZ;dik4.K#qyQϏ^kMC㷌)>qikst7XG=WOec6f\ˮ53)-Kh:9"rxW7ūVqK_|w4OEWKS\ܩ7||t9x/ufa}kڮ ]-"Q4~r1{c86Y||ժz?oKkkKu mlZ#Q M>?Z7u;xĺtl]zıٳYvBF?pWi$]$׽z}nXvqӒ:qwPveI{Ml?O߈^Iťčw y#H7@Co&}[Lirk Ρ-i=hKB_ vW/,igѳ ?OMŷnOyҪ_h|^<?df>Ӵݮǟ5\в}- A-5ڌ8,f,gc"`9O=/l5ֺm$kk%s, 3M4DHQVZNO)RdYt_3ǀ٫A~^_7@pʲ7PFMso߆>-ANj'ֳZ[gIcfwT)Y"ue$mg*<<ʛ7.kWo]tWꟵ_s W%i U"i'igXw <K0G>!i|sy6ղjW2SvO1G"> mwo۹_a{kdm;c*(((((((((((((((;P  :~{JH>XYp[oO5?]S?\O9)Y7gz lBW˺ l\}~w6%$c? _MuIOR['DVw+(((((((((((?dž>|OxZ/#I7זZ{hzm#K1WcKn%dx -$G{GydOٯHka A<^ϥ,q\^s$j)odvTcngx5d_%墒u2#)9;$^k%kZfW~$:mRxF[pn4i-x K;$S4 0IzcG=C—:& ;j0\&{ꖺeݲ:y\6)%=wߖ]bǞpת^kt{_cQ_y}[XYy0G8yK{˴hد̀ \5>|u]/<7 hks '֭[[d{4;2M6XM UJRtp15#iyu[#j+τRo[ڗį[ ~K."ڇ~i+[is4y@6?S/5>;}_Zj>+-5 xcNfKYR" I*PքbvbWMz2E=-9k{[n_4O?_wly}B]QLMk#,I#,JSSM D|6<@wg}8q0HG;_al`7ږw>%gwiHV[S%iC3[Ʌ; *r*]]28WQ]>%$nk]Sc%f>>tJQ[OE>u# m,QÂr˵e_?h}CRàɢi E]}],g$D8Qw_PK^ tG"tM2[ܳGIECGmrZOY$eK mv˵J9P K6$YZiiPtj8˕-wk텽p$I%VdNԩnWJW]V^-wV]+цT4OP[F})| _ڝŇ5=uN. X W%mU<y}gIuߎ`O'Mt9oÙloc}aIB8 j6m2L,Jev&"V^-w[Oskc˙5 JVƢ_jKFR ^@QS/}W֯[2:о 7(NxuM:|]N4]JD D70@z2SH|Q_.O^/ߊ#ܾtZս[%Ͳ[l'"he/~Ŀh@'iZc&-ֵ?=R{;ilgSRM`%}į^}G6>w_>!%ƧKm$MFB$9Asu5oⶻ%{颾8IKN+m?j<^ѕ߻xO½oƾMtGsǪ]ke5NgG̑D4Q61 wOZ~-_F~)+Oңֵkuj#iӒ}*0; Sܣ4*-IÿQo|9b𾋠 szQteay)[CU6BI|tMj|>|9xĖ\_)mv͟t[JwvLRNL^EZ=Wj0R3j¤䜷rrWwuԇ_*xLW#h_Cy{qɦ~of-r)#KsԣbK/kWK |ZG5+7uA,1 j!ՈP!p&Gm|^$=GZ֥5^}22UfJc_tws-yӴdnmF?+U-Elx;54薂 _-7Z3##Q#;:~ٺ~+xþֹmgPo +bHST]+!`c:n0~ϻ]]%bTs Ҵy\]W%Dee$ͫ~-=44{SZ_F.-'G|>OúG|Oq5mMnq]KIb,^uDiYq#H^PTOҽOqm])fp"e}%ݫ]ٷb4kx73NJ4]:\ 3j:DH"LEwIm⹞7yPZ5'݇xh< gi7v76<׸{(@ZV2WkV?j?>;~%xN= KXu1[X s*ʊ%NӾw?o_߉| kZh+;gyQ}xq(O <$>`~C;4O xk ]^mN66[[KiFIm_Hi-C~j"΁[/ k^1HCk=$Ȫ2ʊe?Gǚ4?_;~-| ˿i.=*[KVh.$VP/C):Jͥ]Vis>jub 9$w{)=uI]0OG- ~jÿڏ|3aAmηKy5Gms д0:yLXxuh~8-^-om5 QEq 3`T+b=}}@qxObҵuyu2}F{9K-U0?too3wJk?|m$\.N I"YaUm#gP(S)^9\z-bټkfxhxɩ]vkm5Y([ Oٛ@vy=[O*';kV+es[+]1v_3]ϋagWυ?]3^2 )$K,.U,Lo}ګSֿ>*8~{hFDi o"6%;i;[p~"k~%.h^ i_ X4x^LN KoiyL&`e)}QS%|WnhTERI6=ZoFi?#`j*Iv&Q `k/w׿_xg@-Zٯ^ ˘i{nf[dUYbeE25y?hœjJܚ 0KEiIͺN AI*)BjPR_|/ [ ӫ^e̒kmM=OJ'_B>&E|a+k"4k{Ȍwh"$NΣ Q^:rEX|KqxӚ"\'ͧDycީ$v}Z~I:+=x1ߏ?nn-|; iy. ~|9zgM5^ |EkV]g򼗁 f" ż7hZ˕ok3hӿh-xOkxxSouSc[x/oKs>j] =z;΅;$]!hi#FqjQ|3QE1Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@~wN3F>*@u- J!|/-Blޟj驞Ⱥs/S6o.>1脯IuxWع]^mKHDŽ g꒞#OE?yEWaEPEPEPEPEPEPEPEPEPEPEP述mR[iZ&"^&/c"Hu,AehPu>^|_ 7Z]k&+˻{feߝ[Eg:P7Iu[ַݧCқrM4޺[{K%~n~x/ƛA>-NnKKx 0,_ZKHѼ b =o \OG>)ufB;Y.&[dgy7ɹgJpq0SIFk{ﻻ}!?gG:¦M>\ 6f<3U߿Xc'']O{[iV^ZjזQ.u5݃5C=%feO^&3J\Щ$}IGI|'⏆:ׅռ[{Yzڝ!s\@`6 'c_?UR[i7_"nZ|上-З(4%rGYPk[EZ%Z. XR+|yYI2IWO~5wźQ|}wim ~^Ƹ/n-wn |jvzF}jWZuMVLv/%̒2ݴAֽɆ3N5${7k魻G?h?=-*k&:A(X iȘ. >mYZ vqD Hch@11SIB*ooh艩V97דj)HL_)\j>_ Լ_Po;InuW.Vh#c`8~&SռOWc4Ynh$gx! ؛}ʼ_,߲t}'3VL |'SW6N8u N=!tJrmɿ#aT9bZ4ӓڲi`M4SsR%O MUxߨ ri ch!Au'/Y{+ ? _z3E4B+y.Qࡔ;Fҳ+3uEseu[#_weD~ ey:h|PѥEz]|~J(;Rdm^vv8sXTwwmwWwo;g ixTЯ_ZKmRHYM.;{ۍ5gıy"iʈ4+WgoY_ x{w"Se5VS+36x6%6*MGOxQ!\[iZw(Dgȶ~!`]&:q(~|~ ,7 "ץյ٦PRFƌߕ]QRf {Zx|.Ms4)VAcO_7jPAy=JIxݮ`k8f1I"y $~rJ||9zOmNKwWhl..^=ȘX#@Bb:πh-|#-m7T"-V^'4hoy,.s*B1#FL6jQcñ̷M[?\qH` ~x*R ykӬwev[CGW).H]٫(X|}~~^&}[^\YEލ?Zm,Peq]o$0pG7gCxs!ϴBcK<͟{w򟄾ޓ. OjvxJ=KND7 Ց-b3&X]ߺU<DŽ#CCm~ǟ5m^?\\Caΐ[]bO+un1w(Wr7 +7l/{r!Z*-mwZە5]k߱|bsX> ou=:T!-nE54NJƊIaj xQOj4=I|CO4Iu, "BO./:O~ O>:\Z d>>& zך͉c&c̒O_χ >2-G^u4ky$/5 yH9!$opRO~kba+JZ❗J1m;IEG7+lh_υt?'u^Xi6ޭwum8u)nni3\_{ᶋ}cR]ڧ-FKWuk:,CH= #594UI'+m}pCy?_^/6_P^59u ^q\G+xWTo-.=O/ EJ*qJwCOv~.5H=̷Wb~y #?NNi.GXmSZu}:5FW@a}j{ץXTi^MitS_5qaXkZ]mOOMyaorr"'%cE$P;__ qx;tk5Ōmd,ۺ8ʳ3hϹ+ԭʧ&쬮ev^G#߁^𭞝2fj2j-LrDJ^g1 q1<iZZiHR[kOd 2㄄_ܩ<ףTds \v<)Y=΀ q)/eJɻ{gs! |a>>/"i:Q,<ؙUeo- #+訡ۂc ~VjsY\]K{^K+~i!A +b.yͩjeW/oFQ}oܻ_~ 7v'+ml=;EnGˌ.jxO¶ƟxZUZýʍ*%$ZPQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@~wN3F>*@u- J!|/-Blޟj驞Ⱥs/S6o.>1脯IuxWع]^mKHDŽ g꒞#OE?yEWaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_SLQ cKlB=R Ёc-7jgğ..'ͬ|˳rxG!+e^@6.~v>;כ|1脯:é-|qQxw~EyY[VA%YeicF~4$@iXOHu?_ZIUrO+ϱ5pJgbjҕγ3?3G.?g)f+q5?q?O4Wgk\_a?q?O4Wgk\_a?q?O4Wgk\_a?q?O4Wgk\_a?q?O4Wgk\_a?q?O4Wgk\_a?q?O4Wgk\_a?q?O4Wgk\_a?q?O4Wgk\_a?q?O4Wgk\_a?q?O4Wgk\_a?q?O4Wgk\_a?q?O4Wgk\_a?q?O4Wgk\_a?q?O4Wgk\_a?q?O4Wgk\_a?q?O4Wgk\_a?q?O4Wgk)>>{(}+GDFUX1_Zy6#QݻQ+B5_UA?q?O5G_cK?ֲ~&ŵ[Qfu+R2?%^[8&Q<iW)un~ȲJȀG0qc=;_u5٩;;L3?3G.?g)f^oFP j}=;.D?jmn'Gu  'iR@ Il> ,RCldo.F'`(* Yr+094oq?Z/3=3?3G.?g)f{_6ԴMs(Bd&dwX};9A|_imz K`X"mAE玸Z3*Nm}>]Jٍ63z_O?JWgh >^|'?St ƭiWwU}, +FyH$%Xm BOT>xZZGҤ-o5}0oj]Yn T$x_Yi?uUA?q?O5G~ :_}Kv4jj۝b$gi-Dj3 t8o_V(ѥVմ[Mm; iKFi%cvܴS\~*SUA߷σ _}n?q/~3 > _}n?q/~3 > _}n?q/~3 > _}n?q/~3 > _}n?q/~3 > _}n?q/~3 > _}n?q/~3 > _}n?q/~3 > _}n?q/~3 > _}n?q/~3 > _}n?q/~3 > _}n?q/~3 > _}n?q/~3 > _}n?q/~3 > _}n?q/~3 > _}n?q/~3 > _}n?q/~3 > _}n?q/~3?f/54=}ۘO١?vk=+?)&(Cu!s U( A?:οaꤪcp{IUɜ/e f|C ޹_F<#`[?? ?k_; lBWRSaԖQ>wøUo?]袊,DzXbO!_hj?ͧ[XG[@\8:AQ}:U nO=Wşÿ7Wşÿ7ϿظױDg{};TG!Ae2wWşÿ7>a3hFUgM(UgM(Ͽb?+ѿ|Y=;?|Y=;?1_ظa3k~?~V_o j?1h#3ɌKY6?!_R*{xw&*{xw&,FJpzw4hBm|1wu]3៍-=Eimt{\:pGvb.O4mgPso{>4ki*|k>Q:_g*{xw&*{xw&Vqm٣i_S]K4BķwU>$lNnh?/;3C<+/7g.sщ\4(畛nG{ʾ,ɿʾ,ɿE\eZ<߷kzKu_MeIyYx>ڏßǡM&e<+2v}tE"'T 53xCKn&ig&+_f ;v?|Y=;?|Y=;񊷅ZiWnп朮.:ۿSQktK EHQky#tYZ2IqUE2)|~9/!k Gki>c4要dU#p2-,}_uZ q7oG4ZYʛ#̕9UgM(UgM*ftjcm͕,6i5iFg^ Q Q0Ͽ4W*{xw&*{xw&bc?q_yʾ,ɿʾ,ɿؘ\gWsEz72?緇2o1G2?緇2o1G&7}+>g^ Q Q0Ͽ4W*{xw&*{xw&bc?q_yʾ,ɿʾ,ɿؘ\gWsEz72?緇2o1G2?緇2o1G&7}+>g^ Q Q0Ͽ4W*{xw&*{xw&bc?q_yʾ,ɿʾ,ɿؘ\gWsEz72?緇2o1G2?緇2o1G&7}+>g^ Q Q0Ͽ4W*{xw&*{xw&bc?q_yʾ,ɿʾ,ɿؘ\gW__sn)&(Cuτz N_I? Y^LyipNȸX15?Qyo5u~9P՚_53iJN5foByv_D%zO컫zo_F<#`[?^'Tu%O*/nz(/?K+?zW᷊>)-}DoKojxxjJanm,З<*oGj?g^{K[~^ @Ʒ5ռ]k]>'yKiQ8-ⴎ;gCޫF٤OJr|>[[ݭ̲bglA'|Ѣw',ѭ5xš?o_Y[?4/NIf[x쯫Y]7~_*1X&пgG5ǃ(>.״OڬYkK!{[.K*D\p„;V~ΜuIIYN>Nmo5'W?SxGIִ5+}f+m)lo!Y8IU@8hUt +EX.qO+OCO߀|]O\Fi-kH^I|*'W?gA<3'|<5rW^&u{{d5ṑ"+H4b!#FŃm4_~i{ⵇo#$c(6OO][oOPljCY75%Aݑ\W(7%Re|sY3xwHTKh[̳@#*m~~ѿiZ?7NM;V[]ࡒ(&<ݣi4~ʿ?g #ǛcĖ:, c% -Z*HAo(*_j|u;[h$}NWFQe~U_ ;?iߺ𹘁$N?|G(м^xuyH^xwxRWӗGM=}c,-d,o:!͞4QBi// ZOlN{滂Aj,]]%kib;XhVwkǛn˽ەMjgnߍֱ/eOMS?i뽢N S?iT_D_Oh S?iT_D_Oh S?iT_D_Oh S?iT_D_Ohs /|6ރﶢ3ONZMֺ:_֥(((((((((((((((((((((((((((((( i]OzBg|0T8?[g_i]OzJ!|/-Blޟj驞Ⱥs/S6o.>1脯IuxWع]^mKHDŽ g꒞#OE?yEWe}O=U}O=PQy8u 9(+|?ǿ2K kTVos;@TS*_~ ]@о$_7O]Gj~+Pڝ1EbbNI#J.svK:F;{~~~~'6'AwşgۦoXQ-eE{ ąn@+dq|Y?e_ċO[wI(6FL6$vJ~z;}|MV׿N>2h2k࿋^|?Mwռ'w^4!L#Muoewʤ5oxD>x?#h[ 6.|Gߖ%ݿYuv֢XI w)Ekq=TD-< )U&$ WDM[Ic sio/wmwv~k>#Vox/kάgkK {Tf2C 6N[_YC7IY JFP3v~$nMF۫KOG_(~Px*}{LJd-,od/5}>I)H絝Ckck)68~Ɵo<2X٥nkI+"ig0D8'*^_Bc:R~~~~𮁣~&Zng}}zK-FI yL)m^[oxwW2-t_Z_nUx!i/ kuv:!X1WK5vns}ee’韱M| [?PJ1 }&4OͳeDdX8 H̟%o~qw}rlrщ|O"Ut]/sϭLZ?LZgkL{m&Oƪ\ EaWdee*ɮ~Ѽ1h˫hCGL5Q%bMS%Զ(J龋|Emj/֏/־ _bvYyk[nM2WFbW:&Qc6b1RAo߱YxXZ436}kQK0v67S~C(؅܀'od_3J+:g켟 Wwq|}}eKIJ:)N143ZD"hKo&/ͥ]啯o_F_ Ͼ/.~_k:k/ kwkZM72ji< mDJ 5w>~|Q?Y\-~"-Oi.cBU jR-ܟ}oQ_xD>x?#h[ 6.|GߖsO OQV#lIaZJBRn2@.@ϥk(8ʤ:|_ݩj)FtZRϨhOكO< 4 3K1q/sܰ%-|B#cS^sxoa'7 |q@|?kⓩǭa{-"kiq6fnJ(ӿ =uZnjJ[W>3e;_?X? 7%fգAla+kq$B#c?c_~wEk:; Amuk:]Wi<~kMm|)oqoi.y{Ysf c|ֱׇm@igl֣}ޖ`-lmn܇dQ Qq!?eUa㟅?>"Dz̚?'<:(ge=B2/ۼ$=Yow~Q_*|eS6xDVk_y2}t3!8x xe?؟HΡkrSRWG^ BGVuH7Hg^ BGVuH7@Ex';o Y?"v'?E{O$gP?؟HΡtWñ>БC(b| #+:$P^ BGVuH7@Ex';o Y?"v'?E{O$gP?؟HΡtWñ>БC(b| #+:$P^ BGVuH7@Ex';o Y?"v'?E{O$gP?؟HΡtWñ>БC(b| #+:$P^ BGVuH7@Ex';o Y?"v'?E{O$gP?؟HΡtWñ>БC(b| #+:$P^ BGVuH7@Ex';o Y?"v'?E{O$gP?؟HΡtWñ>БC+S/}{ xdhUGew( s z|S޿=P  :E|S޿?R Ёc-7jgğ..'ͬ|˳rxG!+e^@6.~v>;כ|1脯:é-|qQxw~EyY_Seū_SeūQEQEWzÏ|\?i|Wxz}GXM.tV+R$!W2<}y_Ikׄz,Z/|auu/Ky{{-D&TV%ƃWqu_.bni٤ܛ>oOCOjNT4Xf4 wr|8'!Tq\woWunÒiz76i^HlBM.)  ~./qMRMD?fxQ}[>K]"YV{X{^-|dBJ_4Wb+|=(oFU-OZM.Z ! pZsѽ<}M}BrҤ餯M٥m+7$nn߳[u&O^mmӚ6vm}6ng,4dFWo =n4[cm{A A<2}3oxoTվjڅL>1&73Ȓy_,:>R4h߱Z/_&h!?nt[o*KrppO>!$G9xÞ7tpQI}w\+n[嫯(g$aּq⬾Eܫj^mɒ_:b -J%YR{[}oʊPKJ|V_wWI >G>k>e㾿$)vE4kna7v[(a<@?7>&|Iuϋ?IxD=';&ђMe;_3o|`5xz/^!7.|2+SFk7Hl I3//Z^/>}~.gcuf;dMZM,.?1:Pk4+A ͦZF~Dw8. k~g߆ޡךxH65wזWM O7#aI(Gֺ{2 ;' x񈥘,7zgş~Ŀ? Cz7<7xm[KȰ#A"y̋:Hy2ɍ\^lRlו_dBqwNw{ݦK?y{~"e2s+OG/Dvs̱@ve*l.9Fg'beo?ɭZÛ,/mn㻆4KFLBHO1B!`~_/<x<s&gM+@{Ygk{]n6⫵cػ^-tv? KouQFI\ڌky. 9UE{}Z{'iI o\]x2~?>3xCᆷHՏ_ƹ ME15!)z$EYFc>[(o/i,,g&OYqml ]Dy2ۼdfg_h&s"ύokh@g-:ky%cKw.6\2 I j&^6^-/Cc,wK$Rp;$e_}k/Oz)Kw%sdUk'OktGůi aN!Ӥu01qIfGK}tY\֓tBY(cx$L+?ࢿ/k6߃xN_  ok77Siy;AѳL(]Jl_ihCf~%^g-CJ]6ö^[j7m ys{ xd!+t9:m&?OI[vq$(X|KukwZ~ |]]_xKS#pXE=}Ɲr W45\eQydH?Ÿ5xGZ%-K/5?7N ^ǪYfZe+,3kc3<^7+5]xc ? Ň:!k)1\ܲJ8`_>o⯋~*f]RM.IHi,[Ipxng^]>x-GSVR`Gsg6<77$@D ko*i/5P"J;os]˽Eu~Q%55M}~ikem)B4|;( ' @ºLy5l\Ng Bǖbk_D~3T<1> jmū.5<(PE9nnQk/γ'?ƿbw[O e_>.? vPK,@^ -H_x F TۧT?)c={=uY?~#6-Yo e՛n Uv?oo___i*Fl$K+$d&,`žIJjOƯ>~ן!@dVpO4 K&K7f]FrIQ~>4=NmO>$2[IҴ[i5Geks* iմ`9U%ًZh|=OGĭcε?itK-m/'-4w̆i.WTZR忝g[_on̕R5b+6Um.+ڏ–7 >&s[&A uerfPl:HXW|KukwZ~ |]]_xKS#pXE=}Ɲr W45\eQxKI~БÞ)_ k կ`[h˲YVuOb3 !࿌?r/_x>ĚUPrH[XJ)j2Oi}g+4=|?OdAE׾H>2U.Oqj_Y|9we=&=P}TC4j)Y`]_%6_vPZ×OKk Gxl"nd_~!᫟xo]2K,%Т.Ch +Vb0A9˽EȢd+q:}e//)7ѽekXN ,>=|P,>)W! g5YO @MfJQ_(#j7^x_ƾ<҆)CM?{mlp-E4(Xcf/geC#ÞuG>(|>N7~adz2e4sV#:k~߿Ir 1u7om.`7 mZkDUx]m饿[I6ir7wڵxٿem3~mu;k:^ iڌp]V-!__S:>xcC|om#K|A%v/\jxH| N3_ ~?_=S/4Wo[<_ILQ~>4=NmO>$2[IҴ[i5Geks* iմ`9Uyy֩4ZjkbIM6vzUQ_~S1|+M)H|6Y֣g.ڃIs%dEⴎ0êԿj_KM0ůnX^{؝[F]-ӭͬ| %myюDӾ󄗪WDh?࿌?r/_x>ĚUPrH[X^K>]xNҵ*rr:}M5jx_~ߴ78.|Cu^9tMLEXMo$,z}ީnF`+bQc0 )WOyt~:|8u?zf᧲Sst'[[h-igȘg7WONqMwk+AFRvOvmQe_ j/<ϋoWZx[nm`[6{զ@eWk/?]ůQ𢧆743[/}^]BO2HhgaevRRNQwZ?TM$i---/{޴W~njR7kVӠ]S}ur g6$@mrO5KZW>~v;;QgE "A[Vvvz)+ZofQH(((((((((((((RR_^ͧu?- u 1Pm~^ͧu?- U( A?:ξݳzx|I"Ʇy쿡Lψ~w?/KHDŽ g']]_bwcy/#-JoJx:?'xwxQ_?_ZU?_Z@Q@Q@|~i#֙G_t:]ZZxCՠ6U#7T}E}a^ >-JM'Ӷǧx>'+ x"m&KX䠵 Ac؛@\.ь`W3~IH>.| \3÷~Jӧ! GK&]T}Nܯ~2RI$[yk/ ׇ3NO#pB y&[;1kP(noNP(м+#eVWGE)>wyj5x;z||% "`iDb_f<;&?3nnqkxPut546V/w9Nm\D{ (o}{5O:5_mm,>$.Pi!H8UiAcYt^I x_S֍'VIwmd3|c&:w輼}ӷArYᄑ Gx{*V>]xLV~!ac r Xu&> W/x_W4JMYC*nc8]Mz q?g|itSOҼ-޳[_ϤHw#4 Zd\k?wxJ@~ +-' u0)n$Db0 o|}/W|  S/>.]i8,uX# 8cÆT/A¿y$^j@/QV[4E  w|{E7Ԕmn~ſl \|5Qwr $Ѧx1^I}ꭸwsT'fOc=߁l|;?t4; xJD !۞Mzoui> g#1?zgï|#c{D7w'𽌚5Lܙ;A̮s G/m`gnw|y٧Aҿg/x3\}z%os6ОlƊUwN ]ed_>k |mLJaCoڴoOkRLUX8 Ȯ_Rk?- ;O%ݛhHt1JsOz)[tUޞ_[Ÿ-4,~ *U^~T7-q0F>W5[#7jt,y&7y(ĺ,qɮ<J[/_{9ߊ|'מzߵiZޟ Y*$p@#\߲/›e cևF?ؼ'!|5tQmrm6O 95Wo߮VFERnm 1l`]ȑ]y5sGx{*V>]xLV~!ac r Xu&(v_IGo,gp~¾WۿG3;~WgwgH/wB/ ž%+_FO خKEKq+0#EkFmqZ'_sx2ŴrfEG3DjGw)\6Nsog>xCrhTm,SsIOzhmI$]ϊ'xzSukZt7W%X2edbEttT]~ȿ n>²p1 Z`?b;n)!<& -tjhXͤ-L  V˱&&g= Gx{*V>]xLV~!ac r Xu&_(?\7FGFy~^EM֛}%2ExSijEq{IbIqn"t`ckD~k|;/X>_ &|ȚPB+s]޷O%k[G-og>xCrhTm,SsIOzۏ0_[~/U?3m,5{mMŴ+{ds!۷onmvs[tk՟ޙ~ X_6sUwhnti8/ 0y' 泵'fOc=߁l|;?t4; xJD !۞MzRnWoʔVc5؏Lj A2h!2dbcrgU2sec߄3/z>n#ػ7wؼ'w5Pە?Rռb2>m?o_SLQ cKl">m?o_RD?R@1u\ _53OTe f|C ޹_F<#`[?? ?k_; lBWxRSaԖQ>CøUo?]袊,DzXbՊDzXbՊ((+?g>?7^^ >-J( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( _U-E/|*e|S޿=P  :E|S޿?R Ёc-7jgğ..'ͬ|˳rxG!+e^@6.~v>;כ|1脯:é-|qQxw~EyY_Seū_Seů,Ci5/vsIZn(2GYB1 `Z-(KkvSӮ5{]0Dbϋ?h?XZ~5[w"+,Z_[`Gq_olöiF?.>[Qx3Gï~kۥj8TEU @iSԤZiu{l}B}[|u r{Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@E/|*>b2>m?o_SLQ cKl">m?o_RD?R@1u\ _53OTe f|C ޹_F<#`[?? ?k_; lBWxRSaԖQ>CøUo?]袊,DzXbՊDzXbՊ((+?g>?7^^ >-J( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( _U-E/|*e|S޿=P  :E|S޿?ॗ)m!^ee?H?p^?S<>$}OXq<_Цmg?;]}%$c? ^.f,ˠpN9%$c? _Mt-JOOoMPEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQETR_j)/P/oڧw5}I}tx96zO_oIio}euOxS4 +3Ucc9nokEūvnϣ8s,xu.W%{=ONGVi-mWG`,}qNtO.raPQ_N||=]_~~-q>W$@:W|U(NtirB LJ6zE:ӛWiYi{~l (0]cыV*]cыV(((ho%{x''Cܷ(袊(((((((((((((((((((((((((((((((((((((((*)/Ti]Oz?NK<_:zEx' /=zׁ??x֏??x{EP}O=U}O=PEPEP^ >-J ~YC^0HM"lGR;X証<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ h<(e_ j)/Qm?o^GiGO@_gO5_gO4E_Seū_SeūQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWͲ{zz߉C gPV-n$DKɑQ% *Ҿ#sTW W_7z3>.xW*A}x-MR,e6LՋ$ l_޽F":}Hڕ!g6 1*[dFO 7.{خ?7(obߊ_ߌX/¿ou?Xּ۹n9l]Uy2|6Z-=ާ i"Hux+iF@N!~y%k_֍zmY]}5=W_7z\oP^=K—ѥ5VtMymPy4h,;rJ #s]X<6KKrycF-~N1UM=3i<( +٢+^)TY\ Hpȧ <=ci&b(bM,zrIVa[` JC3qAC}ǨW !t~r__GggaeO%nJ!&5]Vm=4ch>!S$R7 hRcm˞ky/g}~+†Q+ =^5Ok>"IzֽVfh.$4O&$/6m!ЛZկt]Dqe]>qpR7o  [y\oP>qAC}ǫe{)CeŶ&AmVKyWNo7 ˰o,/gϊ=_̱[ڎw$:"1ŷ8%T(5}oK}ʥ;.c[W[Jk:Jkw""^L(UU@\oP,#sT>ͮ5dI5]f+WwSisrED]+߳u;y+ =Gخ?7(ox?hKKsP0h d.%Kynm$de>S07W;?$n!:}o-Eh wv3Wv'~3O٢EZ|ϕ ^]r񡳵}flnw8?ٗA,:EQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@I.AifC=}{6路j>-,~[ cM⸵itR>`Qǡ}h7Ǚ"/gOfc^I?ďk1xYtm6pl]8TET'-z+^Ur;WuK(]cыV*]cыV((((((((((((((((񮍤k閷뚞DueIԔPǚXJkcto[WVLlo0\ `cYw.5=vg-!1SzWTP$-׀RKDkD[ۦ퐕c]7Mr'<_6ĺld{9;U}=4$4jn_h(D wࢅO*xIuvTxE\|1`󝡙$R G1Mm? /#^4sU#0ִPZYխ<umy)ctrZq<4?sfE+wnX** >H$WشP8|;f|ct:ʷH.F Ͻ2x?n4]<)}@A.cS+l\ U'_bΏI MߚW;G%BWtQùWJiOM; ٖ 17c88F 0 oEs&6Z}<7`_y:y]vFnOF[꺾kq[G\FT?sS_MΩs}s|>n.9!˹mۛ9<}E|sxk˟ qqy--NN?t0iNSЯ<-ey8x&9.g +)穯,u+}_CMƕq ռ,NVG^EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^>m?o^wk?h wQ M,yvx>m?o^gR-oGaȹ{p?f=|,|k$_G?Gú|-qxr >#$ҼaC*J < /oβ<5x ^}F %5}m];\1\h4쮴4ԇ_.Z#+q&n9U|Qwi4 V=j85:zf/f2pQFj1riwvLƶ")Ui~g{/uF-X.om4?w#@8`puґ෿ c8ÿT_jChW_?9;}b"ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`""ෟ _xwx+R?Lgxw⪑H ?լk`"" BJ2 BI89Ӫ!MO[V&8d>lVM`i\Npה$]ؙrҫ>ɧ3Z+A|i/4=ۯde?G ~O]M'ot x74+ & z=<P~^s Y{IDR~.@{6路;5K7D%VxIpC G, jL\&'asPx^ŝC\wṘitZ]ŮrSG.0 $ %^s|.k6/f+ۣF4K 4tI#G\F[A$yYQ׏~A 9m"MƪOrI$I$ԚbiEG~^>Ɖam*EU^w6¡8|m@x 5Yr:,^!P$5/Sľ($JMm>O-m+]d6:MdJr%a<g#bOxTfh ny?.m.Yw7ћsdrsfMBլ?-$c쩤^FwO7ܶ1w+-;M3Df(QG%Y$Nhpostfixadmin-2.3.7/DOCUMENTS/screenshots/postfixadmin-inital-welcome.jpg0000664000175000017620000043415310676263533026323 0ustar davidpalepurpleJFIFPhotoshop 3.08BIMICC_PROFILEapplmntrRGB XYZ  :acspAPPL-applrXYZ,gXYZ@bXYZTwtpthchad|,rTRCgTRCbTRCvcgtndin>desc,ddscmmmod(cprt-XYZ q0DeXYZ a)(XYZ #XYZ Rsf32 B&lcurvcurvcurvvcgtu ! ! > %&s "]#%Q&(@)+5,-/V02635 6}79M:;=L>@AeBDEzFH6IYJLMXNPQ]RTUTVWY9Z|[\^_+`Wa~bcdf g/hTijklno7pTqorstuwx(yIze{{|}~݀.>N^oȑҒד۔ŢfJ-ǩ`=ϯyN$дn@޸wB ּc)t7¼y6ůl)Ȧ^ˉBͮdЍBҠEԅ$dקGي.wܿd ޭSNMSc{1S ?i5yS&r:c ] ;p!AL!Y"$S%'I(*2+-./1[24(568C9:@1ABDEUFGI0JmKLN'OhPQS T[UVXY=Zm[\]_`(aJbfcdefgij4kTlrmnopqrtuv'w:xOy\zf{z|}~~pdYQG<2&ݜɝa<٣nI&{U.°rK'ص`6 ⺴c6 ݿU%ēe7ȡo> ̞i5Й] ӐBի_}0ڛPܼr(ߑEi @gHq)YCw4n,b Zk-@[v "(.<R^T !"%#5$;%C&O'Y(`)V*+,-./01233456789:;<=>?@A}BmCXDIE8F$GGHIJKLM{NjOXPCQ+RRSTUVWXgYXZ:[\\]^_`sa[b:ccdefgphRi,jjklm{nRo)ppqrsltAuuvwxryKz'{{|}~jH&߃{\<ΊgAҐ_:ǖvQ+ڛe<꠿qL%Ҧ[0۫i?ݱdB͸zO"ǽtL$®ÎnO4! %Cfҏӻ@׊T݉ +efK~ndin6WeM((!GP T93G*6DSdu6Ro>e?l/a@6s7yL 9 % v  s x , ] O^?#"2Hj'U![ !I!"#A#$%R&&'g(()*R++,-a.)./01`2333456w7Z8>9"::;<=>?@ABCDEFGHIJLMUNOPR9STVW^XZ[X\^_`bTceGfh@ikQlnvpqsXuvxiz{}}L҈{ohtܝ9F]Ű$Xx<ŘN̫UӪGڕ޻ Q8i92y $/;HWgw)D`}$JpAn2e C}8wEh  S O Z  p / c4 yY@/"%3Ie$X*i  [!!"d##$%7%&'d(&()*v+E, ,-./Z061123456y7l8_9Q:D;8<:=;>ĸ:ˆeԳG۟IQW"\  /BWoBk(^"a+psn"}< ,  o S = 3 ahx I|ko$O F !k";# #$%&q'G(-))*+,-./012345678:;<:=]>?@AC%D\EFGI7JmKLNOOPQSTOUVX+YtZ\]s^`)abdSeghikllnXoqSrtNuw[xzk{}$L߅yZ[V R򜋞B𡥣b)lEõpM羵u'ň3fqQԽeضE}ݍނߟ sX(zX5Z"desc Color LCDmluc itITfrFRBnbNOesES,fiFI>ptPTNzhTWfjaJPtnlNLdeDEkoKR enUSsvSEdaDKzhCN LCD coloricran cristaux liquides couleurFarge-LCDLCD colorVri-LCDLCD colorido_irmfvoy:Vh000 LCDKleuren-LCDFarb-LCD LCDColor LCDFrg-LCDLCD-farveskrm_ir LCDmmod*MrtextCopyright Apple Computer, Inc., 2005C      C  " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?!~|ܾ.E^]LIGގ9>ES.~97mjN+Jy=]Rlnp'^?ٟ+Dž>_]:iufO*UWuA*1t]@2ofk'ݗݥRVg3]qZ8#3]sӚ'Ug_Nhd5qxS ]d#|1g $ֶ;IM+QF|o2י1"@< %wo5/?EkW6C:}M.K Ͳ4.&t+kjڥUpYݸno2i?Sj=o#.nn&!R&G- ǹkK e1͕?*o!\[Gu< /`ösۋF͝$崊$$)i~u&tۭN9)[x[&s3^qu|:Aogߍ<+/5;;{w*%y]'vI@e> kSY_"YJ/M&!c J◄(q^([s^Ͽkg9i~FLu 6|^1Wn3a7Y 8Ysaq% ْl/dKl)Ҧª½CEu;K){ˁ35[^HƧTFVUW%uy+CwNoqRz) q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nt߆^}Szu$$p >⿵N>: S׵y} x-]2V jJ[+ Р|3|,񕿞ۥq}{v 62qN*׉ax~HRy7 1^E|Uؿ hWue/vQn.5].TVQbHqҽHHHHHHHHHHH|Cas%AgdvrTq_LW_?ly>x>so[^aq{c8 x=ޣj=(o.`~7tWw};^4WuX'b U+d蟊R_~ʿR?:GRnt}[eYY <d?vՏjj%tIU9!ʎ kWW45 ~Ͼ%4\h CEbY*(i?M/_ƞoOjzZkh]&hf""r+'-ӿ>5RxoBK'nWuu(;tѷQEu:QEQEQEQ_0|4͟?lďK?COY/Ij[KK|~'g=;Bw %-mF8TFcJr&~OznCƟԅK=w*qB3~Q_O ԿdS_+?+gDWya 6ygo@Q@Q@W~1½?}VK7۾ɳ|3K&qcnx+e4/ebm} ?i|aY7gF7cdQEW?टlo}kk{~ذ6#9mm34QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWɟ ~$sYT7C43@ӗ'激:&:no6?}ƨ5mVacEQ]&)~~oǿ96ZYŨvW']Vb/5XrlI_5̟Pxno u4@"G,gj:S`?@G o|>󯙻Lxs.I$t #K?>4MV 2G^>{ӳ(nۖl`uğ3W;~/^hie,v::sk,7`-wf(խI,ΌszP?V OiAo|v Do2( )eǞߠ?/߲\Qi/𕑊 xPԐ|'SDt ixSdH _ cw B,Zȶ3[Y#dG\;iήWݿ'(m8XdP?g]ًv,Ǯ1Y֨5/%߳OI~<5ak:~}XЮ6T3)WBE"=*Sq(/(l&݇0ڸvէ[VUtc Cƿ׊>D̳<94Jg˼Xd 6`O>(_ W{xw)mZGomȵv5(];M|=h_ ٟ/4x;X4B+C4ш%#$j^p xZnςx"6Ko%wIAp0H `,wc,|o~]Ƴcٷm{k쐅P#n~]l_ƚԼ/7?[vN[dx[ R` ,Ju'$s/6+?( Y۵f g{"k9fxn,P?C ɿd+]֞"-cPt l%HB=hn̅?i?-GkZY>$_ď_4[j>2[HU67G{{!ga9^% __?j t+S(|.+tB\I+o1b,;8ۻ'G%Eo/-gx ((\k(:H"NڣGi|>[~>ЅGesG-='g 9'O_^ />5eϋm}MR(u#N"62'2%A@0)_K/~|E9'5 w1[tQm-|AHC7xoZmoƏګ^/x!:}լ5xo䙒A 0at$0 ~۟o .W+ gY>ac Z>O̷zL*DAoq+`m'>/:'%_qC~G^m^nǗ1>>__@ XxKό>xV٭59<ԆYcB6R1nOPAfi?r޵?|EtHGvYjgڣ[嵥e>blX)fXuCWé]-V$ >usmdM4E ߵ޵izbjAYe 3[D, d*TE?Zex]4h̲ؐ-ܠ UX}\\7Ix6WPN|YKg_I$6ΆC#3XJTcv.As(Ě-y- EbR6YݕX nS㭿_-ONXu+[DX&[yٮR8a(cR[ e ݿKS^,nl{-\mZZgLªC(SdWj=)qt?_Rğ*=C/S/'ټ!74Kϵ|q|ֈdvFD%ο߉?˯},?k-h :rs_M*Ə-Nb^P]K~w <3*l;{XBFA( cVLe=_ iğz}NbJ,,cqQod5*iGzQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@|gRCD_JWFu/9/?Lt~b?7>XQG&)~|'['Z=㏈ |$|I? zljtij_%M;y6۱$7ݔPo]о2x/3۷|{r` H,{bfG};Q5?kཟ6x/c? :q%:A&2rTq??_CÞ05U٨Xmmoc+qjwC"7'N~ dؓg<-Cv/QxV@kio< 1IP"C\"C# 0I2~ͯaC㟅?h ~:]B:k'/%%έRi4jdm+-/ßW~5$ⱿdF̅" `@?WM>5{K:w4>i[iS)#I]O<4Kw򳿣1(eK}߳W_ڟ^ ?^xSZ%ߌ/-S4+\I,$+9bQBYߧtvkع{%M5W_O(S2Kx{J/\tC<2JGXQREPEPEPEPE| }[£6^ֿA*5"^d#9*P~WjzZ?- (~G^>|UK(-1mZ 2B9ۨ* C03ਿ~{/ٻ~Xռ3mb;;O%fYVRVB jc5*n)=wuعAOUn~M+!F8Y#>jdwf'so1D8- Ѱ%__yVsMTNޟ@* +)ྛ⟌mKTrrXF2<6,~f~ȟ>-x}J4آm{(b>i(l⢥Hҥ*UoM}HKޕvS_#ը^h-d F/7~'pxR[v^&X 6Jc}?֟QE@ygԷ'|?cew%9$TztR\1i;TwO?yѮ4QEfPQEQ_|Udte}{n.m=sFB.v h1uD}p_Kݩ:ox?['(*<1E໻-?YTkkiFҢ$Bs K{ , *x4 CY|?\Br ͨʱ>A ֊ z_ *e}?kh(l~dO'__7>=Y5=1O9BٹU`b83JTY- ~^$> Ӵt֬R(.2?K4[|CWZNe?'S`+2Š((((((((((((((((((((((k 3|qx~c+激:&:?o1MW,(qAŠRɾ(>fQ]3TenQ;.U.kNŻ: ֓沆4FDS9< NW|FRz=-QIό_n_44/5LLtג+oA?r6jwM@?UEK[ Ťﷀ01^=uKߌz}եDlqo6B9^ tVGAa"-:[WXp Xa@3^&cһUX8GjuRI%oKnHI֣W 'e I}=,ۿ)?i_uQ,~kk"hfw]9W^1 ϸ|Z OwjZdZωtq0[ȜEuD@?t;nllRn߰']p$-v<۹@nI_ާxC x?)_t|0vskhiZMO;QA,dLah+~4wQլt9t9'c$D˲*8Rqi8UW5{[Iiw.,Rivv?a)/o/&⇊ |q}[F;[}sZc0[e*4aw8Ghً0h|1U|=弞.`o/FtFﲸ)8|(x]U<xVl)d\="C2*da.M5 vXukԅEgι{lr}W?ڣ gSk%_K¾#OKʹRfB(iRH I~:j^6q|Ю5s}E"IW&HѫFycͿ>ߴu5R0\i-OAfg(s WgkTxw}j[X߉^ D22T̄U"L`ѧ$ﴚn5_Χ*Ӌ[^6~Ǐ-,6R2e[˛{+;hdߍ̤ _S2~k[I9/$@T>)Vaߍm? /~|;;DPw_ XiPH/-nU.F+-g(PI(p$Q1iu{/K>_[Jn58蹮edg|OM)WN{[Kl+Y?mCE*$2>> g~)x /Qk:7cw|bo"LpOoy(hhn?O?oGiRH}kaaI}^m"Z~|iק]x;_OxP֢T MbZ7,U=k//_ݣSvZ-ֱR,դ{I7wc _J/>'|R߀:5-E )oot"-w#V0V.dca}?ч?F<-O7>+m8raSORi& !B8E&6o:eV|A W?7Ǐ>=#׺F]#tq/ۄ~\\!`\Z޾(xs>"]үCu)-̈́RE$.g|}_nů J?מM-UӮcEh;a* cIWV^WGL]WFQ%Gu{jo# 1x m~?zmx0NpEj/&gQf6A3;~) x:𯅭-<=sm%g F+$ߴu5R0\i-OAfg(s Tի*P-u^m'uThڮjT}IG9ο>(5|C4)~=m/K[yvZZZj T>yxWeF¤Zs\ > xğ 5hګ*KEGuFX>K19U><~~_"~Te*[LOn꬏e_? 5 x^jK$!ďXjj^ƈn U$݀ʼn'u~__C/?hxFu u5o ip+9,!-c"w,.6qк׉f{,?s{}/jFl~o?ࣟ ?m"!/ NQv>!G{}'p`G .cP6X+RJZn5*'mU/muᦥP2'twVgω4g? |h<+?jZe烬|9N7ϥZԓQIb3, lhɶL*-8OV;|fּw:S ~]$Qfs:c2z%FsiQ.kV'p1?)_K^ޛƑix=J!u9#>A꽋٦wn$IyP8yT.oԿඟOtT=wߋu-S] CKDtvm'PmJ //ƟU*o_+{Qcx{Gzž}C pfiR6c~ZET~.|`㷱/wq$%& 1|9Q/C`1^-[kkHbKrTbrP|jsV[uڥי'buVi}t[ѿv*iw~7񏂣k]@lw89r&\߀ટXO,e̎k/˜?Ϳ~T+ygƔUTk\cþ2Cx泩j1Xi^15$]p]Fp] 9+ɺX$r<=M>xD- r$)&::ó)G5xT|W?|>Nq.-g(.Id>_-u\ Da1Bl|E᷸|Ԫs\afV0R*zcܢD,e^ Z5Z-4q/XGS'ׄ.[gt.n$!Y 7/4D5݄bw&xW÷_K k/-$mDI#FFeW6\zǟuU+=9"$;A3t$; :x qo:WK<>1MYdˮW:ӟL(fٳ㏉?g:h>,Zd^]BmbY  ti0X k IWޟI|$iK=~twz|=Olm{]TY +%l1Ogn'm;ۢ୿8ɿj}G'cbX=6Oyjd7DLjdr]1mOݏ~"j? >#Xh:fAi7:v%彜X-hyPF˴V0Gɿqw4/Fi_Fב$^VUSB px _:%4ngܯkmL2 خ8U-y|#J8b_{˪2xO_zLҕO"h^͢0;n*^xp8?6 ?m/ iM7V Yj"y6H- *ٹYһ/!g kOekEx)ḻH^'![u!VSyQWM~}/L'FѮQIznnrFE^61S0*_wz3?2I}i|= <e$Mk_xB [t[u3F$Be@$pzݖm^Z[XbeI.X_ٱXԜ gfQךKHɹՋKO/l(:(((((((((((((((((((((k 3|qx~c+激:&:?o1MW,(qAŠR([/|R|'n?5XNLKu6߿+Lw¿4[;隕i̖ `ttu tP~mvwߴGq>x+ildu -Sȥ݁g9II >x.}|> 7_T=IE$JAX x~&%/MfRO J)*FCײQN7^e"`O_Ƶeӟ |ONɶtX.a$bf]2Iٝ9v> x;|%xWþ ݋3z& Ls f$I95D}ٍ/JٯG[|W%&E{Yf󒟾c^'qyŷ/+=cD`1)X[MF_ WgE+.^^wo 7go.< ඊ5 4HXx#LLyD-eNѐp)i~?u_=R;?]$R88evSHl i_?fw^xJh7|7-I/BC~7,ztWbʤ\0uTr+9_W1 ~ | ;UWZ.`#ʋB׬QESmJIlx_j>!ைbv?iwޒi{Mtd?ޣ?;<3=%V2cmrg:J)ErGAՅx%g-ߋ+ U}Qݬ^O1}}wvx_%|=)crZwa15- 76QO/g|o? 4oXmRpOm>sV1LwֽڊkIs-^5o9O[ 4c#XFLDKJǻbnFvz S_)Gǿ;|]S ɡhڗln4`K$;3 Z)YZ7߇Os)wt:O4)vMP)hRU8 hcSwjewvwҡ6"[GVPJ)_kt<Oo_vd˅!c\* )(m~M/k߳;/@H;ir$,mXYM$L_EgMAxza6ltHuƅU+hZ st&wkQtI xKKky[I%w1I&_5~iU{ i].yl]|lUIFʝ#(qM5mx'_o&C+߅|I;Ie loٔ4SJt5QNB((((((((((((((((((((((k 3|qx~c+激:&:?o1MW,(qAŠR(((()*XF1@ (EDA QK@I084((((((((((((((((((((((((((((((((((((((+激:&:Rk 3|qx~cqAŠ?o1MW,(+-?p7k˩~5+vD.[GIf6B6!?djP+wٳA>gWME#-).(a!@1Wibmu+?Ml6?Bv=> uMd[_%Kdռ}ck{t..n'o;{iH񪺂w,w?t/z< T}>y}$PhlPн̳ /ߵU[Ŀ'XQ/OVG[ TP]p`C]KI$G3~_4_jfɳf*#i$FzRS)$cSk}J3W]Cy>]}% ?k 8每-"MԬ/ h67Gcv`BI u&NUP~~͟]:k^5HmאllC,1HH n$@sC[xu߈>.|;tvO 7E^iIJIx5Ɲ,_Ooqj 1޸'"M)Ҕ=Hv-/ZhޫcOlqͻ4f[>Gι !jK;+ y#~<*Gh=fi^-*3,q1#?~#i_>~,|-xNU[9MѬC: GUe@"O$\_*3ve\>s[>sh$`$'iK%i{:i_Ӧ1B.Zz{uםmٟ?xᮟ 7wx'\|0W(&uQvUcEâ2eZc[o+!}G]΋ KpVAAG ~B~~tf/|Do<|dH(c`˪E)w+do+>Y6/ihY5{Xuݼm4  ̪RHa*%~WZ4龖جG6սSZ# G"/>3BUt>Mku $(C ;yΠd}7?]?us|OMIy-숢 (X$w}J9ʝ="7xlUXzC;p{ke6g6={ះNJERM0ki& d@c,$BՌj:TC-5M'1'KƚTWEn>j _N > DѦdm;F$N lX $۾avZ+ _|3Rᇈ/[iOcu.[\ f ׉~ݿQ ^0IG?>iu-7_ŽE ρ Ɣ}J+?﨤RoQo}+Eye Zxa/[ᶤ7æS ~x$l.,{dӥrԾ:Dd_ZݝR?& "i-ә#p$8jn-7K] Es ~0G㿂mM?>/YUе(udbkgXR5?м%,7P`.ٶ-̆fer#dj\{_KZo0ZOEf1x^7mnt ^RVeTv 9#pU gvn:+μI`|%mƱ(:ҥYjyK8Ll<N}#k'|$fZ-i6rIߘatGuH$Sug.m秩_4~s᝷}w%ς|}njW>*daAJ x>0}ao[B2q sqBm?qv~_Zߋ?Wri ^ [ZZնu)ո~Gʙ<).<z?yh&Qi͵[v$;hZ/^gšx_[ *=?P ԗ-)$ f}6>>Tejga^*u߈l.C'0{XlSHn/o_Wrq{[}Ey.`;ß>xwßtI<]g-oax_(y |ºCikjC5#^jnjٰJc2~UYN<ѵnL_5\h# c'~ x#LSKWkvvNH7c#;ٔ.Ik_ Sźƾ&Yϭ^oyw˒w= W!߁ۭ^|[jKr%f)dB,xm7)}SŚ$k61*5HdV2H>o_ Sźƾ&Yϭ^oyw˒}ߴO#4~:w:ǥյΤ*D)]ZRe(@r"` 5؏=WNx[*[}#϶LsP+wu8:u\a)A-Y4W? ?>&/?លM{⦃wj~QGir[$VsOr`0?,Q_i5x~&LSWISJ!wrb'h-kIEOiTe ).~)5Q^ c?,~|bp?cCIdeWdiB7YEe$ow__|5MO6zђ+n3o,MaPYP? 2K% E4e<շ>V>nQWĿeU5;{Y&@ 0i@"_(k?|9k:eյƮt 7Y}d$1nc!7(oi6^k'Y+=tڋ៊ x| xcXiE.C +~H[5mpuy^`Y ne#}}Y^[{Ep$: ңE^k ,K>ՐG!&H|7'wmovm5u_âܥIkY&e/k iy(n>I~Ww>ĺ|;yJu$]$9 X5h_Mg!R8]zm>bDp,9w˵XJk;'h6?l+O 7+|6ԗYtađYmqm+{P>^xKIo|?m&hF\ʁDY@T7jO诓?(OĿ|>2_Ɖ> {V+6+Ѵ23FU_C|Tv6w_|e_[jme5k}=.\.⑴Ρ/$ sBMI\-~ꨮCZΈO]ϣhGߴ_iopZŽ,P(Yd0QqSHσvq{ &Ab8i%pfuQݛp}. WdtW ڇ៍<[][]&iZz?VФ惃xLU>!<%/-.EQ$vB`d3&dF㪐ou+/osB=y3K΢֚ĶS " o%YO)F|ksD-/P-.osZ.2mh 7)6K(ȥz?oMh>=C~9|6-EYmV܀imǂP0G5Vt`3xsə~Eh pN~ծzMK~$Ӽe-[ZVwsq:I" WFR`H *SM;0N)QEWFu/9/?Lu|gRCD@&)~~b?7>XQ@JW+kj/|n#^)DžQaI-W6+Dhš~>?^oھ$mkVfxuh> 7"9L{"+ OO "ڏ+Vz6ċx-#XUeuDBʓE~Rʜaj;}I(\6|e^b_|OLJhV$y"~^siXkCN%+ۤやJǟ/; Ѽakm?Mkm6  rFO[(I}I*Mƕ%!R_U;yϑT^i;M+^+Vy{Rմ ^hVث] M]ɞ2}{e|j?AC]x,~ꗖ[7Ztx gx$9;\Oggj+擗ug~gŭquX% zmݕ6–Q[Fu-d< -?-oz,^:ӵO IcͥB,pQov]s$=Ej%Rv5yy:Q?7N||+Nm֤<55pE$doEĒwď+ƾ /ooSFѧKɑ%MN%9XF\E]6E*Jվ^[M鵢iԔdsw}t[=kᏉ_ tσ~+rED G ]`x-NFf-,{*S~ڿ c7Bow@ңH`S).eM%2 x C_:*c0iǷjiշnSRomvV/|-ׂ*KAx\xciڤ7ȚYw"}#$J}sǀ>1|6;ǝKK~К_~:A=xQu Z+bxŝوM4J抎U5~UӊM7i4T~R{RONI}.¯ZO$ ?"^I/J\{3Y7eN≙2g>:j_[oƝ3D4YxSi>t?[$Hc-Ӽ#((LL?mkR%2tIlIN(Sw}.)׌}$uݿJN%xwzڗ.C^2??úI.&=ŝޠ1 uUk_ڥ } _࢟'qh Y{MxR&fi/soښ md(U>?d]/OX߾m58>Vfe oI ?zG;qmx#+-w*:8\K|,<0Y_/)z___Ɵ~)ռi[j_NÍSP:ܺ}H uHTa8}^"?kK8xo_ ?k]|1-b>ax_ׄ>((LL?mkR%2tIlIN(Nz֭9JQOꚕp[)V/~QSJNTWF[vK;z({+]tVhb¯?~*-{~4^4zdvG l>>n } s_gn<&:4xźo>xfXV'6K"2 smFy"8ʾQJ*ݢ|Rj|M5zvQ?x+Yh7ÿ0x&iTX IMtY| 2! v㞫|H<5ރ>x}3DeJi~>Т!VS9.odϒ)bb<5G5 #_iwvҌ2)GF+~*4[^(jROmdSjrn\ҫ'oWmvV{7 4;4OxAX֑W&uy-Οa%M5yr# K_ǯ|QQ|+>~89-dk qu Kd d6ؓ}o;3z/"V~a4Z4G,/.䷄ȎjHVPN~\קŪ<4;W_iK4<{ks떰#!\ɦ(X\+ᖑ`xE/nK~>Zh_;xCVo|T¿6~_$Vt GЄim 6<0~6?b/(6~X|y  5S3iZm2sgr HMB_nkuM}$lҜ7 --QH|;'#cm 4K^>!;I%֠]u+:&,/h&7l| Ms?o5It(4yX=K#x&ܧpSnI_jM5]zٷeiWRRO[%蟓G5{i ||?״hZq\KE[K 65^$<x\ğmmO7>M@n<.-bt==m絝b8{a8ٔQDZ{.޺}+vZ;m[MwGh-?r?(6iR/;x{?¿nEJ:s#0c~K q I*yGj~>u>|T_)<#h>ViP[ٶ %M=.Cу;E~J S*Z[[TOg)6ڏ6YufI|{#~xK~)^/u gy@sO_ ~Ϫx{?<5r> Ե;XƮAy4A",dD_*iR:nWu&^9Jo~Z~úOj-W>"~^siXkCN%+ۤやJǟ/+h&/n|%ᯌ5VΝm I-H庖 /5 o)1!ڍ/T_qFui)sy~[6~D~ǚN#iO֋.UԢុgmiۋc,ŬV8"j6ArT(s96{uxOǞoR]x.kxoX6"rv E){MYs[&֍5$τZߋ>1|I7㾭HQn'[+$!Om5)<ˉ|TcO'oOڗG{o_'Uώ<K}Z~M_&ok]i]1<@xxToӪ*y"V\487*|;%+NּJGϏ>{~oſ-q x|CþvHP%Kb87T ?/<_c|77GI5%uOWk&?WOV~@W[τ<3=,*(,acg*'V+ּ['?/>*_xnh~jzkjoP,le7pʱCL˷%-~QQ()=Q?z+YUKEG>hI~0_vk/ ?l _k:g=Vuͪi:վեl֯soj!T0jSᆍo)o앬xέ;^!H|wY ~3qu ~Ԫ_mZԨrO)F17KaᖓC?%i@x^>kQYy(S2C{Ȫ'eshKoWR]Ig-h[R?/e\MԖ/Z+M8-$ץZ|kK+ߦ5**+QO5n~^_ǿ>־ BuلC]>4*Kn,O[dn]I\L$>gk>%ӿh)-+?|$ɨQ\-3 ضn;$ҤfUc­/w>4TJ ]IavÓ,DތxkpWx7%[.gYdiyfyI%YFf$kXNrۼ9SꧮƒN4㷻F Vm(#UnWm~O/ww? \kQMylEw#±p~P 1_=oxWmj oQn{5U 9CgƋTeR_~VWguڦoeoV?k?u <rmJk+}ŭzBɨ%͝я %iUI+<п^Gog3Ʃ̏5tֱ3iZ޴!??g(aMB]Jy%vO?gǏi/Ox7~(hkb-ZF`,o e$mǃV&'${-i" ZN߫QEAAEP_5Ծ8\]hZk^4Ѵ|#סF;-a$Ӵo8XNpŎNBMOMm~>G?,o.xB%t7Rw^%Z&`JqxO{;ChsM W@rqtmر@ XIQM%6ߦTV?!Oo|AG]5RocRB$ҲH$r@>xҼ/,Ru!`1[ݴPLliGn+tc.O&|GҴWh_jK{,:m|Me0H~~ǸVOj:[/-KtOIe#`&Nϲ91g C}qW9~;&Sr-] RQ8IfF*@<A/2K+mၭ[l17[vc7+ZvTWګ|C>$x WJ_]K/Z\6I"&$_]x^J ZEM"VEiL 6AF5xWNM+z-B,crt*RPRo@3Iu5诞?_QO~ixO=V D#P4wY%d?I+ּ<[ mWױM5}󯢊(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWFu/9/?Lu|gRCD@&)~~b?7>XQ@JW+kj/|n#^)DžQaI-W6+Dhš~>?^oھ$mkVfxuh> 7"9L{"+ OO "ڏ+Vz6ċx-#XUeuDBʓE~Rʜaj;}I(\6|e^b_|OLJhV$y"~^siXkCN%+ۤやJǟ/; Ѽakm?Mkm6  rFO[(I}I*Mƕ%!R_U;yϑT~i;M+^+Ny{Rմ ^h6ث] M]ɞ2b4 .G6|A7|GT3wros|Vj~+~Ͽً]7~=.UmKFI4RU֚"M\nl"^ax_ׄ>((LL?mkR%2tIlIN(sv_GiGUi4ַʗnnz{2};_QiG1=+_q~֢UQ\<ghct3lGÅb)5c?'?x{//5h,d>4^k̪r6-Qj KO_PzGgM_/G|ߎџ i}SD5Ḵeڌr"ncsK$1+طPĿ²]{n{w7ӴkɧZEuvIoW]hå.)w$F_{&w׫m?0׊4c<Ex]u]CT:&خ%ϒBdBnlQ˺kf?:<xC gொ?RΗmYA]Z{5F[Ǩ]Kj-cHr"{'Org.oV].OEǺk%g%n[QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE_QKsNj})_5Ծ8SMG8vʎI6[j3cw먯H<; "?4=7M'Y$3vcsi Emg fb}潣G|-7|%]Gdѭub}^n?uj:/ʀGZ3[JЛI.WJ_LhO"G=|vZkks%0,rH Bg-4 bHKbՔH5۷_s;+Ǿ ~zd+_S{#_U(51.nbmTOUi{ >xTPDK1(YoTHi96.[q'=ŠP^x⟁o,~j-x嵫h |Dnel#n3^/,B? 5gWݦq)fGM$٤ףWOѭWq{o4W ߴ o㧈ξ:Ϳ(b++gn0~ dCG-s=/7;y|+)F\ǽ-* S/$6 5Mmnۻh}EpGK%x1/Ch"ml <Cuie#F @#,ce 2@lb"m/Qku;+g EύO8|b7;_5-t/xrx}Oͳ[W;i.`$K#y g߅3:_.TΥc#vzdQC$RX^ۖatUq<%xM|,+XÚ[ |5ꚬEu+ `< {C @o_'Lg=Lfo v_ڮo$Ko9Y2_(θvT((f崗O]yjJVi{JY?w3gIiS瀮!/Үluy5;UYdg ,oQ!e.7aڟAռ |ml/[{ٚ#4~0i:y019h*#zZ/ᾇg|DLlm.v T$x5g. P8??|6O{.xjMgƶVIiqvڌ0+m䤱"™ &z[.piK0TZJqKf 77"oĭ?L--6$yRǖՖRo/BEKO-Jo@+Kx~O |F&֚Y%ChRC睤w52ݻNm~kG]UNQpI(˧g$|ONાÿ<Z_|9m.zc5QbE$@+%v&R>1iiN~XM|P4kqҼP*%Bcᾷt_>]ٮQw<UiTS;9"蟵:?>'|<5 K6#^9ŔK)k xPM6+^ÓZi+r(E =?f{mGzmu|9΋ױOqYj}eٙn)ܮ^9dkj?[o_LӦ|C=-6}>{ ň)XEW xb]rɫjY67J̿*=k+? /t|-yIwBEAtZ@ QMJw; z{_fOomխiml~^k/4qn5:nC n9Qem%?j_Þ6mCZmkJ^𶥣G'M۵Bd3Y/IgQ_ 4?_jE3HrXwj/~"DrWK#fd<Р1Hr:NWNO?Ku~Vu&Ϳ}֍+ۤx/GŸ i_Z6 7UKZc-&eY̨Us'->3^2uO |< Xj|\ne,&9 KȦ`ΊyGFn:/ Oÿ|W]c5_hqbkw%`d}1 o#^ៈ7vﵻh/"<*ا;OgF|xZ Nko?+*sOޜG˙x=|7~_Xx5tuSḚ3 Ր[mѣdxw1~|N%OZkK'ÍGT.Q{[s< ۻ- @?χ)BĿ=Tz~;k/'[,RH'#sllT&>&|>Ơ4[Yc-$}gY ݑҰ5~g߇(7/>yՠ]>W)fe`?#FPirke뽔abkk?vruv͹Ú_u/X]WGe_h; Lz]<&kT)3 JO{.O1CǍS^+?KV泩xpY@XnB';#~xKZ?)axUuUK-F.m/ uܒ2!A5Ef|#/M|O}h>B 6qu"˶F0$+aKÑzϥ]Ԋmgja߂_{xK~e5S .(,c[a$qLoXw:X~ 9x.qi+o|/5x|wm^"w6z<%Ɵ |K֝ PvLY wŶY>.Fw{lxQIO wC|>#[X aW)d#nSX{ٷյi&VI~gtuo㽵wN-8JG~~+|xI>x6{N+֯:5͢jDFHT㯀5O߱߉м9=o*ϊthܶK &ct4pntP|V.j ~$:Wׯ4]茀ܑVܨV$HW߅)$-ox÷Ņj0WNd#`-7oϳjzM\m,j)QJnMY_M}yIw~Wj?CǺO_Qy5M~lo4gFBΠ( 0P3OKo}6]bS^c{cs%@IE)iW*m6Ki.g-urQ^' ?#/_ɧKkֶ[S<(T}Q^xO5]K\y %$YW5kߧ?.e+5/O~QgĶQŦZ#E eQ<+H"xe$_i"uK~Tww$o=)/{oQ^}OzJ7_ťgxy#P+J֗?h/|=_xBBz>_D[IIاCF;}/~|>LZ%?ң]Iy>"b@i<c`Լm?╿g8(( 0>> |F>2<i^\EuᛄCjB$thR:} EWڻHOj%_|1[zB9_K ؝$KRF®>/_?..?DI5: Z G/,lGyki$~`Ra,wQvQoW>i?/š42]BڝGMb7wdor?)>(?9CZvvHPdVT@I$HHB{{9kkkͮyY7˙=7dQ/ğ*><{#Ma~4ݬvt%KYI 8 -._~Ѿ|a4|I >ӯZTYM8 ś9 }H9J| 㯈W~w>P-Po[rPxVCpBk;R#q+_#;ċZKH6[ƻP cQ-ҌgYF]{oeu)KUyJP=גO۫)/#Zi^/ud-d=!,uIIC+âм+|7x?~%-J/ᖧ5$ZE+{wm^BZ('׋ll/|>۶{6 ga)Z2YB:$tǟxk-ٟ>~Wn O?߉k(.#0wF{%2  T$B/X۳T$Oث۪zجMH׼Ѧ~իuM*և1}q7b~ש;kMO<f;R;yDVޠaXV| A[M;Gm@_KQ94]zsI!NFIBcAG3sx W; ?ï|BV>gmV kw5P^Ci0 3#c|U6/υ߇Ԛ=kZǫ {+{%#[f=یVTiF :h*0}ԥ-Y9uo*j} *?ũ?4xw]e[2E;<3q_~)ďcǞ34 Yg=uF:"iII dF ֋I|:'ċw }Wm.(e{eȱe`vA59uk)9k:mbxoc r:yXQZR#A_"m;+"˙(+Gv[>4~Nše/|(?C_ `_?i~6bx.@VQrѫ$Po3|?~Ͽ~随;M xj_\ h{+v[keԢ8o=W_|$#6~@k/O HCbiOXj|Ih>7z[ŵqsD%EN ZN)o94GRu{夢~O:^o~0k7tE~WB[6F@Fr쪪/> >(|(P_Em%[f`,z`0)3S{ҍ{IoOKΝΊڵ׉l[pm (O< Y];A}WPL5䓪c;̄ wg-]9y]OuzJы{+=&t8-v׺zwK~ͳ[ix׎_]g> }WOqjxVTOnIʟ,;goxI[χ m~5’Ax{a"<-B˙ YE}sn뿋 :b" ]9,У9ȭo~? zǟ< \#B^}idx㍭I3 )vZT9qM.\KOu^9-paE}ymuit>x_'oXk k~V?]Z}' kC 3[ {r%V3g~|`]+7_ } =OwWMii2 e"$%Dk.̌W?~&ρ?[VRa7ڼX&a-mχMğ5]3&iB-, Y!Qvb1.]^)-5rrk+m*u|aoY_'tO> ~|n;i&YayH6MlpYa^a> oDு!׌mw+iEcA-XUW_?iφ_ [|B<̫uEmNlb IF 8?_۳, |A&`QU)Q{ח'7Eͧ4踯~#|&&~4aƾ >K8.eԢ/œڭn 6GrWr^su؇~zW<5x0'Cg#5sxbN<swY63B38:Oo/|Bogw}v7Zh6|ډ cl~*a 8'W"c^4$-%ŝO.n$TyyarpGV۝YwOikuIJ }t&墺v~/߳l_(5YtUj!խ-.@[Drk>8x}g/w,JY| }k7x]mm[klfAZKm+yt{w2(XETkk_-׼Ҧ>^Z_wq_xkOkDjK?\خ3ŖL--k-B(_H#$<_k? 'u!|kRuq#**"+NuyJZEw'&lT%((((((((((((((((((((((((+激:&:Rk 3|qx~cqAŠ?o1MW,((( >4Om_gOOZEg<7]xf/ھI/ TΟm0~E~o_u*4X 6j'{*--6|y Iq5N[ ۷ ??+ 4w⇉ f!mN#wu۱b;xFuZ-V;;KU$(2M+* $G$ TN IWy.g&ݭXUYsI[/k%W_I>)K <=NxڞV4eF.K{gÚPzoakFo<;K;++k' &߁O~5<)a4[-ܥ(#UcsT~)~+E /v".( 멮#T#f.j?fiAu^Ö^nV*5NIW{%S[Y4_goZZxǟ ~;E3Mןheڌr"ncsK$1+dORO>׿gԾ^!'uz~3"IEGwt86LdY7q_^<oY|_X61~-5==T{`aXbFA3^=)?O/d2:Z>.MSsisM'!_79O"/g>k7iE{%T^_y[i5nu_'G⽝ޙ|6ՅԵA{'Ze O`TdvBLhW+jčHx]m5 jk+sp$a2_v'9^QԬ4}ڬ"kt+v8a;@fFEۧl_5 x'ÿ4{}cXנVVKGn͹{ysW%$7ϚjVZuͷ;$m{_7 -ľ?G~>׵X/}k^(LWOgs|ɥ>J i"d٧YZx񝮣ω&7z[ŵqsD%EN U/BJ+.}|E١ԗ8YԒlo9/E~:-u46o?+k>!߶RO +G^}sTAy[tB+-}A:Ծ|?"xDrG&klZ,8gS촨,3n~wkK綖ziJZ?&1o)[߆>|{>~?<Ϗ^6V)Z,5/ ækvVCt 3ye%ojïoF_Oiii>5Uo/%XY-O41H'C/:O˿_>.mu}vE6*X܉}Eoh?/xG~ ojZ+]~kM" ߼ 5;E2Z2ه@ʾ>m<-|g;S~!zWo`<z5[mBPuC6bY,͵# *U:3kNW}NxS䂂{(QIu.c}:#$<_k? 'u!|kRuq#**"(\/E ((((((((((((((((((((((((((((((_s<_J(Υ9LSU? (?5\o|>(( 0>> |F>2<i^\EuᛄCjB$thR:} EQ??ڗ=c|<94cPPe@֙-IP |vkh&~ҟ >.Rt | b{.t[5)%wl;el(xXz?િh< w~ͷj&(6 6B)h渄CҾ }ź<3OAoI$I]y UyҥzpR*o笔ʭU'$[HPqRE}/?'L?/|(9jz#=ZPҍCI-YV2YBdq鿱K.Do|cC?'/48tk,$#G$ڼz|)Ufp~Yv {cwl/ УSTyp\aߴOU'u]zZUTi-̨O $3nʣ*+W=m:1oէreo|ߎ i}SD5-<k6=ܭ)h/Sԓ'/z|= ~^LHQ|!6+N M7W~8xsJ|mwo]xյ5.Y-˸#`&2#i{x^gj%״-vDQ@*4Toϕ8_MnוE6'{7էg{ۿq~v_>j?;ᶬ/N )>֫,pM|'k@ze؋D\V6'Ծ$jC:ikVs\\-^;# "Og<x> 6>!cII qe$v+Er! ύGⷀS,xhC[IbcyrfBr Kk]}tVɷ)wroտoWc&ex~~uoY௱]\s_ )|/4'D $\4__ ?b O~3|97LjZ.isyMLd ?:ǏW:EY}mvD NPN5?jg[%W׭lP@Et-"r1BԭmZjiG;E>$'̿'v/cQaxK~5S:>|K/VVα[ť͂G.V1~>:5;?>-x2{w _W3ۘĖBNCm^6dVQc~S=_Þσz=GTuitY2Oqxe pkjfld1?Qj:}̲\jNى5 `@,_ K? >, o^| tkikopu3"|G[5Z.e]Qݮa}msm* l2R ]hZszsV%y/c8MtkQT[鵿)fπn?oiɬ6en@a4{(#lDw|Vmjt0\]Md9̿"JN4lH8%5;5/[+_wZ 1i]mYۻ*|OöZDŽ SIԭtP$r!*A >x^&>'>4_Zxk}8e#EDߛKn\SzE|?Kᦩ?4Y:V-Z{T'XȌivg7ȃsi_Zo~3ᯉ||, ImGe ȗpH,ѰFɏI8=֭vgn7BOs-_[YdQ\jo>cxx3H~KԼA`v19mnEmJ4ܵJ.!| 9~Gkd7ҿl:i~n5܅F0F) Yb;-7֚.}*]aIy]ę/ ;QNZ?o_zvqQ^Ca|վ?i 4^ 񶽢4:Z{7xH|J^=ҪbFpNj=Fo|J5Z666/ފyBA?Jϳpzok^csl|Ү/-1YSbC@w2nrIݯN#?iQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE_QKsNj})_5Ծ81 {o'o׏gNObxqfFY$; z.%P|CoO|#׌kִ,\Mյ T y; __.A1%/KƟx&7n }4V[Xf$҄]m}k|~')^?|%x]i-us$YTmlJ!Xm|JQQinUA^s.wrjtgm+/eO |yZNa^&'ki%Ҽe17-hw qSh_<}ZN+&lk{-f]JX乾{˫)a ~Yn;x~->V̼dV-"ɍ>sZگAB6~6'X\LbDi9 / )ӌ[n2}ԣM]?84W}F$kgyyk7Vw-7߂_| ~GOM6lP-nbKV~3nYxKR~"j_ |xH,.VOpgecfo/s4Rk?馝P3Gm''n4jSoo?{*@cL,ߴ o㧈ξ:Ϳ(b++gn0ZO9oS{wJ[N^˒A[*KY? xO~6CoFVoxMŌ-Lk=2+6aoas5ͼ{xs$;z >-Wkᧈuon x=Yk7YA&/WU}ҳ"H })'_0߇e=\hzX3;I ¼G8Y7[~ #zvW5 XK GNKK\e%hI2khR~FߥqiE,g i ;ZֶN6~IZyT?^<;y>wo|_ g:ׂn>iރ}wqo4kIuoncF!E;A~yVh~~?%Q,au/,6I~td0G,=nߦx׆<#%m.VihT.#TOQ_cÏe}I47wj^[!sʭ|m IqFp厺O^qIu-6~\~H߾J+? d?_uzjoKqiq_Vak F h9'Tmb\Fϋc~5¿_?o G[O7:lK/t#M,`Nߴ>6x3ݢ|^w<+C-ɬjX(I\FDwf誤k3_?xE<M7gHӬYKҭI  ֺUu&-g-5Ο]7}ۺgվʭ\2r?j~~(]6]Ѵj [Q F ?b goß]/Ž[ ;`]HZֿ2S-RO'6o4#ʻ5VyJ㯅t} >k[,#Ѽ}Mf]FuXg2A7-uO_Z('5SzՅ3$1ɋ 8"~x+'X];׎ du!kVSPMHܟ+q r@Q]^|W^|-^[Y Ɵȟ}..C,Pil}i|һnu]ښ{$oxW_]c?zWĿ:5߄1qE6)xf؏ S!kC'Lj~xO,~;|> /^_kY^ɶ!%4}GMiיT+@m Eo k ĺ%qoiWZQ8IbfFpx*AVgK6MlTd׽gm5U{~ [xAgWS'CMMevY(Y51D3y>Ji#~~ǖ:w^>hy,]|"4:Κ&{2k[ք66#GG)CykI_O$ݴUT~Ѷ}t|k? >/~@M_ ů|6Klm'ѭ1L(Q |폍[> oDு!׌mw+iEcA-XUW_ފҲU]W:k)iSpT~N ٯ0/ $9h>4=WJ;8'I-ތ( A؃w_>|VD+#VcϦh,fh0%eV;ehukNZi/\Jj /߳íw^S74x;SΡ9o[!ȳӅBh´i+ЭKV#.]'‹CEWWUV:ɈTT3}oEsGٺm^OW;y*ۭ;Hj2V wѾ*^Eg4|.xB_j^!.-ld-Z|A^-|L?/?i/$!Jx+Qմy [TĂ7;w2?yF4ώ^߰ZkV6d1PHwl̯pHe }AT"@o\NDvj0wK[Ѥ 8|Au[]|&OE, W6<Z:lH<:D FG ڟG?hW~~l'Dž-+T3ַ=k~cVHYK"e.km{y^Svm:oK0W&}lQ?x+Yh7ÿ0x&iTX IMtY| 2! vP~oլGojtuPRk[IapAU+6v\M]XQE# ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (Υ9_s<_?5\o|LSU? (J( (?,?CSCo.-VYW^K6-RKF/js~ Q@+;o¯ n- V@oCqjF6{lFY0xέWj7EόEO?| {xSX oiqZ쌒YHI۷ ??+ 4w⇉ f!mN#wu۱b;⇆~ZO3Zamm[c3@ 2Nh! Y4%{ӖqMlܭUJRq{ߊVrV}oK,(mu_Zǿx~0o[!BK,oK;Q1l%|?xZahWcx“GkWSW7o xŸYꚯ(LӾ T.|7.ՂK]Qn(D$4`7Qni5M:Zn+Kh}®]O k7+[E$>go) "E0G!RWTʖ+s+ f>?#o ]&rxG-l4,,LudChߧ m|@GoŶQI =֩}umt "C:֠_xHZ~_i^'u k բ֭QNd)5~? h<x޹\OԼwonaˢ$w[Pc2̹q^A~|hcsVO? zTu k%=ozDP!pŕeG&7˛_Me+eA旳qO3sN:WxW-K}^W"X˿en n1QOvE#I?o~ <[Ƴ&2v,΅T33H,˝n}YvIhLSWmn^mշvQEIAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_5Ծ8(죬V᥵/zǏx_Q}#Vy ?m'owc↣ =i-cᖱpRi-TtKXnoƣܲ<~͞7zs} tv8"?Lleyiʺ>k(ˇ|oSPs^M&_~9Y{$WvB%5fo,=PQSKQ|ݭd:Tܾ5۷ i~7g2[u[ZӾnýBH4{+k}wVl[\3"5*ȥVoo>3j]~Yɧx*cӚMN!t2H+*9$viSqJ_5b[7+n5:m>Fe}힞 ;.| iZ fdoiiWD/Mўu^_ xC>:}N׼h<2m1';vȎ8(Z[ֿ0)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE_QKsNj})_5Ծ8EN(Wy[~ZTuᅣ<#xšn}3GcMZH{*A_ME7O8ߌ~T/ZVM{iif_2apaA Pp iw߇~k~_O/9ynEWq}y2+Cl$l*I^[|*ԭ'_n#]EP0$r 6H#m(W*WӮK(*W/DMYUkou>g ƞg[1h=Y9.8#"-lԼ iW ʯ+EE[>eĐCɷ ;ȟ?f)ϝA_i~6]* 8cȅ.-f 7dgcx_໿į)I'V>gOJY#LvGq,Y`bH$ f*P<-DK{$ӻW3纫;[K{I%wjVk|O/!]T4G?|#tH8ވ q}+_v|R<3'Imt~t"yv+Ibo.3 ??g~SuQoe_}.q%ܱm{ai;lB!S}_Ts{Ec:JV[*nr$[Y3xRSqKFk~h|.c>i~:hE&h)d'ia8T<#e@B^0_oxɟu_/^-ӵ/nK+iD-ku2V|[-kpMuXAl.5VҽӤҢyUƵ9(EK4Xm[:NRO|ƾgSxAmsJuy|7uwe}lʠ'Xɑ*HN̟sWT<:y.[4wbЬ]H&Xw ~hyy_i,sv*s*;]gn(̰((((((((((((((((((((((((((((((((((((((_s<_J(Υ9LSU? (?5\o|>?߳=ޫ8|i~/$,,I$y$׽QJ;X7g>2ӼG/ H\XW4;)(nO*Ax Ko4!þ-m3u^D"pX6HbS^E>F_?>+Yw!9[|1gs},#x;U IW`c29)o~>4kIͽCo(Di#rqE++r35-v?;ǿ~fo7NI XAlBD1nfmN2ke}B3fOi/g߂:y].vCe@PaT?{Uε |+k#6: Kvn>d]&ҊRkkmG8oM6??f?7Z&%ut? |X|=,ГnomHТR.;? |1iz"ouk$֖FRo*._bŰ;h!.DzJ6.Lwy;߮7+QEIAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_5Ծ8\]hZk^4Ѵ|#סF;-a$Ӵo8XNpŎNBMOMm~>G?,o.xB%t7Rw^%Z&`JqeߴOU'u]zZUTi-̨O $3Dv^ѳh:xf-vɪxNm>ѮJ\+&2#iE?l?rV|Sr:tͰ-xtr"VF +U>_?W}?CѨ!ֿj S? &9x~-_k6|Jj[V^BHS]js|GSM$,O*9$͌k?k?(#P{6ix$Atf9+k*1rj+wgWyDxD3>4ڋ;÷:żZx9x-YIJ|ʤp})7/| x:j<~֭mUeKEs*I*0%LᚵݗԈ%uom+\C[o#IgΚ"v!yRɷ[t4{᮳y! wԳxzM@`'u8Knw4W??nn@tYX/mnO rX eaJ矐+ۍֽN~ CWiQ^qUdğK1XE;|?II$ޚm?Xgߵψ>%?ZV:2x͵ Exyi?iOԾ"/]O@~sxPd8jGJb _QѴD'پy# ާWæ5JI5$^o_}շm#'AXQ5g:zrIlw 3[x;p3gViQ_<<,d4mu<kiE[WWj+*kgϯ话j? ~x=&xCO ˫Yx,6WZ%ݣAlyyO2!Þٯ_v?h? -~ o^AsFvW1=[wS\+ nGRkɍ_oF_w5M_ oY7H k\Yml1c*/Q?o>'|=:`hLq HxXM&ݖ_3Ш _K}%|?u<9̾0:~LDө[3F,v6Hq]&Q2}r'%ѐ#mՐ6~~%yY?]_g=+_s|+Ðk?|Mi1h7ң,)Vj786z|k+VRe3jOqiealnwBH%K0oط1zBxSE~!QC ^Mо&xv=_᾵IYaK6;w))PI,# YXE 4ĤM3Z(0(((((((((((((((((((((((_s<_J(Υ9LSU? (?5\o|>?;-WZ1~^G kMuS +([7m$W.*х5yEO"z8yWt~Pѿ_~#|&oI=G;3XVv:U%iז+rq?BI0E.Mۻ.6rxB!c#$I+fLeԺ*dQI_ͥiwv暃Z۵|I?ǿ&}s>|-o4K߉}7IWMy4Fe3j񽹞}n Dr&kN yb_^Vɷݬv~?~|W W_MPlϤ)do}ʴ1dqf kgAi/v>&XTEQ-.u3IrIl1ZNUݻi76fȶ_zjg_ xsg;OM#F{, 5J=`6-f7 ;rܨk_m c_ѼOv iiב_nڔhR_MUyN6BGF1$kYVݷm6fGQe-kIG4 ho~NJ|.8,-IYO8~QE&ڽ{uJJuRvI%礔ѭgF.?oY Gq cRLT:ݽ:zfqjI$r3ʳ.Z+|a?h~ϟ?iOJkm}LzwʶZe{N$TX#etO g[IE]vm==m&"l~}_3gtψljq^O [;3*?]k? 6hz~3xݵ :mCڜIu{-Bi.XA|v#'ETbVܼ5VW"c.TOE^mm6~|hW_x#Ķ*t#N$&DD )"TS v<<_~+YmsD\hVrHpYM5!,T1/i˚+[߻-g뙷-HWwy|tNҗO%.q~зqM3?h_ hRv7)nr(V![HW:? k7+[E$>go) "E0G!RWUʖ}rs$M/?{Y*_m^j/?G㮕{MxYD],|ScyiWKѣww b7|qZ<7oÏ $|WG8|m-sO֓I^r^8ͫ#ZC֘L f"-~E :J~iyY~]||?#?dx@eWS/CͨcvX(Y51gyo'T $I?g|%9x>M"Uuc6Ok3[Z{dς9ʞ'Ov8`}EgF*9W]+Td>g׫oľw/zզ]j^7ՙ>j:&tދ ةo/xR4u_ǟx ~9Ÿ ψo4KP"|=mîi3[/F_ʓ>e5;ET=(/[{J:u')>WD? 7/YYox:i&i֮ande2ٙk̏0+)dIow 1㟊~ZVβt^ 6{e+i٣H4Nqe-\Z#m-km,%o)'w?~G>|;~" 7ZOMmgWNg [\$$emvߵ.]W߄?i[VK: Vͥ֫%Z$EK*(*Tn=)Y^J2{+[Yx%7oog 42m:P4FX.`ˠiS&_{6 \6_ ]TUm]5xxVx[ȼ{X%`L_R6vI/*7)6R{vGT~4|G3cxK~ |@4KGu }iVMm\F_w|//n' /^Ү~r]\` bmGYcHϘU'_ IY|Icx2]CAּ;U&Sݔʫ$Rhzo|3ۏ4OCLJ~jZm=ib?."KE/ 񇃼O*7]%g< wx }UdeNޖrOYh!Yb?h(}rkvVU98O{{(蕾JiwW[X f߄^|!{>⻉NqĂY.oNȶUegX(?ؿZν_ τ:5έ+iusg*XQG&)~W /mt|mI[X5lڲi ƤgX6m @(--_ܵM오UweKv }x/xŚ<#'D/ x}[Qk mƊHIەN:/ 6~2u^:^au?ZOiˈ&x ̳`@=hoչ~:n]mQ^l߶W$>?/cIq֋̻ns^B]l7(>i4߃>&|>Eiv^"6Dp$"Iv2#KQ~ i:iڟůjxMm_BcvyX,ȡk秨j_=:kr0H#H<֧YƯ/3!;sKڿgmq|J;Cj'үCim{ El:2y;qB뷟MG5)jAI5Y M`o0/"տ  >#x֑zk0 A!gy2+Hn{^WN7O秩^3(?h~Wu}:}fIi$ [^N'{leZ #/uX)èW~*V/iM g}zՖ'1)|;KOƴ\e,8 voӚQ|-uMiY`rOI׳=&+F4oI> |2Ѵj|:txMM4^\]Bo,}by$S$ZqNMEo}N]:kISN-|4Pkj&de`,>^E^]7GaĘ[£]:ʯ%ɳ<ӻ4/KZIoO]@?t_ co v*X&GNנQ>z6Ey~_`%C§VcZ.c2^g[MsY[?'cď?Ĉ ju_/ɲ<ӻ4/zݽ~}Q_7 1~I[ᖍVӧo:miye#S$(%{ϋ>?_u1:աѵ-[lB"rU!c M}5Zڳiǩ^okd!i,*7.&m2K |)m=*ՏYT?-77>#fk__Ct9&z^?ߞ:kISN-|4Pkj&de`,>^E^]7GaĘ[£]:ʯ%ɳ<ӻ4-t_֗ߞEQ(5 'D;Vwl3j +̇i/ſFk៴Qcj]?m][?'cď?Ĉ ju_/ɲ<ӻ4/yZ_m4oOS(ej|E%4=~.إݽ 3<0+,h wEO(6lZ/GuRwixco M;8ey,(mO7sb rb`6jφ| q#4]}f$%Ğj ޳]M~ooQ^q'~&C|QwxKbGg>$r$2Eu۔(qnë]BG5)jAI5Y M`o0/"GX|.0?[LqQڝeWh~Ӛ/KZIoO]@~?> >+x+7Z|I_i~4/Gxuu<{ɬ!2`eUb: 6~2u^:^au?ZOiˈ&x ̳`@=h͵TܚŸ~n_$SԨ6o+|s ñ$xTkEf]y`ɷnv9 lo|cx;Z:^ )n[jFicTbUH9.H}gQ^c?e4OH5 <@|&k!1A<PmT~leZ #/uX)èW~*V/iM g}zП3Q]o.oKVIr&ߋoDTW~߷W8kwxKǶK~]V4-d`k !NՑC`eeQ2Ե}OӾ"WךfmhkvlRX4 ѐCh(Myi/t~M^uwtW*|j5x4Ksao| YUQU"H\:Q "V~kxTkYUĹ6~g?vCߺwtZv!=.M/O]@ 6~2u^:^au?ZOiˈ&x ̳`@=hZEn&n\ߋI~/MEyo¯_.֭NWD[1w<څEXUR$E TnG`/ڳᆧ:o_\|G?m_Y {1'#+tsU9b|$|?o\u Zd.P[$B:Hr0N`~z+c #ⷂcuxĞ%VSHzWQʷΒ&ڹ[V#GM?3I]mJ \+pou0YQ䳷U- %/F$-^SjԻs|Ki-jT/l?<#O1*U|3&NG5)jAI5Y M`o0/"}ߞ4kR3RX$^~Ͼ3M_u}gQӭ,la\\h 4@@%4|q=j+>#"4«ZeW2l8~ty1o[^ ,i6߶|ei&մtNbh!Y|ŔI *>IpA:vWZ7ѭ/wf{=S>~Kr[dlG%>W.Q_A0vצQQ^[f_2GUš :qgIm"Yq֐@Ywڬ( lo|cx;Z:^ )n[jFicTbUH9.Iy&֍1=OzoR,j?Zw_\_L-mb͊]ڠ3Ɓ2` ]8?!_>(;ռas%1hv~#QKWdAl D"`m8i(g eցxZ_M"vQ]FO*k:HLjnUX(Eo&m[=)䒻h?]7GaĘ[£]:ʯ%ɳ<ӻ5GQ~ i:iڟůjxMm_BcvyX,ȥ==FWO實QEyo¯_.֭NWD[1w<څEXUR$E nZR/࿌_Aj~ĝ_th'u+9mFM/aG)"$nT8#>ME&8mNrl4~t Qki$ךjNK[OɧoO>QEyo¯_.֭NWD[1w<څEXUR$E nZR?t_ co v*X&GN K3[߿Ŵ'Y<P`ǘ7GK[m5{+Zjz}>~Ͼ3M_u}gQӭ,la\\h 4@@%5߶W$>?/cIq֋̻nsNO?_x{(?[?'cď?Ĉ ju_/ɲ<ӻ4pz&E|(Ɠmi'oZ6m[ON]o)ˋRmϻYO$c _HSGwF (Υ9_s<_~b?7>XQG&)~|?_۶\)K] Ew?ڻZ /+EOq6?QWɿwckrw,:jv4;Wntgee! =Ckt]\_6IqR$vѩ/)ύo[^xF__ ђ;R _R;=ig-[ݼėivULRow_|MR׭|Aww=:8#42D-èALiLj_?o>|V{jƈ_Is/WJqؤiV˒HeIJ+Ҵd> :~Ú(YtOJWCϱ}p>o)`(Z_fc~ƌ.Jp^[\N#4{'e}~Mmi_,on ؍H>o+'koۛ_ <3{Ƒy~(MGU:ޟo|wӵg*n 0$Bq?ڏ-/?ICi?:ݫhwכIKc=g1YDL&|tjIiiEߣ|!{+Ͷe]{Jyi;vm_dψ(|C χ~"jk 6Vi٥ђ'gnEfJcRW8~=k|'*j>Ηٍ Ӭ-m/>U$~k2^:߅Kլ.n5Թ%dӗO*iuyb_0Wo( ߎ柤x4 g ~mX3o h#2,BʈdhmreeQTv[=FI1{rFxƞ{s@ mx?d^1<45~qQ -aVM̱XƦP ck b/|wMoGWw?jw\z2i˧4于@ȱ/bC4_C/i?|?/"lSx8lt3e0%tS lo~sMI5*{GO$m>z~~Q~߃)೦?IuqzCĄ c9Mx5y>u_k5\+"h[g}q eUYNGxi_ -< ox']-ǃa_j7H5(-.g&c$xcdGL# |!4SGBH3X]%0AF`@$3JTT6/Y5I]bZ+)}[עvֻ_%#l)7>&_x񅖑Gz#߰OSS\Lu%V*@?z}i_vǍ w< O>?7\|2}O [wkVVͤ:#vUZ$sm^H]k}[tz!ڔ~>.|>"k7>[z.GXZGfFHu(#i )KO|3r-3v?+B vS>`Pو Jon4]ajx|M>-75x̛D[ȢQ,ٝ @u_k5\+"h[g}q eUYNG N-6 oYݷnmy'O/7߶|VO=+PO_o| !?wi|$(uKmA/ui4[(3њ('4BZEwTunXYh.s>oyٯ%#l)7>&_x񅖑Gz#߰OSS\Lu%V*@?zQEO߶|g3-:w.uU׼4b ;8,Y'2c*n˹/|@o~8z6j? 6Ɨiְ "ym"ci/ܭ!.z x7_S/h4M7K͠H 5Yde}Ϻe)J{ vhxFըuVӭϚ4#]/Ue/tDC_.n[vӧBK|>wd.q?/>%]Bݨ41buŭ'G-PG/x W7S?m/ğm=&V e]>fa3Ed'Լu-7 5_: X]ksKɧ.TӒ9K"ľaN-{(D_}VW/ ru\N4\EtvY|>"k7>[z.GXZGfFHu(#i )KO|3r-3v?+B vS>`Pو Jon4]a]WF|qsO< o?6,~ę4əUReD26%]v~Bм;}Kǩ^'u(%/`M[K' -p̊$qҕ5w/ *r[nV9YN/H/}Q'ƾ6ᯆ?k.5v[-mn8wY#%};_ O xZo~j:ùu/VR+װQN]?쩧%rE|?rS>;$%~ xg WPσom>(]h{,w:l6 $o W.X-?]sk|VMxגtBqiGdC#Rx{?|QCRׯN |;=إ¬-JȿߞjT9Tɜ#7O7?xV\x OW~.Pj5M.th0ضeqki|pmT<)_i_TY\o :)>j!7MGAbFZ 3u_0!U]Z.aR.''rSm%db7⭯'_-+|Hx.lҳ^3+l<3N 1G_ 4T2m{[mo"`]G8ft/Cy#>~x-x7/i]Լ7.Km&h.Ŵ,{-̩2̿=M GaFOuzbFT/5:z5t>"k7>[z.GXZGfFHu(#i )KO|3r-3v?+B vS>`Pو Jon4]a<3o; Ciqx:?ɮ>~gKa k_܂H97. ?4SM$sh/k.Rzitvm/Y{y|?xZ o˪˨Ko$Qi,Wa'k_E1  ?h(o NGYM Ƥ{_8kqFbB<[_+gօxvƗ SּOqpO$A"[ke`Hω-Z|_u5/,ڦ-ͼw65s94Ժ|t|rT[qkN-Fv}JJow|פ6~& SY.Y@+;g -ŭJȪw2?x["{3oW~;7:ު[k1XAew,Ef7pae܏s^:߅Kլ.n5Թ%dӗO*iuyb_0!A?7 |Q"Nr7"VLK)&Xa?lH eFrSO&;+b[RVIs}[ݬz3/o-|.s߈ǯZzuqZGitd [Qr6ҘԾ ?h(o NGYM Ƥ{_8kqFbB<>~x-x7/i]Լ7.Km&h.Ŵ,{-̩2̿=eI5/z*Mvը;WU-}+Eէ'%I>ݗKxEG1?+Q/~8| o!V^ъ +,d-1s.|~់i#wo^ok8GԣB@0S|#uE {'XZbv/\ -'N;#"Yfi;EB@jko? <|5YR2ͪisk ijYG3Q#NK nzj;J759v[Wb' JOK~~mOY~~Q~߃)೦?IuqzCĄ c9Mx5p^:߅Kլ.n5Թ%dӗO*iuyb_0ܔSp^8[hUK)]k[k ~^4ox< *Cx[Zkm{F+,ೳŒs(2 =̻ϰ:|snxJcKxz/ ϣ^Y^_n[jױAn4{pwqm3mt?%OMᲗK{x͗WdXӳM%SIkG~.mѴ~ÿ~:χ!TOZmVuYu m-6E$kHC!>7+~֟)|bjԣ~oI{^@39J.Z~Zx;~)t/A^{ZmgS_/+qwnDIv֔ j۳%;*Q<N3ׯWwkTh3)š3? 5> ۶$c#{<|>"k7>[z.GXZGfFHu(#i )Kִ?/‹s GB{WͣPC1vg/62XKᛩl;pOl?ÏuhOլ'Ɩ&:J:!X嵑S 2*ɹ??e?DŽ|w E='L:D} lfe.BqkrWݶ7t~9$t/3׺CE⢒ugEy5鯽-N5RUhҡD?,^㯎i QԾMZ]K^]FM9tQ_% @}J:Pu^j]~T_K[uRyn %៎V[|5]B?> u^^O<( 1\GebCc: ?Ol;[TjEO߶-75x̛D[ȢQ,ٝ @@gnFN7TS:я-YO^ߜӷά-ϛ|់i#wo^ok8GԣB@0S|#uE z3/o-|.s߈ǯZzuqZGitd [Qr6ҘԽkO*_n(?$~)_)׾uQ|1,3f/?4<-{Ѵ_|[F#񀼹aͳK&m rfUxYQ $)kڵkⶽҴ=z7mIk=|{o؋Ɵmxg][7tzMmxhavpXNeUr>?y<~Nl7m񞙩ZII^_zA}{ -i|[sZ[Zx#h/ho`5[Fkww~.Ex'y(AxWgR 1 MF5-E*)Q6yUdOz;tA_["{3oW~;7:ު[k1XAew,Ef7pae܏}E5E_q~t; ;?"+c M㏉#/XQ\52g+h'Zlju.X,Ck}ܒ:.-,(k|e|/az6|N"ĺZ([k2%TUh]1"m*(٧k<%?f2i>+b7>7>}tmbbmq$1Ӵ_Z_I>o^>hv4;Kso2TQۗKm%F+% 翞roշՅx3Z+~>*լ ^x hnk4QJexDWl^E8Y)-_KghL$,^^GGڮ,uIl.n[3-ɼVB'k__v#W퇈u/V<?>,#ͻw^E(yiF+1^76{&[¼Pd|?ݕjz o^>hv4;Kso2?ß'?uV.9&ua\I ti XHա+b04tSq]4_=~;_*?Œ{İ vikMnK%+շgc/ ҉ 6_R>!Gp.?#Guj-m|!WQJ ٸmKiD~UGW| |Y,qu%oc궷yA%ܶ˶c$jk-z_2=ףV{o; YG~ þ$>$>/Zx\ӡ#E_Z,숪"v/!׍4_ kk7$o]èx[t˽d&no^K`D)VP~ϗKhv}˲ >k߮{gN .wn8Ty?,WPȈ1CqYu|O~$-ѺcgE\~-Lm< {C|:rWݯ%skkkC#i|?'i[aPjGAM_v%~7Zފ(ZEEm_K䁾f>h_$OLou۝/[x+(u g繴Rh'1[`$l`@ڊse>e|hF]%뛁p`cQ02_/oQsKm奴uR=xDM/|g<+}5J H)/~~`|3KTN??_:v K5G[ֽm.ƞgi|mBZʊqnymK]'{<&&;fJayn\omuH+u6- | L C[>ƚ΄_-Xd:lbpRg-KQWd'Mh9Kvxm%ŗ񎝢Mhy65[DK_3|9rwQw{&7Gck_M4FH&M{f#r $"*h%OI|i9=_mϝ_uI|=XukI4kewge31ɍiD|'_GO$1}Ǎ5 uyd][ƱYdua2#hn]-}]Is)'=v/6|#ۭWw^6WLXKnhfӤ{ [\}E(I4Mti57󿍿~ l;CKoEu-:b4Xi^Ȋ/ nl,]xE6}F:GLKn]Bm6$F 1BJ!_hytimܻ {vxn_R>!Gp.?#Guj-m|!T7Mυ_Av>&x[nYGʪ|WQD?wʣ-}B^76ֿ{t< L C[>ƚ΄_-Xd:lbp;6~Hd|Vn>#6|o|ۋMŹ1{%ktb iUmV[?W q$1Ӵ_Z_I>o^>hv4;Kso2?|@|Gxj%OZx\uѷӭR.$J]ٲ]}5ET$鸸[ktn/v~?+!׍4_ kk7$o]èx[t˽d&no^K`D)VMo߯GHmz3|[Ai{ꚧ|4[OY3OqFw4QEN}]I/$x`=>#FOZS5E mqyCrwsDM 3MoE#1I[n.7huRKt48!M*O__F&ףkf q$1Ӵ_Z_I>o^>hv4;Kso2TQU{%oWw?bį5mu]/5[kۗZ]RlƊV80B(Q ?_oaշu=NIXjBa-65ZH"5hJĩ 6])5k=켼~oϹN??_:v K5G[ֽm.ƞgi|mBZo'K/;E#v-lk^cO3g6izs!-^Enymܾ޽|??|#U_i+KqۯkWZ 3Nk0FXA>]G4Q%%\^ϧ޿&͞C?4o>(Y|<3Dh<]ž4s|{J~|3?ikU,rGQI<1rLher &"mo-}˰?z뿟s|e|/az6|N"ĺZ([k2%TUh]1"md_Op"Ub5/Oj1ٿf ݾg^EJI^ii?T ѯɵ|#JOKë[O٥5[-/TG{;(VIYLh&J$ $p_ }&[x_SՆq$&i_b!#VJoNIGK_Kv}O q$1Ӵ_Z_I>o^>hv4;Kso2TQNJ==] _߄)yv_Xmn_akyw,Ic)XHG;C?4o>(Y|<3Dh<]ž4s|PU[%+ j뿟s+>AxwćĖ#OZt:hӠKE]_ҟ YҼX^W[]R mn6 |yhڊQTRmfk8vBUK߿Ԥݟ2?|@|Gxj%OZx\uѷӭR.$J]ٲ]h*?Œ{İ vikMnK%+շgc/ ҉ 74SME.ymmܻ!sK[7~_ {|Gťȵ.gj7L,Ud`#grn? .?/ăE7B|L(\ مU{xx}Ɯtko+ԵN߆wNǃ1M#|C._!~g|o&\=:&;fJayn\omuH+u6- | j(^o-SXS~ef&ףk<~_b~8:"_fyhgc*(Ew~}ov((((((H?ZEl`u%}o_0?KG5wހ=3)NZ=ϷtcM"vT |8xkĞ#B-3v>/=7UH.uk{G$Pȡ?j4O#7OoxkOҴi6-^zۥTaJRKe$謺t+|S?iY6NBo]AfbȰ'Syf)n lE~o?>.x-^oτYI+Ӯ`A2y63 aYZ({ȟ07[|vk\:Mni'={ku\_.Wn43Oe"{vI"]B(Dib5i%}"+15~+P:Qm2&k2gD2TھG<-jV_R. .7Ei$EI8eulcd ?_~'Y㟃|w[wŚ]5cB+}6,G]Xga3$6B9ƝשZYHuf }tSvR|hDַ:YzV_o$YR<eX9`J%/GKwr>/[fmcWPY=oeic~֞X>ukN%MsOȶQ L$pZݍhSG]Ҽ~*EX邏N(hGW]ڿm`i+~|U=fE+dVi7wZ'tWU{!mSlaZXk7 sY?Sƺ~C-'W/ b.vD8FUуűʛ9=SkKSIMW>f|Q掩5~>8x{oxS3ǭxFHt니eݮ%4vFA1W' c|B4/վ,~6&LQ$Pʦ]2yjmOMZ2-_m#-Yh{ h?nSoxGEҼkgRIڥ?OGO=x(;.3}G_HRE7.cA>L3K;V5߇ ЭGKHn!ȆYBTbt_mيM%iEѴ>U5@ M>9nn ` gm"ğ i>+5&LI]=u)ZtE/#Y aPgZo87ZㄑYI㿅zw#3Ćsm%H?3Cn60Ҝѡ:g9i2tahr9Z1M=8Mmm7>/C_h3R(EyJezqQ SI{T|zh}01k_j^{&sq}KHU}#Flax['z\zF-ݵm~sr8ZYc+$H|A~~>/׾ n>Cog z뻻T('[xgHӼeOU 5]%=Q/>#@#Ifr8cϏ \V_Rg9C24Z朥eev1~n?m;;-/w*o>٢cxQ?Nx࿎5iȶCo-ݺ7jbC#5\>5m>޵CB\jjZٶeq<#NKkv-`USU: spq~FM-%RNMhmuvzKVE~Qi_ 3t]gŗ3h>;ֵ\[Ysi.gݳE+B j0c |)w[vzU,WV-鯬YR;"A¬M='nѵ(~VIC^T[UDjd-/vkm^Gws㮡ahɤ]ShE[Hȑ̮Hʶ9+L_ L{ W4IͻKx~ xKş3Zg]$Z|:rn6ٷ巰P_ewyy?[OGg膹Qx#ÿ<1Snec}\ow tEmf@Ѵuy@/ΉNB>> ֣\i5}QuI^]=V?ioߴ.oťxQ=xR|G6g3jRG%Vv22\y$ QN6|w罯Ѳ_ʞx'-z9\>8x{oxS3ǭxFHt니eݮ%4vFA1W'->7ďhŗZ#mp;Py n]4 .͍[^m"y-$XdHfW e[OMSz⏉_~-x%'Hz= ? x7e5(Ԯ4cMҮ5 K $1|ǐۛC/ Ǵ'@5'Ú߃n5_Ho~qp_/|FFsio.%rfyl3}!vsZn=KϧX^>K v 50q$p)U8ZtjE9B>ꜯh]Mhw:S~{Mu>?i_~Ԟ5棧hZLO*8$I+A5Wg¥~h?|Uŵ6WBtGd˷ dFEh.s'?~~'X6xmJ-4ЌM VV'3#}SZ˕57RcVoUNrG}jo=3o_ړ ~7xߎ/u;OKD=䶗mo%ש(d.I ߴWÛo-E4 [ 7$%p j/go[<6K HmTn\23F{T_>.U (}mϠj'մgiluKY ~d-xpWzR;7dҾ򲺹Ǟ{//EsڊԾ0?|9пks=kuvoJlP|IS&s#R'2+Z|Oq.cƻU p|n&_uσOIg2ˮxQkb][VQY- Zx&ZD4ߵWKK&].`Iݽv~Zzqq?JA;_ 5#ĞyG2HHzv`j(C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( Zum;Z0Uec!X"砮kMm7J|㈴+ɯOyфo7. s^x&W> 3Hd]x~[/K#K6HAv`= ^cQ*0{^!"߁u:ZOsˬ٨VP^fd] Gs]/v鷐_=8{6|Kெ>aK1'>W>k"k?iINKKl0(`ikt%_[/;w¿ڏ>|97WėƛZ]=#3c+EHI˘жJt =KOAѮfPlK&IhdmQI{!o8__?^&u gA e:pcK4lz#5ɷྉ/U1i~b溰!~%@Tn{5.)ا߳<KÆ[??^/#Rդ',f p3 ek'_kz/|miKk~+KG>^\DR6oW,1y==uYZmӍf-6|[ yñ9N ;-oI oqe *g#5p(>_*>km1繵>̟__Q^80JHF)$QIIlT쟞<<%gC6>gB|\igiih'lP$@wſ' >ho"~_\e;dvh!ٕ:YU/~ocG]P\|$Vᾯ|O/ gCc|2o5&{(}q/~"k·~oi^-76˾/ ,mp_u}?Eo[3BR|hOVz8jp* Ä>c1wße_E|RU7ƚAėZU $\O j6~$q+&t6vWe؟RJYF~κǁ'Ju bK{tddFL"n\/?O~ Gy[t#0R(#NF>Ƣ $pTN4?hE{・=,l[KjWա̥֛?;j!ğ[Zo+Z__C?>5u.mtA?Ètq j]6> S_u|Wj&Yt^<5u,_d]*FfQ4}HT/W/8x8]x{5%%Vk|֋I}VZ j~ϟ?k(CAkiQYZ>cil \1̎ ګ~tzǁt txnM¶0iTڤB9$RCW^E|&+WZxߛi%w{[S ٥M7A趲&-"~RH_/~#Zx h.ݏ+k`ܤBDo˰0\qWOh4'=ih>Zk]\_&K'L!AörÂH_O/:+j>O2K= 6kGmi+/\($pI4RZ+-8M?\eYWï[xl!Zj[,b5o~h 6У//{/i:ƿ~񆳠]2[mu 81%6h=vk;ly З@%|.I i !9v\xjk}.VEbU٘$צEo!|j_>e%ٿCѭnI$r`E%|'k;;w.W I*N#öiR$7[< DvA (MP5)?f'M_};N*ڗ#y<}5Gp^AټՐAQK]}}oxM~-<4Ey0H~;G~ʿ <)Q^Ӿ!񘯼OmZŬ^! ,bW" \QF,p?eUk~߇K5PCX[4l@'arO7b}xJ Ǣinĥr 8b_Q_wd%g῁<'x>kcqIje'cԚ (~IGc7 , {G[i]vvQ1lQE6w`J(C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( Z"x;` lcڹ{aEo'e%RWU{_E~#x?ߴ_osBoZO \k7Ѩ~> >0 >%x:ޛxՔeHbd1o)/ٟzR Ja1i K$Q,H˥4b{ e'sJ*ťڅղX$&ZUaw/91qڧCCD-kwOGkjdϖ$ 2Fvt-v;++@އA k:V]Au;K泚gYd'p8⹯?S8$1j1x_Y skn~\\I:s "VőcRHUV$ IMy=|=~KǺ?5mcR1$2ۛSmD[Yo+Oğ*Wj|;lmkO 2Fv,KH*V%ыJ='Ud1Wo*?LhC ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( Z9|ofGtFy{=4Mē#c?5 86O_Ɠ\?h~@-ſcɮ[%|+LJ*o^IyeUKWg4aVg߬Oƣ)R+J>vV{)\J9(;ÿυ4^}C*dkG0BɵglnU#k#'Ꮞ5?=ŵ[%ġ)ci`u.v!O@W@7GǵKk]SPP%T! vR[~>|D?ŵ0K;>#2ţeMX#'xod֮cSR*}잇|]տZ}nk?$k: ůtZiZX֖wZj ]%vf^r;pۤx aYԵ&E.Hgt)<≋,Y W~"M>ρ=ss{DfdSO[P$a[y%PW? k/7lNjxy5 e/u;ketW9.LG,2ʭ rOKQFPvKWV.Y=+/nh= kecaj }ٴF#nͿ.ct |*ŬK~uixg_ G$m>f%+v R_ |d𖉣i iLXG JPwTn 2߆_Ɠ/1IG:<+I,ͤ2ݸY8s)GnI-ks84Ӄk%ZySXoDŽuRA_ƝOK!f=:x-+ g\ !g |kgo.@H0ɨحՔ":\O%M}w 0=oWo3bZPkj :fE[2!X,W!߁|B|<@|C4t+&qb+29*r'z>m)r5͵ictpw5E4߭;Apua ~:xsPqm" )@ n0$\~0G[_>>xKM]_@]{RDlXZ"}(@,AVk!?m_Q{Olj#E f "mIȖRy864+^|AE|EKo1)tc)@]t[XͻR+[{[j+굺:1RutoW'˪}s߇OmsoGKTv^Եmbzv4yg]9o 1d^ _ ?`OM?{Z>vk7S3HI&guTghPQUG TO|>h gŚ E?[ 54M,7w6Si?;{gIci4W9.W r]~Nv?g?hڟ?guܥ]Zwi+TI>QveUߴ3'>=7?[#*OCԯ.Y@ERyf). lE?v xofVUB8FTjN Fi٧jֳuOU^_U{WF4O|2>[šΣmm7OMV}X ڹL_Ar@%7m'H~ 橤X|,s_jZu&b[dYe&T:PD['B?iy֭96j~ՑDj,}mpi'rG|E_|quoZ_v~2$3:V:-o4j%iG :{-h*rPRi9J YYs)FNFݚoz/ro]ujnq~m~|'ējY|#cmjz5: {o"ZhN$_)_*/SMckyOkmuۍ"Ki,[yC)PW~:ߏ~ڿo|7|M5MH$K]E[pG26ٷY؂?엥 CeXkυ"5)TtlLW<IrRqDԕ4լyʕ8*Nח͵WGxb6m\xWAP$ BX_3Pphڷ~om3Oծ{MPH/yrAoox| k1|#-#ZbgP6v6 GO+[ ׎(څ8ϾT;y%I$Wp=:JMi3IN܍otٽUJ _>Բm/.;J1㻊7xx)Voz j$>"-i"YYT.QKt>>0xoι+Wt|)wWT8brHʋןOaUF\QԹZV}9um/>0`U$;I_O? M xx[LZyt;Ȍ˅f*6P>exk m-WWַ:-#9_9Z.>yB]cn.L4UE+>YJ{F>;Ti{+/k+?EIRXh˔+clpp{{Ͽfj>4y>>-WX/>5՝GtmJ3$~!IxY!C.KC 7 D'2#+' ak_v_^kBjrI-|ri9/I<ܬ~k窒i괒m47⻨E%MOv:(Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@|-)zzajG{.hoPEEP^IjRIhZ:h2x DL}<'*;ז_ -|;ƘHi9oo !eUǒee]:P})')$쩨ο엤kB})x>ɣxv+];Oel٧dIHXA?گ?f߃5'&^w~=kSCFu-/FBY\qHZ`#hՖU(uۏG /Ǟ4^2,uHtM~Im.#uڢ|VY;ז-KFJ;w͵Wx[~|   W}⯇WD YY#[Ap;#"!z8gmT-|N㷋Q_ gO#l-``B`m|K?VӯywBj=+ŭ_z}+N];H,f)_;"gᏀſSO_.ů\'4:7ΎD(I72ҭBEms#2C0 8k 5$3nePHvݻ 㟋|]k__aC\ø/44%Ђ/g [;[x>?Ox_Z!X~G.Ͳ奔G|xtRѻ5ѥ&m{h_I6,,^mJ9Z+;^2`>,|H%jUۛedXm$}+²ȾcLpl 7O$kַ/</Tl_gtKQ\V.YbǴ suFeqOkvhHVeWBTO#?no_?d=WwϊR?ڎ};[r·77nn!̠GU<Zsj\Gh8ny+^K=b'z6*l$tn:S!n| é:v'<`,2> =2qU||? x[icS%;reZh }ݯghhs/M[?'D=BA,fF P-䐤Mn6g7(vR486%]\vW/w|Jm_okRhCQkOF.Z+ 6^#$z<$m&'eTiDmUKc$* so_N&E߉n~?/ԬǗv*\&69vb491^|?O׿^Y|3y&},_ M~&9R$Xj?,,&mr],u9mgvWVoW{^GiHo64iVMx%O*0P<8$GcdT RGxS] 3_F<'snI)7[6A2Yv~ч9:˗߻I;Ե-|TғKu$V~ ]R >D>JSV~֚E߾ke'׏cwjLǹS/߲xT𽞱ڷggX_mtr mm#{&g#ݧS℞u:‡5ޛAҌIӵőH&P̻ŤYli>Vޑ[z*EASRo{[EUٵo#O|ž,׵3x%ԵGE,nh3˥֍9>g>yFݹ}&{ m]֥GiK1;+i7HWij\7mo5_Z>MzΧ S%Rke;-y[TX_uR9[~%j^W=΋$ڊFHE*EUtlvz[sj\^ۥ}g_4H1O#Xh<%ڭUAmrVf*"o¨>x'xrXt MOݷ;,0fbI8<o_|e.?h_k;q? ޥp¶jq%eqqu.Ml A~|V㟄~UX]>'{hY R̨74~XQ#I΢_r$ٻ|9]_%yktcƊijj^ m];K|4Y},9KD_a]\x /^4S/Tu^G:s!vuJ B?(s9RZ+_Ow0`zzE}~?io~?_ /BP;ueu5y]pW/O=Yg;~;|ac}i4q3㾻eKCۓi+GT#h=,|}_/< 9/|CS|g_Y܇ȸXIFхOw.UmZ;Z\]VM_uh?ez*U\X7:> }ݯghmO=(&<\n,=|Sj/ڮk9j>"> դ曬j:Mb/(+-%)JUa16MW.9i)4*UizI'GV;]Zjӧg{~__lឡᏉ:WvjrQW˟M}'\ {]'XKXPM6WIo[M#NH/"ǺoM/xQMc];IO@*ײ}.ѻfog-zP~Կ?f 8񗋼#+Pω%t}]|8L~׼< YR4Mۂ>Dhk ?b  _1U»O.%޹ $Z?yio.'Ml[ԷK^.Ke^1n6i~NnVϧ/s&{'O '[[鮧ՅfyJGKa"˟Nh {ǽ+⇃g/]D0嶠5[e8.ʛc/=~)|c?/5x5K;:naA[Xt(da$(QЄ(I_?o-E{iVoٿ}XŇ;vkK]K7+("u!AIB~ 4 EK{[JlZmm-*W?_i_ o>#߇S-tCĺ~.Ekv';uV9B:ۛ7-7|2T[~0~zk E|MB#?M? FօP֮'L9幸 d/<"0v~`M'KxSm,5);Z/Ư٣ľ2bxmkM&OXG&EVy7Hݟ'gߌ tό5Leo-ukH倚[a"˴3=grE|PR)>iNUYR-?~xg ^0*x%'1(vgMG?|Cgt Mo)kO6E\CMѾ ģo>(W 6Ӿ=bVM֬ῴhHe@XRUkQ߶7x~ Tlo-l%MZK::?dd6ɷ!'2 ~-cׯ-BKV aDn i f)9MͦJM{ˢ9jF~5Fֵd2?T<nMW/@cɵ[XdK($7L#Nh {ǽ+⇃g/]D0嶠5[e8.ʛc/業~?Ovǁ~xs,o;;9Mq$$:[e@YR&_vKz[уxvݽLj|P|yM&Z=:B,mkJ@Dcx67]|-Xկ52?>io}H` q,,ٺ4Ä_UOk??ix{|@s෉un^fk=mZ-ۚ6'Kf,!Vf~7lP#uGM@E>[.v*|Ay%.}UΌV"1pzV*;kmh]$uz;V_]O=U/i:@ny dEÑ MuY_ſcMf_q\\kyTf#TiKt-$.<?Ny.u?%ĂLuah Ԃ<8@+!DDq|$y]wovmmwm9JpV/V󪞝WBz?|Q: Bwa`["Xلq-vE:Ƿ[3Ծ4E[|yRl|7⁡y$-4j6p\݉F*^!,4$✟ޠvi_LhA-=/)Zil}E~|bV9e[(#/.?KѮ/>ϩ-؝zPXZF̆ɓOŏ><֟]OxQB," iEF܅MhbP΋&MGҏ˻ЧTdetWFhߴUkī-+S/REm6j$.LR\f۰؉^|wW>/;kut-Ey~h?:]Vģ6= e{jngΝ9.ث)Le)bkmѵ_((((((((+hO{xW=&pEȸݢ:*( 6~i]M||Ě%J#KQ.#ҊM'n.? ſ| OE}qXxfM&{h@!]Ąc(~Id, |Gg~ V-|AMF,I4l2Iۜdψ߳?ß <;S~颹ҴGGv%natRUY])$ܫuysS¿x;rK'XmjV(-^D5~BY0IPs+_S-@7 {a.xk6Kcs3@zko$)4*~ڿH k?>:}?įOhëmO@isnVYIEm_ڧ<*%Ik{1}ҟ-UWO/į |%x7^|=&2i( ;`2;O*a뺫ڌbۄ]ՖV\ѥ^f;_kߡ~|K'oxu|#M W/7Q~#p|tz4߉%smCak ]^0U2 0koz։O_g~̞F>Zx-6Iopu{6j]w{kĺpxTVF"Gt>Ţqdyc/$xcg|YM35k&3i`x3K*q dc_"F-** {t{ qZs_-avf/g/%iHce3jl$ub++[ VeThoZ妃_j8G›]Z{s-҇б6NO1ǰѿGo Gx_Z4XG6N֜;5 3g.bf.|j__< K'nzMGWxdmQm1wǘxd*w09K*NuaNotMy}D0ԡVNѹ-]ynVOO_i:'zս (n5gP(h8؇ྫ}?C>/tVMvO¶/kgrDa25G=kD'Nᯈ3g?fO#MNi<nchVC7mq8f]=F5cu;ϏW4oW4G'qA4}"-,^%[PU0y,:u/h.XJ6Vӏ]lfW龭]s|T;;xg+ pɦZtM 1ed.r25,o{_HWB 'D~fI" ݐmw+x7>zϋ4].emg$/~lWg*ޏÿWR▋N%'locB#Qk%YQoFt.ĺbC5*_ɻmMQQTޖ&>7s5|+]? l]ҥ𮜚R9vk˪"!p}na76Gm{xc_ ;惠xVݭ-m;OO1%j#T;*O?}E[j%lĒz+$mlj˒ |[]6iz*7·VAQ\ͧ#}Ym|D?w媹6KFJ/Tۅ9Km7WPȿ9;cď+Oz[Xyg}ayuʭgq]f4Mk+;;q>IƗk'  neb3|K^|`o>Ki,+Kysr+l#@8_P;oĿ|OH|./_O i}sTmJEuqg<18G5"-g<^쭮4~뮺"Ut~m/徉[#|)c;ψt:[bIl-ldl!4cʌ'\zoٻY| 9ujڿGK׭DkhD)cG#<(&| ^KG/v"jrE漈i(ɍm]|UPۊj֒RwJ=.Y즦 /WwZ1{?`߁xZ§.;s6_4NS$LN]9&_'7k~_oG|Kfvxf -Nw" ,C̐9P/eo"x> [OԵjrvy6{p!U&;r~-~_|qi/6< ՗Eϣܬ(-Pb7cGN0Qd֎֗%iMmRrrok>|&υooѴm+Mo"<^\I[~ N|qF>9Լ1`.s(e߆2t+Q0V? [!>L7|K|$i ~3wx~}os30xpY݈rr]RkãᖋG⃢-yNW~yl J*F*N1wJ?/Np?3284+/l>麌jmu6оd(vҹ_ |rmE |3M QӢ4i4Z-kyfd014nzioqz5]O-~ 0Ҽ >/+M3C6QmXb v>b1V9DuGW?[Gg{#q#WVT_XWOs> 75dž>TmҌIglV0aqDF wT_w_=O"7@Ҿ $%>Ho5, C#qd;F!?P>Sˣo6,ڝ;I#4_u ױUvպK6| } l~s'o Xl%&|["o̡֏f='jw!ff.$ЬPxsHW}1!-Ko;֢x5~-^7 &XIJ+PC1hA]_[[YW_ী|)>EIмUl,:QZjAq ŲX3 +2ĔW)GᯊtsυZ5i; 2h>dE |&Vms-+|1| ,WMqEy$Do%(4i\ zHz+td5#e_~x3';'[TPw_oɴyįo\x+ ݑg5 Y_MjASn;DA#a;pHyiGO9'žU gW><[x>_3Fћx "8+$aGmvT *\SN=?F%4V|m+~2Yź'kI?___lIhO% a5Wػٵ ҿPoo>A{cͧ|I/,[|S\k`$m|7Oot3I( iZ&bmS~$~ǿ >2xuߋ []1E5Y h%&o!v1g a~7xfg/#߆ߦKi߱«_kk>;xS-xƘ ۶Ƶ<.4W0yxT{/5]3Bk $*r졛$]Nm1PZ+~} 9xn-.|?M=50ټ#-1aiieE+Eeu-QEQEQEQEQEQEQEQEW> ]hO{M"v&pEtTQEQEQEQEQ_ ~?2➡o>ټ) Au+^(3_ ^=| EJ5 [y%>ok>x7;4_kp!tK{Kua G e( XO~t?|qRJ| g^Gu7j:&hipþ< !Sr9A:ʬxOn݅PVc|O>+xM*xZPf XsWĉl2VS mj0Q;¾ "CG,ǻvvg=kD'Nᯈ3g?fO#MNi<nchVC7mq8f]=F5cu;ϏW4oW4G'qA4}"-,^%[PU=cq~ʬZQ\MŨ$mTM+U~Ki_ERmy=-&Σ6^6 :ԍwְxiyZ7(,_oo,vP5x\#O2ywJ|]s_<_ |=~7ZƱ.;HDhf!;^w>3XKxSL2 ZɪZcţ- Lʜm<ŀYWZ5%ךm])$* oW}֛&:&5nVjk<1/X5x8imMu$X@KN+ -į':1;𿇵HŤAp&2ʮ͟I#9{|&~ '|EūoH4sd}i ó[[ :zF&b!wR_vN4ҵ?i2x"tdE;25{(RR\%YQaf(n)F:y&՛2C+;7֏ܖbeg5_|+g _h 0y#- 1I^U! gu'Γ?_G.N y"1k+G :wobm*)\7 HK(s ~2 NNtW/*JRT~.-?yk_j5V_Vim/7-9sĺƟV<4 |=HMF FL(?J $|^#co]760ǷiU?PTm8<:Wʟ7Co gV+=HX+DYkj7* !ڽ}rZn?> 'Ŷ.eLmN4+~_41f؏?0X5uOM博c۫=I3dչ)]ϋi?}?j[ 7 1, esH+Oi=o'.1qkNtPҮԒ ? |a?eoxC_ 5~F$_$RJdc!|wW?_|sO $o>M$./..X*ns1e-6,I޾&0 QJi8VO]~usiBVQzٵΩ*=_{'Cx;׏sj%̞VxG0Z?B$n45*|_h[Ǯ|}ȓAo"xuvyHL2(Qȯ4o~࿄:+&%U&٨i èj( D5W 4߃"{iiύ!HC *\WUxϟHb}`񑬖"7#q^Wi5OUiǚZ$xNݵ^Jx#VsG!G<9l]ɒxUo4fGBS\pg'E񖍢i-OOիX^Tv46"(D!@#^]*HOxK[^9hχn]5%Vc nGѻI-aK3hj?'u_>4`_> E[V;c<3H q$iשae״[^ҲkZixdgl>@<}?jwOwx37Ml"gY_A^ KLk^߈5em wOZK`eφQHڣ䁑^;F L]GZ/uo7}Z2[21+6M[ZAc ZYb_0a9s^7>5ڏgվ&Gߧ^| R UJOV8X TFw|!O ŭ ,ObdcF\>'?$fUWXo=<<"'t@@[xS<3x#/ DM!ͣ˧8-7WP#++~#\O~yxm񽆵9׮X҅^]#XP)y uk^.5Kۤ"5--xIIvMAV_hs{YE}lz诌M / 8<|Q񿌗N,֟>m-Yp3g5%nSN>)xo"/ :b}#XÀ r9zZ u_~>6m_Z .e R,hhN^Qv|~j f/t}WmfOS>Ē$2,ȐIl̎$T T֑ 'JqrJԝ[˓P\蚶j/j~*k]jO%5x[{tvUhM :4$t ,{m>i/,تe'q%cEӢ9S[m= ^Ҧм;ac7ŝpK}v*3JGA܂G $UWp)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW~WC0Z}Y_I} /,laR۲2•_Z+xǾ>bI=U2wd1E}CEPEPEPEPE_/)~ X}^=߄[Ҽu5J%ᱹ\SPo^6GSOX#E6DwVpYyҀە9O/į |%x7^|=&2i( ;`2;w#QM񎷄I^E :_K;m6=M3ⷌt⧌/~_ >ieoysHZi_ |jz,k gErr@N+ h;iu6Frͧj9_W|aI4S'tg90_ WyЮY{Yn`-+,&kA{|&~ '|EūoH4sd}i ó[[ :zF&b!wR_vN4ҵ?i2x"tdE;25{(SR\%YQaf((nԤav̽EVvGw{C SㆿoJXY>xn&[xv=eZc~"|ksr#T'ҵ9$RY"&+Ǒc/ 0<+luK۷S^h_|k~W&^5dχgii+|[?LR_:L{otTj~S<|p|,Ѿ!~ſ| ĺ?9q_Qu]=F[DPT|D?zƕu;vȱ6w}[$%qpغcIZ*-r)IJU#wV|.?ֽsK.M-,{Y&ϱh|mx|p/x?#ZZN$qY_+0k| {~x~KJgl]'H%Xn7PH so||UR>.. 4VsZ2ZʩHve*;_hܿV|9ÏmifSM>; 8 Ae"6#2'Y`N~rMTlW29)F5۲q=oR= ]ctKۍF?m@Ole-q!;^o$goGҞ٧ѵ/S:D7"W? |a?eoxC_ 5~F$_$RJdc!|wW?_|sO $o>M$./..X*ns1e-6,IxUZ5-(I^1mB#kidroQof:oϥWG>#jxV^"oj R5+ x.kdU&oQ·#~=<oD~:A5Cq}j>V{9X(<8\\"F37> ~o#P^7džf,fү/y6.FHO.FQD`&1|¾iƏKOǦn|o GaW6*|@ܨFXTjJaUn-/TֶKDke xSj!ΛF7{kiP[M|`ֿ,[i+?^EjҳME%"Yrj?&ωW/~"{IiS $Di<4k221u~*q}wůi_hm#TЮ|E"ipjWQA``[[Go'cr! ]'įxX//gL][jt7{T{5gfU )b?kixǖThykFZVX'mU.vosMzG?eFSյ; [}k$x<<BfXq^#٣suı|,|'+HzxFxTsFMNvČIŒtOZ)=Ν |cw▍Ye#3 ŒK$n%Hb aҩ^u.ҋIF1nnvWMwV2燌'wgdM&;u+B?g{θWWF?>rXi+!| j?< '~xF>d& "na[GIKD BK ??h~#B ;j]>/YSEԆ&6}%IX)sӓ`(EEOu'/ݴ[G9Z=Y]]6n}ƟOV/Ao°$Qţxk,@Eہch?hx,|LφzFҮXghI "b<|]?Cwni0xH/4]}l[iHEXru6o~6ōC᧊~'kmW&2x~{M7F{15̬bwdۓIa1t*><˚VPKܾ[{kդ-潴[>MwoL˥gqFiT.W/3b2 A ~Đi?|3x8%i\AH2\Z£~E4y# K+|OU3okj^,ƯxGPr̶[bv2y/pUʒ Bkg@nn<T.'$+*b0tH$ڴ[[UqםJJ1m4=է](| ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( /߳d> kBZe_K׉3RxJ0]躌[8Mp< Uh~۟:km?*r")$\:4W>Դh ݏܱ(\(ُk{-t2UuKWqR\\ɲ9d+lU#ù/^W."4YcLwZH-Ǩafmx_PSl<]|$sÚ$i=M op,2$,%Xxߌ 1_|C⦳xM/c̩;>ʇbWZGݔQTn.dnρ/[+wP>|5xΜ4ɱ 4V\:32 NWx+MNh7[w1Dj6H)UrB!|[?(R}Nyg#&wٻ qCᴳះ{ *e- ~c|Gş*>˿|k+wgXծա]GUa4Q<^l(iWo⧈|- [~8k,keqnHpÂ3Duk՛wZ]ԭy;nVo[}F LvҬi+Gzv2?N c'[WՁ[#^ ,xyZ@[瞵OV7/_ ׈簎+yhuGW Ay&Փ^گ>TkE7?|yeO]9cKmV cK$H?+?LGKƫ %<+/$9,"{gaۜq_JQ[,V[l͞&۶#B2VY {tWL:#YK"/< )7v_'%%_wyUlnuo,]Y^%G̾e ]>_<=]y~xOv31y"f.FXwI&>F?WG{~j/ <<ǎP$Floyy)%ǦG&r#2/{XoZ9tK\MĊ˕lJ׵h;yxGoi?I_4 ơ'1 |;p8KXF03H- T{V 7P]%si> M$ww7Y9uqpJ=bܣoORK;Y[>h?v>q}givTz/tar:VlZu_?m-dK95 6@_8` Vڸ%+dc>Q>kM[/^--SjCwOwl #r]8V`X,HKǺ֧x:ηk7 w]j=׳*Yey<:K 3F5}QPcۺ_pGR;?gºqj3֮u[Ǎ缗{22b'x aPߊ|}MJŊs.];xxqN )_RQG-[Zv>^^KA[ $B2k<+q$~,A>T?8$WX58?1WBPI| g[\ß$!'ny5_X_ |?]GWIo ~7>&Լi\I/<Byû9T' ~Gzj/7 ~Dɔcry澳αO;}N#_34. >%úϟj_gs7/1v2ē=*ů%f^~7C_;H0]$/ےN}MEJJj[>X,UHd_|'_|'h?>+[4I#MσgӞ5AhDʤ(8w/i.6зCx⾙q1 wXK%=[EѼqZ_xl\$Y w K|rs֢JREִiΗZGzKĮ$$k*q{/=۾Uw~/%΋!xo|A'#F,hfUʀI=M}AEˉUڻ}2IT7O$QEsQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE/_Q%i>!_ y]GyZ>]mR1T v0|iA]ńigZwg"]ͽT ?WQ$+xk]ѮƁ:FEK5:Ubf]PJW68postfixadmin-2.3.7/DOCUMENTS/screenshots/postfixadmin-admin-create-domain.jpg0000664000175000017620000020561110676263533027203 0ustar davidpalepurpleJFIFPhotoshop 3.08BIMICC_PROFILEapplmntrRGB XYZ  :acspAPPL-applrXYZ,gXYZ@bXYZTwtpthchad|,rTRCgTRCbTRCvcgtndin>desc,ddscmmmod(cprt-XYZ q0DeXYZ a)(XYZ #XYZ Rsf32 B&lcurvcurvcurvvcgtu ! ! > %&s "]#%Q&(@)+5,-/V02635 6}79M:;=L>@AeBDEzFH6IYJLMXNPQ]RTUTVWY9Z|[\^_+`Wa~bcdf g/hTijklno7pTqorstuwx(yIze{{|}~݀.>N^oȑҒד۔ŢfJ-ǩ`=ϯyN$дn@޸wB ּc)t7¼y6ůl)Ȧ^ˉBͮdЍBҠEԅ$dקGي.wܿd ޭSNMSc{1S ?i5yS&r:c ] ;p!AL!Y"$S%'I(*2+-./1[24(568C9:@1ABDEUFGI0JmKLN'OhPQS T[UVXY=Zm[\]_`(aJbfcdefgij4kTlrmnopqrtuv'w:xOy\zf{z|}~~pdYQG<2&ݜɝa<٣nI&{U.°rK'ص`6 ⺴c6 ݿU%ēe7ȡo> ̞i5Й] ӐBի_}0ڛPܼr(ߑEi @gHq)YCw4n,b Zk-@[v "(.<R^T !"%#5$;%C&O'Y(`)V*+,-./01233456789:;<=>?@A}BmCXDIE8F$GGHIJKLM{NjOXPCQ+RRSTUVWXgYXZ:[\\]^_`sa[b:ccdefgphRi,jjklm{nRo)ppqrsltAuuvwxryKz'{{|}~jH&߃{\<ΊgAҐ_:ǖvQ+ڛe<꠿qL%Ҧ[0۫i?ݱdB͸zO"ǽtL$®ÎnO4! %Cfҏӻ@׊T݉ +efK~ndin6WeM((!GP T93G*6DSdu6Ro>e?l/a@6s7yL 9 % v  s x , ] O^?#"2Hj'U![ !I!"#A#$%R&&'g(()*R++,-a.)./01`2333456w7Z8>9"::;<=>?@ABCDEFGHIJLMUNOPR9STVW^XZ[X\^_`bTceGfh@ikQlnvpqsXuvxiz{}}L҈{ohtܝ9F]Ű$Xx<ŘN̫UӪGڕ޻ Q8i92y $/;HWgw)D`}$JpAn2e C}8wEh  S O Z  p / c4 yY@/"%3Ie$X*i  [!!"d##$%7%&'d(&()*v+E, ,-./Z061123456y7l8_9Q:D;8<:=;>ĸ:ˆeԳG۟IQW"\  /BWoBk(^"a+psn"}< ,  o S = 3 ahx I|ko$O F !k";# #$%&q'G(-))*+,-./012345678:;<:=]>?@AC%D\EFGI7JmKLNOOPQSTOUVX+YtZ\]s^`)abdSeghikllnXoqSrtNuw[xzk{}$L߅yZ[V R򜋞B𡥣b)lEõpM羵u'ň3fqQԽeضE}ݍނߟ sX(zX5Z"desc Color LCDmluc itITfrFRBnbNOesES,fiFI>ptPTNzhTWfjaJPtnlNLdeDEkoKR enUSsvSEdaDKzhCN LCD coloricran cristaux liquides couleurFarge-LCDLCD colorVri-LCDLCD colorido_irmfvoy:Vh000 LCDKleuren-LCDFarb-LCD LCDColor LCDFrg-LCDLCD-farveskrm_ir LCDmmod*MrtextCopyright Apple Computer, Inc., 2005C      C  " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?!~|ܾ.E^]LIGގ9?>ׄ_V:gZ:yk`^̌RApFg0mvoݼMwW}z]gӾ1C؋H zgE|>8vVE,n G,rƥ2>`2Fw?~4wCtZ/ lH8yH,[l2ASܵM~J'Ft 㖯Lԯ%z~E<# 4-42i֒{A$JYĒK0A 0> G"?;(.ukL}]6+g"Bx .1+zwz/V/1s^5TJ t;[Yu++-0,;w+\nwIqtU Y>^x[<k~eGHm-[xl '/ 0k+]t׋,K)A-I[M4D ;wde\X.w/vRz?};\4QV V7{_FP}hOmzgtiZdD-SY`ǵ@FF]͸1ݸp@) ǝuڷ]u__D𿊭.A7|H|oqjyR۽4X* ?Rx]6]Fe[d"I0Ҿ~ooϱMY/PnȚ>?]~u_ÿZ]9#izQis5y-P3h"ɾ-ĸFjywi&:%D,fxH/o15]UZjc>uU#"kj|৆]A6ɧM]:iJD,c+1׸wiErU ֡<+sãG*p-n̂YU U ӊ_wo+FGjϜ}ո<񇋼T~$C +m&#H#6 >V4l/x.&l5 %)RyH6F#m˵KM7+/nrN.Kkm=O[_ [ғS[awĐ1I-#gN8i_,՟8}yh|DY=NhΓ'Wmg]9D,<_+7|b->'Ȟ!7BOT$C6&Vs$? U}ƕkwWż$owa ` v__I?}';}}=b RzjNY㟳ܞQ? 'o}s\iWo]DqeTk>ES.~97mjN+Jy=]Rlnp*Jku(z?cVskΗRz̟,K>|!YqK;=!,t$2)|&!saL|뮟}]y48.y$o gʼn<$#%fg]۲j\['/kz'4zHVl-Kkf. OcorqLW%rݺ审]6}P6{W6и QF1]Ski?_RFb>[?ڗKwU"QcRzq=nQcRzq=nQcRzq=nQcRzq=nQcRzq=nQcRzq=nQcRzq=nQcRzq=nQcRzq=nQcRzq=nQcRzq=nQcRzq=nQg-ƣw4!Ydpǀk/D~^.zZ8REMVxR5;ösy^0 RMԼI"v;)?#U`>)D(µVq^)J@mΡx!ƩkcQG Wh+k!Ӯ$E)FC)A"#?½Cp?$eV+s)eW)xR?;VR@A%̲CФOn;PG k xEr_E`A&6Yе={P7 HHHHHHHHHg#K37!ggx$WohV>+Aū%ThDbC4N*:n/\Q_Px|5>wMq6mwáfެk4gO~xoE>7KkWIt0.F8J'N,Jᾧα /h]Ԣ[4F߿E|QEQEQEQE| 36|`ng_?~.j.=g{Ⱦ%-m..+#4O Öꚍ܀6YQ=+wWh~>1)~7Rb,Zuߐd=IE~`~?r4GKRMcg~ߴy_I+;睞o}7QEQEQ^=l~ `EZ=/n&.\Ǒ{9h?:K|мm/%fݟ+wݎqQEQ_/|Lº-ϴjnb g1ͷPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_q&~~͖zE1j:]/WjŕV;q ;s')>5#^]r <*?ڎt~'r!t0]g[V6FDF!r-d}9,eWNF_~Z-CWvgo>=}C& *?GM?PF/5b%FH*?W\5;?,O !Av}YY^ȚY(.[( !}{s2o3 ~zX&[ Ror!q3!`A!8O QZ֟VO?/# 'Vڏ%M|YANv3׉~?-ڦ/ ?źo;v+K,mb}XN6+Io&~:x[ƺ.{/*E Y/4J&(W)!aHӾ%xoojV!nxQtKdl<|?rv?׿>B~O|YoshFTH꓈̉z}eL$x} s__~:~gzu4{mdV&x[Ku-G 5e|[W^ 䡕9G|ŽO~Q:7E=xgƚ~}`xYB/ c := >3QhO/(V}Yh^"|/{4pZ3,$0Ky7(!Vq ;7M <hI%ͤ/-V,v+)ݬːhJ-c& ^Kwk  xbP,DlIc#y7t@?xgn^jht?O!TԮUk̫ |TĐ_ߊo ߅._b4WV(8 AkO_^]/xnΥA`aXLq1XrM{(hԿT'>~)'oh]|wf^nwJn id$ijD8,AV+~oo׿ ?i=^yf1EV0>rEڧ_o \e/)Կk'PgKw6_ӭc4K `+.*[l/3M__@EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_ G ־x7 x^]7|kWn m$B/庹h$3 I e[Et/ f8f6* ;^lXQs_NMO/g9 X3ON;Ik:NI<4(*+Qw_(w>(*+Qw_(w>(*+Q>,i~?|G4}B[y %K]`s}UEq4=gğ k/iZOwʼnfT0qͿ2C@aQ_ŽEE2C@aQ_ŽEE2C@aQ_ŽEE2C@aQ_ŽEE2C@aQ\=Ym&ڮ2i~yc*9t|X<sSĶ j1M#MW @cw_(w>( w_(w>( w_(w>( w_(w>+cϋ_;{>P^H'dR鵗keA<@UQ\Y'mZV7{1bhپxa 8t5o(P?}}PTWǿ2CG(P?}}PTWǿ2CG(P?}}PTWǿ2CG(P?}}PTW~˾7<ymSY}sP}AvF8MҀ p8yυ_IkV)"o']@"1|Q x4(P?}}Q ;/;_(P?}}Q ;/;_(P?}}Q ;/;_(P?}}Q ;/;_(P?}}W˾7<ymSY}sP}AvF8MҀ p8zMwυ_IkV)"o']@"1|Q x5ŽEE}E|{ ;/;_ŽEE}E|{ ;/;_ŽEE}E|{ ;/;_ŽEE}E|{ ;/;_?e[~!^Oɺ{#ohs:uA@Ex7G/¿K駤R@ͰyDbR*2y}y(P?}}PTWǿ2CG(P?}}PTWǿ2CG(P?}}PTWǿ2CG(P?}}PTWC|7I}y̹F_@Jzcx/?5O>z}ơq-ZAHj08>=?G|eq">¢=?G|eq">¢=?G|eq">¢=?G|eq">¢=Ko6eQmWWENs4<1•: (~!x]玧5 m`bF(Uv ;/;_(P?}}Q ;/;_(P?}}Q ;/;_Km;y[]Ndi j7`NO'<QEQEQEQEC]q)P}Q@Q@Q@X+m]SV4 Tb: +? ((((F}[B?o Wf+EQEQEU'B?cIuO(OB ( ( (:*O?=?AI]OZO"3袊(((+W-rx+ARS1S!?O"(((٫٨+rͫk 84M.ݝqY?iߧBk/o7WaC!JAn@IẌ́=u:7ouUGiG[73+ڥH x#o;Q?_𗷌IͿ%ѷ{wާ:DŽn>c8pch21VVG+){`W|<^/<= xD7ؖ7)ovyF7Ą+-xS-ekjZB,)Qqm- Uq8$ GTgPmC_XK=N߾vcwx/|+ IQTz\:\;^#Y-X?#=?'|[~~G@hz=ݫ\=Iiw|BHýخ`^c@B+[O\/ ƌ" eXWJ^ңor7K|t^rEt]pնWw^ s7ǚޓ%ЛH!*R%Lys v}_FWo<zJKwS!̈w8  c^oAЍrK>v(tyYH h]_c|W+ Bh,W6vėHqpZ;&٘  18|D7;_'Q?dSi[0EyV&XՔ;q ~xGᏌ|:5ɯ$Et|u sXt_Þ;nn2y{Ium=oiBU?=~×%\[EiU[+$&Q5b3o602B#/7hm )k$51%O $׊<_{K7Rx9ck|S )?y3F;W@m.<]B[G@:;g|Ei%k;iH?$l#z`7W_G}n2`u1^i6mѫWA5 p<{Yi{ *@#1#lubp;ܛw1\®,LFfqr s_=ict. Se_|HPj0>zw X {% !;p ZRTmZ炿'u?k7,9Emx+ARSZfr:*g~Wmo_ k߇t ]4OTmmp m:G>`k}i{q,v6~Mcqs+ig ^=7O/7ep<M6aXZ4vT#)cq!?d|麵χtt`hbhd `*D pǦ*NOoy홴`k}F-&HUYndH-kdd|NxwǾ+Io5{}BKX[s@1!$ޝq&Zxž֥֮ Q|EZ̻n@;Ydm~%/ehvv s-Ǖ4[J#Oz5M?z:K-t-jImF{Y-[6-Gݡq"/ \[Ǭ#6qj)$\¶;I2$D؀8欿f}KkH7QE:A1CA%Bnf`x'Xдbhm/ Zx^7H~'l2-6o^xWvl}6KE|~𾽣wEZCD1&tnTH"@$E}+IKi`ԵI49!8%Z=(V@nNs6'oϮOa}Mb 2,.r!uYTbsd> 6n!1Xi+el7صK#n߻$`IjUUgO߅~(jeJ[7o0VxTU+2*O׎!rx-D4)_3߽f>~o׎}_ OJs7,9Ex_/wmWDM3S5[{+G--doή8_\q d[+6We}if86. ѠuIN[cvicm?,h_Z^G_XEZxx+r~.sfm=uXQIVf[#R>tg#Ï>i:ns.]"m4g9 ;Q1銗ioZZ/tkiEIk28d[dQf蘛vo]t0\^_0i0 +nX98o|z熼+js]0l s\#F`2r'Qxe麿//d,V_2c<2+i -5> +ZRq,qԙ!ڪ$' +YnVv~IB]]z殕RxoO!gjzi\ZG:wDaa. (?Zss$/m6 8+E>[`2f=5l+}_q9̌mV6_5ZƠ|UmoIg<ӴB49#ݯ_oWp7>sGB߄5scpmg[x Aj\@ ߈t?enu{IIZ9|&|X|yf?[ou]=tGpuT"0Hy'xM Z,鍩5Τ.(#֞?VQrxRҙtlkwr5e_SϣL񶵬|CMKOKm-"1P&︇TcMHgYDsetƹ2yH-g.kilMƯ^3wuk/]\Z?ɚX9v;3V<WDw:Mk d7"icQ*6ӇB+9uaiEAIM) *N}M/weE_z]l2Ԥ[tVyh$˚ڶr*VGu#c* u7ipL0+*K3`sTk?%v}NO'A O3,iu[Era?,kzsӚ^$ḵ˨skyDT0X 9/AZֿڄVWdR9330f…U\ 8#/E,+7<+{Vw;lr*_>7K_p73''4]Oe:+QmӃq>/׉|;qmJo %Pŝ+C-;&i ګ&n+<'|QC>iu|џilgn3Y-+~5OI-A-ˊ(BcI8֗𗉴qO[?<5Y7mݍFqW\|u)u/ $OC0,d ҅H$qS/Oo5:~j_ڒk $iequ<Cm"YF`I~ \::MtB<4|wc4.ᄺƯ9m+kkG\ 3!%LT5OueT:ukk &ݴo FZS"ج&Y\rnG"MZۮF|Ǩ^|J,Teu>UWw}F@8A&k{i.}qh5茱$J$a⋒nEs&umcGml-WV'[O?Qy 2Q:.Kk*P,f)ZyEy|%;p@糏5='AV?_IUrO*Q@Q@Q@Q@f^Qyy>2p1ZTP?!6G!6[P?!6G!6[P?!6G!6[P?!6OIZ6 2>ECd9`Bm?¶( Bm?Bm?¹]׀.9V Db9 I&0# k0w >/1j5oËh[})MQMWUA?q?O5{ ҟKK| _}3?3G{ ҟKK| _}3?3G{ IZ$0*nZq k$ #8aJ3?3G.?g)f'w?  ?  3?3G.?g)f'w?  ?  3?3G.?g)f'w?  ?  3?3G.?g)f'w?  }-HrѰa9?q?O4Wghwpoa;5Gr_+׃YK| _}3?3G{ ҟKK| _}3?3G{ ҟKK| _}3?3G{ ҟKK| _}3?3G{ z^nc.ͻ J{}F R1ǧ| _}3?3G{ ҟKK| _}3?3G{ ҟKK| _}3?3G{ ҟKK| _}3?3G{ ҟKK| _}3?3G{ ҟK_svVm1vW˟UA?q?O4o;?}5{}F R1ǧCMWUA?q?O4o;?})MQMWUA?q?O4o;?})MQMWUA?q?O4o;?})MQMWUA?q?O4o;?})MU'DG>7 Ϡq?O4Wghwpoa;wTVU2OqU  3?3G.?g)f'w?  ?  3?3G.?g)f'w?  ?  3?3G.?g)f'w?  ?  3?3G.?g)f'w,NH`,U3y9B7I#F,p'>G.?g)f\~*SN'wJk=.?k=.?_.?g)f\~*SN'wJk=.?k=.?_.?g)f\~*SN'wJk=.?k=.?߄-x5j6KXZ"c ҚO!^O:[^ǡAΞױMQMVtKiXY&hXgsjj(*7I#F,p'>Bm?¶( Bm?Bm?¶( Bm?Bm?¶([-8+1O((((((((((wI]jξ,8|QE|EPEPEPEPEPEPEPEPEPEP_o-OMkm+K|\"$C-vM+I 8ڿOESk<5 uyn4-t]JJqF3@wׯu?PQ]i#r/$ Lx@+ Oݿ-t2Yx=~94:Ű_+4 U=X=}As=bٿwEtbi _Edvvjc6C 5>ڦ/I/ F,&)q' e]Fp3E{Ňkn&ku=fn.%yU3ENO '95MN?#4& ;5)4DL]\ʭ%KmSDF1f_\߳t?]L6ZDo, ~r_mES{_Gtkd5~1ϛE{wԻ ?h{rZ敩rH㿱m7l?#v7Fc41.|.-RNV{{dGep3Ve2O~+ծ;S+hoaǥ[ 'eyKMUi +j?oY}7ȍSv|ۜa1ko +o[_0IIӢ涚ؽOoKU|EuszHEXO)*2[@oxxSPMk:Y`Lc0_+{Z֭iqjz.m].5{;5D` (ۭ 2ZK]I-_fI nY3K[;[Ho'i]RW;߇_*xB޽J&m+vyX퉥>nnQMuطd fٷ~-5g?!m k "͒Oom.G9?cS_]C o/ ?DZ_ݻw{q9F9r=I}i=/tXH{_x X.<SYԭ|7y,t48$˞PdiJGS? ;.2)7.ӓڹ['M6OuEkTF[H_ܸ3}т9ݳ' J5)⳴UτVlĎLiYWWOS9| qIk'ټ[_Pxr;KqgYW$H`_?,yۧTo.Y5-m{?+ooӬ~xKPM_&0yP[Ya I;hWG5էX/b\[ʇGP3F ?`OM Yu{3^>_ٷϻڽi }oM:ud_^pA{nϽ8~Ok[XiiewQEEPEPEPEPEPEPEPEPEPEP{:IUrO+ Du oW$}KOE( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (9 .4 㺹Dd3,%V##漏Wşÿ7R~4i߳B}_j> n'= \d Hk>Dm>"[< "?Jd1]1 aY8Cp~7kͮOˉgV-пʾ,ɿʾ,ɿz7kτ_x#v4oKޝirJK1'Lfn5o |;^ iye7nӜ`X;/^9V&Wşÿ7Wşÿ7NoMGĽs_ !>3sniuch2CSF m?m߆?<|c~^85s$L0F\<7,̒"Hc}f0RT<NM?Wşÿ7Wşÿ7yw⫭ Tӥ,mӒ 9^w;E V Q'4b`?p| Q WTQ0Ͽ2?緇2o1G2?緇2o1_EQG& }/>gοʾ,ɿʾ,ɿ}Eؘ/\_:*{xw&*{xw&Ub`?p| Q WTQ0Ͽ2?緇2o1G2?緇2o1_EQG& }/>g:Z͖M휭ż'HE%Y0UyTW|"®/"cOB^2ok6[Q Lf.jdc^|vFc˭c^>&mZ8;=.~oi,-/?L_2y^ <LE\_E}? 4?:oo?ijxj}~=b6VexlO:E*BL?k/l+|J .&_\=Tɽ!Xwc0K]oקQb_]=y^ <LE\_E} o|x>?ZO:/\6u*#kqEq|#+2𯁴2ixUM[;SΝ7.rqKki;&z>e=E3qy^ ?ß> '/+BfڅkwVʪOgv&/l4|x{g/*(=E3q-b`?p|ux{g/*(=E3q-b`?p|ux{g/*(=E3q-b`?p|ux{g/*(=E3q-b`?p|ux{g/*(=E3q-b`?p|ux{g/*+DSn[MjqXm!*e`px pCƏL_.}/0UgM(UgM+(ϿbWşÿ7Wşÿ7>a3_e_odbe_odbL_.}/ϝ|Y=;?|Y=;*?0_ظ?>uUgM(UgM+(ϿbWşÿ7Wşÿ7>a3_e_odbe_odbL_.}/ϝ|Y=;?|Y=;*?0_ظ?>uUgM(UgM+(ϿbWşÿ7Wşÿ7>a331JNy>Y_[IJV9UPa)Hum\ U[$BpZXHRV[N>.RQ]EPEPEPEPEPEPEPEPEPEPEPEPEPEPEP5?;Rw6ǎ~{t{V6YH V O G?jOû? cUҼ;iB_kJILmե[tMppc7/aR4F^۞}Ⱦwv_g 7ߍCDIM[ŷ~ohz֭Kxs^:SX[&+aZR{zw[GĽOHZ\w~%iZhkqeg@"d"nu$ 5:R5ciU(Kǹ4y| _>ռ3g4^%f+%xMi4N,nTkl1>\>4Qm_Sg}XߥjTZ wwO,`P]p?FP7_5)k0^UW{#m*IW;j_.5'ZjOkڴ M2IA+y{o+/?] KiA4f羺$lgDLZ2͸'_3 ԭ8\iD)p람2yj]˥I*J)}EqQI&Ҷjo E[ʫMjv>??_&n_^Ѵ!{E.u4k=w [<",Gc_~x?[\'J>x :Uޫ}=vsMŠeDȉ{k{/\eYtA?EXRorݷwXhZ/owy\ZMb84ub]p=f_<]j5aV+-C^g2j 6̶2G-0AWYug]Ӽ_74\_RQo%S4wp8'U9:UR;&% [Jw9;ꦟݽR#.WU,=ފ]ˣ.WU,?w.=ފ]ˣ.WU,?w.=޸OIcG{\\ey6D_>o}F^gqǗۊ袊(((((((((* oU*'b(((((((((((((((((1꿳Kmo ֵ{[F1*++2r)#<ƧsJCmO +O![oj:5@,l$Ԥ1eovF[(L_T?3>x{m>4 (.$hՕ\,Tq^%Gt Bď s ?u Hau pP閖E;*eDXJOOPOIoto-+3׼OAԼ6 ƅqy]^kܵ3i##|3yHU۱VFu⮽i> c$t)yQ[$Iqlc3#4ZuOuYshvN9eYC;8 \υ_ ')kS._=t GȰZ`EKhO&+o{~_^ |`O i gW>[+ 5h؞ExsWoK#þ -[iz I1kp)д0"i3)DÞT|/|*[XU͟+w7r]Bבomtv{w0\E&dY?zta4oeGK'xFV2iZi^ 5YVL5ʙvI@;]{00왥:4xZ<cɵ{&K vڤ{o_, n6u{k3n\79du\|?C^??K&* ( ( ( (?9'Zß>j~kMRQeWVXgj ~*P~~5־k>*oZ4m(|K{K0K7% `ZQ;e*~?<)[^y|EimFfL pC?E׿hϊ6?'|\#uiZ (txu <ոYeL(Q3I4/SSis盏/.A[(v/kA;s)yTL_ _zu7Ö2[kC߰KkWrddFqW#i>3񖯧Ϩ|CP鶚vF"]ą"͵e5TǿS[|Pey:eέ5}WJҾcZ%M%6p/]d'g<qMgů4i_tǨ{by|`ޔ=[t%v5U[FQ%Mu[tO+l~]^jobu})(Mbkd/"XIaWY&\ NUëO־7em#._6VjOcqrM=/yX%lC-g~g5͞ v<$:$WPxBDN-OC4O(<<c vz=[^N^ >]:JѤ3+;cʨݸN]'NU4W{˕N1{ӝh]қ[8ko;h?hGMCg]Sl#K6u"݁3ۭ߶o>"OM|w+'69^ѭu9Y["\7J#8O$5Z_? /4mk$}k፥ߌ'2qmiX#-靗ͷD^a]}g|qO~_hυ6WEFW0sקPn_i*'o+tZe_Q_~^&(x ލ ho ϋlx4o唍@C%+o~#|+NԼA}gKWKvc'%\C3NsIS?/k%j.y JncҠhⱷ2gy$y<պ?>'_M;].@ΥxTzN_C{4$MrdKvj[/MߚMjRwV[ZOx= _OXZɾ-j孻/8cz7`Yg#~ך?}_^h>Wxk_(6%]_%5=wR h2c4<ܑk(ӾETQEQEQEQEQE΅#ֿ^?^mq}R}P&jy?jƯ#GϿ+ĿÏ lzi/-Bg"`yUf)&##߷/?jk<߇MKQԠաR-N<(\.IC4;ӷ[ _/'['?4#GO%?|lkWśGzσ|ڋBۻLJO2PNmӓSjc|c?# |k<#?Əc|cz(?# |h9G6?w<#?Əc|cz(?# |h9G6?w<#?Əc|cz(?# |h9G6?w<#?Əc|cz(?# |keQ433T4#F6sFOIcG{@W9Ot |3׎muKBIA]eؾ7D+U<h׀t]WO5 >cNt{~.{Uz5)uH5 } f 2!).u~ZDMŤF?t%H;Y1j7' m&gnI5n_OVvWΟT:잖_xKl,zsnoUU'4]|%nGkOKW{j}9E|[ o#ǭg>/ia g>wr>~=~lMO$)(fXcQt# ]I\2)C㴚KoBzM{=J7] |?S 5]V KXOyifq$^R*K#edž|f<_~+[x_3}隽އv"JLf`o7rWrsV_?&m2[_lwG_ۻOm ?XZݮV8}iX1"d-ƓSBO|1+W695=KKnf8_38 s /m^j5h/i?5 _~7ψ4Wkk;}.iqƹlw5I5]˥Qxxx+<1x.]\ޫX׶C ^eD w9ߚN-;u^i^5]v3O!SE~m\ wW,QE (((((((((((((((4g;Yf_2KKd9b61*J# @7C?ږ ڢ[fE?bIݐ"m^UɷKm`yFtFx<#Z:??Aoe~?ֿ2yFtFx<#Z:??Aoe~?ֿ2h?ǟDk_G4g"5C&Q x }k(yFtFx<#Z:??Aoe~?ֿ2h?ǟDk_G4g"5C&Q x }k(yFtFx<#Z:??Aoe~?ֿ2h?ǟDk_G4g"5C&Q x }k(yFtFx<#Z:??Aoe~?ֿ2h?ǟDk_G³kK/Q^Ki?6w,Lʪ9e 8&Q8Z|FgyU,grKG_zaMznxJQңFH w";21 GuoQ@s~ t/?_m>"3)öiD~q-(w+Ȫ#0|u¤dj {㶚H+cj9Ѿ'x/IýR[5HBeTHFV pAmnyok~?=n]|%|# oýƚԗך,;Ei.!#;ba+4~_>i%M,|ghl5m'6PvYL7iJDN㓟Rh $W$ A=ߎ4tvUL^!eb̻Xm$CK mxPy^%3麍cKiJ3*HaA2’@E wD>Qj5+}*k=5'swsCO!:nk6YvjV:x@RDe$`AVg/ k><5bVC@ݖUPf,H$y"h? |x⎳x{rֶPI,BRk7?~ O 6 eDD$ʟDaFTݾ~_uuj^i>#[_隝wvw,2сE&VcMtpe? /| =*jP: vً($e&o(󷊹{=R|{}J)4kgIԥj1:%ܪN1¹<~)xJ=P}08'NP{1TnWK7|%~zx% qwk [2<˔m#bQ£\χƤt>x 癷w 6nwG+z%+KeVN-iT7,oܬ\a hdNܻW6yƹ \{ğ>j 'n|#a-ڜK慡*n֘x$*?o804~[5_ X&nvh&08B4xcO ֋Gyccp6HXeBVDe!) 5SGm5Loxz]CR$Egoy ?Jji-վms=l * oUw ? IH(((((((((((((((()u?~tOiγ: \\%QDUTIk6W>_uO8L|>Ÿ&w|Yӵ#uՕf;!SNU⌤l } \'$?P'(x UVgg)mw< ׭ jZ[ Jm[`n;C Ut;k/_%M |i 6UYέmuM+˫EAo5H5fe>ŢE*no5monv9n_J_~f<ƾV 2Z~DTl|90۸H#7AW⟃i_ xȗZձlU6/gi1C԰26@_[7[ݶXr̟o?oZŭ'ޡ;@jvZxFю[M(-bG$ &o1 5?g[߈{gτ<ogIyY]܁$qg2B47]9~m};KM?kMſ)aoi2εxF;ӯ"5+v%G[Db6I|wڗ>h|/ۮ^>|st?W III+4QJ]ZF+'gi+ kWkeivx_ZeZh9 xSҴNӵł5ˈ-q+<6 .o;FL9O5Դ(&GDlg:}Q[+i*4wyOVp|ǽ7^Cߌ_l _ֳ}XmO̰<|M48ҷ5= CiYAu=^oaZd݌C >lR41ǫxZ? /7VtMY1~F8ox G>OOڗ<O9\k@`_2g'F--!z+hP*[[5nYFm+~N;O/~0xw^axzFm9<;ykuⱏuȒy!Dh7j|◁seߋ~~7_ڎ_^K=iI%Mbᣎy%;%E))EFpq$ռ +G㟁<~_ ~+sx!ȞyjD"tE,&xɯg8o~!o7̺atOŧ-Ew8e7K{;EտvOH|rī?6v/6k0ևkIu8^ɽx?o:;\J[uu ?[eig'HLW+6|l⟉z 뚌<-xSN hRܬj7"ͯ%O a^|A+x4 j4Ȉ. p:Ti^W:9u&rluik2o>|kA'{ff&[d1P7\E2?⧊ψ^D_tCZvm ~,K7wDޠ篆OO~W_6| oxZ_m[blmOK9)Nj>5zP[4dkH&"t+ظqI;>[|[4oMTә'u{֊{;׍|=? 񇏔ˡpMnuHf ]8#f+7_|?c߷k4?ٗic_]y6eIdEQo'_. GSx ^𝆗GuWí}N[e{:F{2u0# %/ؿ'1x_  G>!j{dIŔvQIBp4`9%{'&4UﳶV)iemַz/? i"͙J!բlnD6α3zƿنQG\o w˥eLlvHX Tn3`u~Iz+w.0ueۻz]~[_ U_ |GsKqwXuIДiʲltFҿl/|BZ0(@!_POZ͏CgM٭ȑ.QkSa-ڎwV=OY޲"nt 鍻ՀfcoCoOSZxxY!5;na(4o1.Qb16?{yB*u9|iEWIۢSN{ۼ]ӵ>?:W5Oľo{WїU4KK٦B/vA9[gT1r>k/ #|P >-hCԵOYk-"Ai4al|(n?U͇"QZeմ+e[WTYnBs%y:/~ e i^&mQ Ƨ =p[.-nQm7zlw5mwťe+<iBx;ۧewmޖo5[χ>1iC\Zw5h{p̆ͤȸCTFN_ïN|x/U[SSmRC$+.|WȚSv?G ~5օ۫G:΅uiM[[-恞<)ԢfNM~+|CPd~^"V5+i B7/-Ww1;`(vQOޒkv㶶vzsn|_]+s-c:jpŝ\[]+$r*G! gOj /;ZU-OOGDeR0p:WiNi)4wW[kX*1TeA9_}O@Vg-nEJkhLXE "P YXTvVC=~%QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE_IUrO*Wm\ EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPy+rXE~?ycXX0ᅅ.${RҴT3Z[srw6${e_ Iz:eĸ*AusI2̘[:/Zoj j5/XVvt|ZiCo~.4F/-VHLDˈ/hn=ڵo揲>'J~^@ǖcDVmaktm2]˧$,K#5Qf_f_ xSŚ|CK-u=Zsel5 c<^ȨyrIuh^hOh$S[޵]W?i_xy<烼?^n5خ'nN[x#1cGW v27X _xW:Njg"Z[u6 jmqqycOcf|ҁe'Q=5}_-Z+J66ˡK@Z?? Oz^jV֗LxB\"R WH]Z7_𧍼1hމisyn4~T).ZxYTku%.v$_v#8Fvw|*nIkC +Z5^υE^:5RFm,Ӫu5ޚZ}=fv5o4dx 5?b=) _ |:_!и]ME[t1 Y"ca i즜b՛[tZQsU>/|?߆'C_ ^IbIXS(F[1 /Ob嗉Zi_]oᾗL.uմu$2KV;IFrW* [RݼFS\&ܓoZVQ_JiW=VY|>.#\.tkI4-:G2Ń xm_7Ÿ?-x[iEamxwQt4x'[Ļ/?xH5KO:H~kp)c#et܎ra5SWO`o :4Zn,Jkrm.,˕VPm#) e>fq%?ObJJo)IGs_Jo <1οsk^4j1ֵApm mϳx'ZZ',l$ñ {;hU>^ 31(畭黿o$K7{Q%㔿gIxPO5m+N.mB-mvo) HF%Q@(MŦ_ {ק]?iA?]?oKjx&w}w-Իf#}ϴjP~%~)j:o#R;-g ?yOx@ϖ|)=w۾M3oپKh~hwaXcx $G.bbÇ;yK -w'5(Es]juv)4?}l$dTgwtQz0Mz-/ehVAm|x5].e7kN'" uG Z~ԭ5M#Nn&uOod7 u x #rWڨ?e$Dm_]w<3N?.Au5 3W#Noaye{qcOs-M$l*1ek igx'7;}[^1~!E汩>>wpM5ܖV ovmA擷u?HQN-o?o\m?>h: ƚ_iFyH>ky%1a6;K/ 3ؿ᦯BOj ĐxIdh%ՠN팾K!^Q=Ƨm:r(p8ג$QE;UEO޼SPwwmWTY.-̷0P?+7pO&ӳ >9k>[z=Z-oAkql̫rjHϔᜋ~-Zմ}K@uϦ JHem:ba|_0:J-)%~׶SH&I-ّ. vś#U_msZL7mY Xq00z>hݦ5Gso#ִ𶱭؍k[XɖTd vq:7V 6c&I.lNaԡX9^vÏ RXxq<ae,r(TedVU!]YD4U{m3sgɻ3:]u[4gQ~׊Ci<1O;{7^߈P3xVoе}THoIY1RO]ۆv ß <;)@h",Giz2[ okŠ((((((((((((? IXO!@((((((((((((((((/aR4^_ \iV(((((((((((((((((((((((((((((((O!V* oP( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (+E/c}C9^O`Gu G_<1|E=@Eyo#G_<1|E=@Eyo#1#/^*+>"#/^*+|EG/GAPQ^[/GAPQ^Z|3zFc?|E^*+>"#/^*+>"#/^*+|E=G#G_<TW3zxj2HI{{FS#/^?>"Rf02uQ/zGAQ/zGAQ/zGAQ/zGAQ/zGAQ/zǟzF#y{ǨԨ-b?zF#y{ǨԨ-b?zFc=5PQ^[/GAPQ^[/GAPQ^[/GAPQ^Z<39{Ǩb?z=JF#y{Ǩb?z=JFcy{Ǩf3QTW1|E=G#G_<TW1|E=G#G_<TW1|E=G#G_<TW1|E=G#G_<TW1|E=G#G_<TW1|E=G#G_<TW1|E=G#G_<TW1|E=G#G_<TW1|E=G#G_<TW1|E=Ezyzq_}ƀ3.08\>> xkCݨxzVPDӞ cv dUȈPXܿH-[]ZS% RSFmHIXF_G-L";ۊsGvJntJi1I*Fap˲0 `s}kho{8_xZuK;tKZHH*ÎH5|DojWY]=0B F},ԍ 195?_}ƏE>BB[_,;n9x^ᩭ|miG&UWInokkG omGk-ڷV;^|_Hcf:^hZx4j"l>S=w_}ƣwV!33Tq}-~VSVȣ~6LmKew%Zĭef@]),"khϞ'xUӓݚͩYX+i1zIv`#/6iWZi:l|qKQWyn痐1CrYwXK' On}h~Ez5RQd2<4/Uݿ?|xմjX%q{)Hﲏb|a(>Ě;`]V;X=ŕ0퍊-byE>G"_υ^1f T{)Ap_̶RXɂQq?!x5' }9UaVYqlX6?.=kiw&%^~Ommk6uGЮV1n͌ o(gn:77o ٶqr&RI woFyj6]:c_}ƥӱڅfn4ۉ[II+c0F&HA27ZվZ-=Ck Byp mTc1@S"_k_Y5ԔC/S4}B{+ŦjZJD,gۄ2M5///5McFm../ Ui"b S,1\^hZx4/6|yj~5yƣ 4v`-OT!L>B>4\Eiq[4IqtFvc5__}ƏE>M;_BZ>J|Oq,"K[k $竡cIBy۳[׾.AyѮF 4me`ˎo(yvLgnFܑ^hZx4?_6t#>K.6W?Qw_}ƣ> 7Bsgce7$q=ZI>S_O2y?MMKgCյ:]>sk^'R`i\0q_}ƏE>G[8/_ xnukl,%x fgYX+o6qO]=ݺxS,ayMݧyl7+%eSu0AǙ9E>G"_hK7KZ_z}5}WfYH?̻ &_ɴ/Yu;0hqJݺ %b9"*ҿ_}ƏE>I+[vЦ7u87U̺̗[hK@ʱC6rd煹+ mHUFgНg[fo1I X,|@sϼ-K/ C ׯV"_kIxJI&K໩Iy!$PdmBWu[YƉ$ww%I%z^)bBbl0mr2wC.j>!լ-O\&m};r|$0_}ƏE>Jz[_W[9K[Ӥtx'Eh)AzʲQXefu }a!ڋ" :0Lн+_}ƪ?֖_#SoSww wͬVeƙ߽z"A=v&C?uK|csCK}ntx<1ۆhZɐ!9 _}Zx4-u|)|ۀ^?Z~ ?##N.|JזϣZ:LOwfev1]q``<9 :HV;[}u$b 1##{c57#᳾|an ]E}<ɞ Ic Y, _}ƏE>N^ 35oxAZ,"rfUUkYv|ͻ\ʣ8aM⏈6}&ȴ -d&Oq-dƧ;jve/˱հr2 T_}Ɖ{zvM+~-~ǭy:<qMK eYc,2{J>X%6gC}BUc![s_}ƏE>Dh>|ѵkB军k5Em`Omr 73H!xUx}kWLǶkq}wF84mKTK]v,ql7e E>G"_rr&>r5~3I[eE/|}5lDK4BOo^&$֫ ^v骯 "M ,1U1w2I8VZx4-G"_ +Ckh>Zx4-G"_ +Ckh>Zx4-EvQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE|c{R2_es9mm#Ywfw矞E8\5"wjZ KªFN1 WM#|t/|1}MktI=D;dD8kc|W÷:| [Z}wEТ9.4,#. d`QW<>KZɷ[ZAUsj8(postfixadmin-2.3.7/DOCUMENTS/screenshots/postfixadmin-user-change-forward.jpg0000664000175000017620000025404210676263533027252 0ustar davidpalepurpleJFIFPhotoshop 3.08BIMICC_PROFILEapplmntrRGB XYZ  :acspAPPL-applrXYZ,gXYZ@bXYZTwtpthchad|,rTRCgTRCbTRCvcgtndin>desc,ddscmmmod(cprt-XYZ q0DeXYZ a)(XYZ #XYZ Rsf32 B&lcurvcurvcurvvcgtu ! ! > %&s "]#%Q&(@)+5,-/V02635 6}79M:;=L>@AeBDEzFH6IYJLMXNPQ]RTUTVWY9Z|[\^_+`Wa~bcdf g/hTijklno7pTqorstuwx(yIze{{|}~݀.>N^oȑҒד۔ŢfJ-ǩ`=ϯyN$дn@޸wB ּc)t7¼y6ůl)Ȧ^ˉBͮdЍBҠEԅ$dקGي.wܿd ޭSNMSc{1S ?i5yS&r:c ] ;p!AL!Y"$S%'I(*2+-./1[24(568C9:@1ABDEUFGI0JmKLN'OhPQS T[UVXY=Zm[\]_`(aJbfcdefgij4kTlrmnopqrtuv'w:xOy\zf{z|}~~pdYQG<2&ݜɝa<٣nI&{U.°rK'ص`6 ⺴c6 ݿU%ēe7ȡo> ̞i5Й] ӐBի_}0ڛPܼr(ߑEi @gHq)YCw4n,b Zk-@[v "(.<R^T !"%#5$;%C&O'Y(`)V*+,-./01233456789:;<=>?@A}BmCXDIE8F$GGHIJKLM{NjOXPCQ+RRSTUVWXgYXZ:[\\]^_`sa[b:ccdefgphRi,jjklm{nRo)ppqrsltAuuvwxryKz'{{|}~jH&߃{\<ΊgAҐ_:ǖvQ+ڛe<꠿qL%Ҧ[0۫i?ݱdB͸zO"ǽtL$®ÎnO4! %Cfҏӻ@׊T݉ +efK~ndin6WeM((!GP T93G*6DSdu6Ro>e?l/a@6s7yL 9 % v  s x , ] O^?#"2Hj'U![ !I!"#A#$%R&&'g(()*R++,-a.)./01`2333456w7Z8>9"::;<=>?@ABCDEFGHIJLMUNOPR9STVW^XZ[X\^_`bTceGfh@ikQlnvpqsXuvxiz{}}L҈{ohtܝ9F]Ű$Xx<ŘN̫UӪGڕ޻ Q8i92y $/;HWgw)D`}$JpAn2e C}8wEh  S O Z  p / c4 yY@/"%3Ie$X*i  [!!"d##$%7%&'d(&()*v+E, ,-./Z061123456y7l8_9Q:D;8<:=;>ĸ:ˆeԳG۟IQW"\  /BWoBk(^"a+psn"}< ,  o S = 3 ahx I|ko$O F !k";# #$%&q'G(-))*+,-./012345678:;<:=]>?@AC%D\EFGI7JmKLNOOPQSTOUVX+YtZ\]s^`)abdSeghikllnXoqSrtNuw[xzk{}$L߅yZ[V R򜋞B𡥣b)lEõpM羵u'ň3fqQԽeضE}ݍނߟ sX(zX5Z"desc Color LCDmluc itITfrFRBnbNOesES,fiFI>ptPTNzhTWfjaJPtnlNLdeDEkoKR enUSsvSEdaDKzhCN LCD coloricran cristaux liquides couleurFarge-LCDLCD colorVri-LCDLCD colorido_irmfvoy:Vh000 LCDKleuren-LCDFarb-LCD LCDColor LCDFrg-LCDLCD-farveskrm_ir LCDmmod*MrtextCopyright Apple Computer, Inc., 2005C      C  " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?!~|ܾ.E^]LIGގ9j)M7މ_7^!f6v-k2ЬR;R8 ^+y_ׯ^z Fm7~Gu(2hZ%HvuY-k9F_|]Khob7ZeǓ,s[bv7]{:&JMIy1WmiM{omxtPKrV69Q"S~ o|4 ^i )#78>[;+p敬}?K_R/vg'Կڗ45_|@INȡUQx323׀YTJrn;ioO}~]I[)meANqZ}r}A j>ږƷUo2"~g~õ|m&յ/_Z$if5œ\(+v 7n$ xf)];[|M|SCn'1He9g/~;)?nkKq=n?e?g_ }hm٭-Xe#Y~Ov^;_kYxvF[GF$2ӌ|zO7_qVfR[_ϭ&_hψeI';9/Zt6-kg'1Fa yb擩x,zvq𽆍pMw۵C&IU m-4[&6W}-GڳbkzsG55wi?,IwĀ+ 7rK<_ MJ,m 7^)M2ZpKD葲}H0ʄ1!Rm8na4zo]Q>q]g5O 6kw_<O maR<1(LFmIK#2 =ᇈkKO%νeM}g lյh0j#b ƛ]wĆ%?rzaRRo:;o揱?.?'ϝu\-PvqQn,.P8~+Pom7M_š?_EMNiUs=FWd+y'%AX;s]5gjz7++{Kn|MپeR8EbW.|5MNo]<_eslŒu$+?kvijNYڗ+k|ejzͺj[X#inQ(̱"6 -l2|c? N "Q'ߴv+'fckm/eη~-m﮿n ]u\- }u "y;#Y[?, xvu9Km7WZ'Ut҄$Ր.Ѷ>9,4oKxI&éhze͜IԤ@gT`DwU(rq)%?NލwſVcHV|κփZk>]пh%e5Qj_8.53nlch0=oljc⟇ MJ-OEI[{zt[XN_BIvjgfޗRzxSƞ~xRVZԇDV_2:u>l,*(<_kW?oV֗ׯG88y$4׉/WA =#E[NE9b9);61ݴ_|~Ku-kAkRzq=nQq=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=nԸu_(q=n+g-ƣw4!Ydpǀi^yVxR5;ösy^0 RMԼI"v;#L?v{/ jPH=RXY{":ޞW[UE\ׄhVPh 7ZOmx*G ]çS4[;Qw'@ NHF) pA#|5P\E$q6Bcw|m9ZTQR4cheWb1зo[-1ۥt|MHx(PqZ uM☢O|4ϐcw}Q28#8Я᷎^\j:uĨP&z8wCWK,FXY w)6 SVo ҿ:ZV^EnYȲ*r ILcDu5o'6+9ZVտN-~&hu_Ebe QF3Ux|Ec)g"7#O?|õ{N)*(E>g0_])?*m+u7%jDu5o'6+u2k gBdYi+,-(N12arcVVr^ڧ]ӷ}ևvU`Q`kչ-U][տNDuixăLqocKv%O$goj{7}NW9${)+?i_G-M[+J$w7a~b զȔ\]տNDu]EQG_ }/Gҡ3TQ$$Xw$i t=TX$I Ԍ}/HO,]0c\M:-)3Mhz|տNDux/zxrr'{rf#32}7Wu Eԭg#<ey1Md jWI/cpU#5k殿fտNDudj ɫxſ>>{.(@2Yr ~,㮱qoZVտNToW *U?`UkJ jjOmZW'Q SVo ҿ:S_&?ToW *&?i_G-M[+JO>S_&Du5o'6+U?`UkJO>oZVտNToW *U?`UkJ jjOmZW'Q SVo ҿ:S_&?ToW *&?i_G-M[+JO>S_&Du5o'6+U?`UkJO>oZVտNToW *U?`UkJZ W~:&7)r/ԒNuP0SHTZV*0|*5%Q   MTtuW^T'{/^6tֆY<,3kCDuC   MT©C¯_UA5o'6+;߉g-KcJ!ԌӺi~7G*0|*5%Ri5f TG:-0Kkh"V8#E _pVjjOmZW'T?~7G*0|*5%U6ۻ /J]>m6sƯտNToW *U?`UkJ5o'6+?i_P©C¯_U~7@տNDuC   MT©C¯_UM SVo ҿ:ZV*0|*5%Q   MT7-M[+J?jjOmZW'T?~7Sx1<`67.5˧ZNJԅRq&'{5o'6+?i_[_f;X;u֡)8.^X]N@?5o'6+?i_]%]0xB*gHZCmnIu&1?jjOmZW'Q SVo ҿ:?|Q~kaa?_gik{ky\m#r~w+.O  xJpͭE%s0UZk FGִ|%m#^| .nLSnf;# ?i_G-=[+J>7ZL>6Ym87x9APN<_6?:F3qg4R]9w em?xV8K^/|w5_}ܖOv* ~ OVo ҿ:ZV@ Zks& 8KY1V#"X5{KCU u<毬bRҰP;_ ~ûۯ|!xvRa'-qldCV/0E(I \;v5U5^n{Ϸ΃ğlyK1jwQF],W,I8OJd_j7e[gTo/$)ȱX;"nI<$ ,xwW {Ğ7EA[tD4ٛ,rI~RK𦣪޵D1G4]aNy.*u^DZzeYRmMcj|=  }\j7w6\ (Ϲ[JtEo#B3o]O@) #ij/(HM1D]x#UXQ|<I}OJ_ź]WW$BBX [xF-c)(UǭrUrc&v_&GG2%&cGgw>0|=ት LmFhHa, 8ǁ` QRqۃ+}[AukjQc?IZa㝿p5O'8GĊ(UQR֥k{ pj\^Y뚜0g 2X%1-ݺki/: xv-_xUtzۮ:%:|Ya& q#?NeO=k+ų빣MI2\uL!cw|a>e K2B  yp9M(A%86ڊJ/7Տ.`,48NND)Ji^IM]hI~#_a-U\]70E1_#3 X _uFw]2-ByX'P=zg\z~?J8F>5[~=O$UN횗k+$O,b^,8,~Y@'z~bC܌y9^q9~k6݌&>Lĕol*ݎ3ΏEk|ӆF zۊŦNoOxOkET' *a½Zφni3[SO2TIؕVX0 ~,/*a-6 /n<ӭhLk.VvB}$:~ytrG%֛;d \4h%oDr! TIZX+[(Ŵucg[w~o.TG]QDEhU?8<QJsLl ?ȗה-)5H&Lts]?K?oeJ<ҬVI+߁3:`gm],]Dד%QKseeH7 3uU#?lOv^oiw:-Q*bC,B"B!F_yO<=Yi6٢7hZRl?)%Xt,݉<#N> <9ߛEn<`eU`ijly e>֥5jѝGN7'|4MKn{rB4{KcVRpGjqx[|I;ox¾'IxWG2]khmfyD9o$mǛs{Qv4oXvϽ#~,' F襮=$ܺo_=J~,|1𭦃o9Ķز#*K__3ZR8'|w_tcmFH"k[)~ |\2!?:A'߉:luϊ|BԀ_ NlcGwgyܼfhJyJ?|4~ w/BHm+FF"oP&ZzQo}$>9U^kۭŏW/?UfޔT dRA~^/Ҵ[B_ǚOh2CY[iEs=#KQ2M Gp|9 ?|g4[JĽnW%Y cB$vI _i,z7qofG|9|K+xDl{Inqu MqtȎ.k-BV.-{u7j][eUi7t^*sxs_~ _Oֵklj收O+g+y"8| +wRoB>w<3~;u{Cd!f]_Im3Iře؅GShZuikwڮu>"//QL6 h6 |"Uxk ƾBh1k摠]iϥXmK,UI$,2yH*uusv׷5J_[owd)ە};M_yS}WSδ-D'li炵hz徣KsDQMKyZ\Wt:˦ o i>!xsꫦ[uv𭘊Y#kc,VM$rO0<" _Wᾭ x>D&-w^O'41 . ^.gi;vvOK6+F;IuOPvG 5YF!0yj?#o9/ OE5W+ΚEW6R8o}:J~~,~ru/RpUyݿ}O>gC>g@Z~ֳxvX~?i 7ZFX5\\]d8ⷔIlPZ1~m{_u^_M6?2Y5J%ϒK؄ vV'>0 c߇+[i7Ԭnu˛;6Wk[ h{rXJ!h;z硚mk]O;۾_K 3/4>jZv 8Gx&-B;Kbk=ѐ ½"JS?}uwqn^Q$ X@ϙ9|,U ǗWx/v7iJJMT\I+-7OVqr{?|P|HC|!qៅ5/6`&Y.#q;JV WwxT׾ Xszֽh+}KWy"AolI@? wbhJ/4Zxoq FqmtZItOHO*Yci[/%W rмm?&i ֜UԲϨ[[4<@'Wi7;6 i?wgu9VVIqo_;#_wM—lux#[;k{ I'X8~;'uw>~^:,? |,4ku,aܔgU`P8k+UïJk_ҾTѣu[H1-GDFPXJpO_)JZC>1ګ4FTznm#fTXy0?_σfߴNJ/ ZH|Pis_Ac,hbk9nalS-G$0:ⶵvx OVZw|B{ H켶I4F;hc>L*XOisx7 4|a jZ54jop5͖Y3I=1+%߄i ]ǺN^ռA y_VᾅͰG$0rw]V*iZKٍe.]>Y'?~ >$[!=^#|1q YQe6Ci{QagBe21=L?x=CzJ]'3Hx\A1 # "mxGÞo|>V]F-Uy̞|f18@Ut G S/76cmhQ+լ`9z*)EYEɶJ7}6WV1Nqw]|;im/_W=7^Am;ߎ:FWW3ݮ=lfKf!H\?ğ ׵_coq|xf-nNgxb7m#fl3(o$߇?Jr~9&{mxn6poxeAXju>;}L|Ei]|Fھs R_$o[h miuQOofV2Vɯ7TRgxw_i x7AGoZ%pji*Z+7e >'} sTVx-g&OjvW3Oa+I+ǔsw; 1=Kįč[⅞?>|Rbeֹ؃kFnx'HGA其5ݤ9nz9"ߑs|_#/$Bi)WoZx<;M?V~ǏY|$r>MkKtx=[[hl-c8jcP0@8x>ă=oSŴAti5Uֵ&ZTRLȀ&1^㷆 ѵ --\I GrlnpiyW$+̼9B:㶹T֧T-56AOd x`YtEY`NxknOgmZնϟpل"J1JܻG]}ncdpˊ?64xy<[Zﳀ~~aG?|~iX&:{~¬I4fe)[ 2F ߡ+9OE{ľ5mR(v4 TH;1A種G>|l߆~%x-uMs02E5w]̤Z[Dc8*ad.%wx?EŶ׺ <ڝ R~ U|1_:5*~~|^˦SǞ_Gj^6GO;yn%hC)XvGN8|}/M[ڿĝRK]Aymqw)y +/6#<|d3|ln5 2=CNt:2X3e!9ȏ L,N|o뺯Mͩ%͔Nk%4FGm* dZᦋsnʛl|'x+o%mȴXJ[r?nhTVIpɴ)iG퉪V%ߍRPմˍY-߱y"V[yͿ&[`<}NĞ*pĦ[e#ZQ`PIPb*DI~&~^1ws_PkLȒ$4"cA_גo4{[mrǎ5+]&–0h^ɵK@p(# N >7|~<X[Z[KjsiWc[9d# -UW͍D!As|?m3xH4=*k:Ķ[Ix˽dIb*z^ty->'ILkeA@EāFr$]z5%II?QFG@Š2=h2=h2=hϿ>|U_+Mm'J6%1=lM7jo@,`n%O|2 ~6 }.OӧWlI#^ gdA wo?db6Q + |E(|Lu7<.^M+Qw9me!d@;n6}[@CG/#u> uk$OYi$M4 *9ϨVڢ(_[Nf.cQz(爬5땟>ֵv,smfmw~_fhthRkDl5ִv4z2խs [y!ѼW,RGGF ^ERJ:$K#ӑB`šKMJ^E1 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=Bum 1׈w1DOFw<'_I<7/$=?bмQz𮠹( G Gڨ63˾} o g{x ]C(^(WPz?'??Š 4Ro/x =C ?^/z#н_$Gs<3L{ĿIGB?Ί3'=g %OPz:(?Ko/x =C ?^/z#н_$Gs<3L{ĿIBMCA?ΊI?%uG4š#׹Q@(7T|Z5?^&5GjPW'jPJ˺tY$mE[JFcU>Vu&xʼnoiX:t<<%m'`Us "V]ah+sg}c:ou "0o~ڏg}0?[֦,|Wx5͆nZHΪ \2#D$~' _AԼ3\XN%I{.I(YrIJ+JHCrX<5L%Y:/iMۥ>x((((_|eσ/|/վ!Cwsa',Uc>Cq IH2MAiQUjz5ޣ { ^yq[ĊY $ʿyWWt2]SDme=FE|!?/ ]{+;-!Xx[ܚb1ң{M就aA%rN߻((oڋ ?G/louQ4أQ#,$69zzM٥~ x&P5;Ɋ4IʚH[r&# x#APEPEx7 3­gKD!PVhIv4d>'MfF>@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@|F|"~4ܞӼb$O)5[nA9< xN?Z?#jon|u{~!ItHC,8 g¬چJ0\sy̿0 ?LxG!(>?? d4m||Q=— i 3#tmjS$0z~迏|G(T6DK` v{[NaFU}@Uh@"^7<"GVW.5.bƯ#O]'{C-ԵYZUš;H_>R(v$g?m |Ȝ(A1VF*MvKI~/+Oz_њ[9]b ."8eICJ둕kZ^O5D LVSn|f kZe6E*O?o*_>#~ΚGoZ񭯆Ė76o-:-.$g-Ai_rw#{i-|(ON'KyV_І8K9iKb+?oEh+ msY2V/.ty::[y8ZdmuV8?#O¿TXXx#[,k :K2M).& Lr)ݳ{|%i2ѿ'#<7<=ܶIul\ȿj9 $o3}r?_ *?kKlh _ x^4I3ŧvon xLs]s{(tinnt{4ͼUܮ|9@Ko9C]lg(+_m.k %3_ 9v|$ܥ'0F{:">xGǚ{=J׌鬧[{~i$"R|vOu- ?C:'rڴ1LVXac?13 |h7|d|Q"t[ JKk L6-۷2fЯ#S,x~8~ fi|duv),]Oy ]??dOռQ'}kˋƚ4zCTJoO.{҇da7b>OYMқ;x̐]$WO$]] 8|7'{㏈?+|KѱԅQtqlEc/[!ŽW'ÿ5#ĺvBg@xuAs" dl(Fo)/­Ocßw\CBf-IYLEp<n h>'a(KX(?o? k K?VtJ#I˨WHGGF "(GOW$_KyqH?Xt<>)վ>f[ iU(-sa`4${sğ׿5mkIԯ/ռҵkQkz5xW:U0 cdDi?_?^h}\4o+oټϳ}|ϛgUu c*m%z{=UC+'N%i9{)h/▯~ cHWq^$o-ZhFnP<S ?Úؤ,-CDF&r)#_ڟsB ?bښ:Ɨپ-b[y$-#Rbt` 71]ᮩĿ M}/!U% 9=zmYQw=+x FCRg$I;]X9bO]4SxB[nhHnodPH%IQ8"wG-76~utk-Ӊn "2 ٟPѩةO}^y-]((,nG?*#cƽ:Ox7͖XN0c$ _rmŒymyHث Ewx5YeXw!pnF9|Rd*Oc1~}Kƿ_#_S/¼]y -?/t7Y_:;C 0bH#mB'\WQxJӥsΗ{-IRID=d6 D3Ff څݰ#-椅# G3 *߄4sAfkffac# +.|K |,X*T:, LWgbqPQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW B={xN?Z?#j.9?_kD%~|.9?_kD%~/? ]/7#vnTXZ6q)tEqjnU@uE~_ [LwϏ(it|+ɻq@NH")Tcjӟhg`׼+_i>[W[w*76)s pE2߱b"dž5 ܏GQMm:fY _L~QU0e*[GI{\s_'Zً|m𦮱i:/%Owm[" 4)kH*TNj |L fڃᶵr|Լ)oqk.kn{f=Klߵ&yg|S/+i{]m9}_ +ֱQx=sjxGĚk׍g[x)m,j03>: |!ŸxKgYiUzv ^Mg\C;#=-χ_J ࣟ| X3i"t0k7QyS:!)ݹ0 }EVt[? m-,,bX-XF07Mj ^p'*2Oֽ > ._]l4M6>XdE | ~xkԥ?9cצ@Oɥ|g<JA-ER}X??co᷏omCq? jĀ*NTd^Eq࿃r|9w=O Yhhord7$A S4fs3NY/j4|4sczGyEyb/ 'o|!_BOxV e.Dcz GN :g|@g|ѼUcumfzmoq|H&I;ֽ;g@o~ּU}t/u: 24,N@gnw/Ix w+xnZ-XB-: ۲ҊӍM$tauʅG՝WOt|]5/<{wvl3p"Ukρ|[x7“I2i6wD1MD Aʅ\c*ri3i(Ԭ.F٭Yu#%<7F7 2.hLH"ٷxWa޺(LyC<yvؙ3g'I4k $qAUbQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@xN?Z?#j׾W B=z_Seц.~ lBW7Seц.~ lBPQ@sWs^Vmppt72*ʩ* y5Q@DŽ x3>.|A_cE׵Wg 4ȁٛ O,OS]=PEPEPEPEPEPEPE?tZ?٫Ac<7~?hѨ)9€>ESGsK .?Gή| |~^g1>_| O=/(+_JhiG%?w4)9€>ESGsK ;{_Q O=/(+_JhiG%?w4>=3gH}B4`2/ﻻ{{Y|)eH|BO"8[}q@u/%?w4;{_PTWȿJhi@]Q_"SGsK ?)9}uE| O=/(/%?w4;{_PTWȿJhi@]Q_"SGsK ?)9}uE| O=/(]Jh]c_3|{wӊs;{_PTWȿJhi@]Q_"SGsK ?)9}uE| O=/(/%?w4;{_PTWȿJhi@]Q_"SGsK ?)9}uE|ğg1:C-٧s|ϸ7}wNk~;xN/F~q?ߓos먯)9€>ESGsK ;{_W_#_{[JܻM_uK? j3[G]Ci,'C?=T3e[ύɤ^iDJR%'nYWq_%.4k*XK/[5wd.[žUX+ABq)]?h?[Xiv6V-y=)JܼfX ~~}(_x3S{"1qepXu^I ի;J}bѼ7β;L}Oqc] `?&}ӋDD Kx[xb9.mzjzMoam\ H!ӭ亝FY z. oWwu}g-*,mu;SRqYEpҬ?+&m19 ȵk4_f{Q+ |8S9;׹??3RӭWXZ|l =Hrf.b;`kg_i*:ZZ[]9 o"TX H 3Ԧ֏]KmLMF68vwK$F_ߧ?Eҵ"XO2k#{WZ0ۀ?zzOG4j!5nncHpy{3Hޮ$k'x:>u f-F)}F Ǖ"Si;{n~2 7Юu ?OӴFi,oY.!6ܕsVĻ[+_ckM{?^CҵȒKWn#bXga0r=nkSU VT罎9np%xwV+^-cop Wa xnCZ7t;PNDa93av׏x+߈|A5}OR:#[iVۋٴ׊k9$X"o-KõAP1XwWAԵkcSi!dR.¢DVJwoDg-WGYNCF5x@S!^{g[[2o+[y>vQֽܑ ? F w\ZƇˈ$I+*FFI,_;Nu-2E^I+W0ۭ{w) A [|AѼWW7}mՎ4Eso+&RdG1+0$qjA~'xhɦXV[[4FK+cKDppMEݯ]-^5k WZ%$jѡlc#9=)9aX[EXAv/{ܻ D[q8e8B=k[*x\VE펗^+$1CXc@R|/Ou>լJp|fِ#$nl__t+-ߧc6&Ӗ3t]1nyӚ~ >/ol):ޚ.ᴻi-$bERJ9 !?^M#Ctӯ-0(yeMUP?[di/ws$Z"6[ 51.~g\MP*1-~ƅK'A9l j4\xozfjl$YD;Jޭ~ZVcAEּKeI5BȎ!ɷ .Ց[~W+uB 3Փĺtdw&M^yuʎFCPƚ7Ze𮭦jmnҋK3Wh_g *ڎ+u1nl~OJ9#k;|'[oE{cc Y;~w-,r@'$M(w~ ?M+JvlqA#G+27X $sL-ou-E϶[+_~td|W'[4[{h>&ԵᵻK1IQ.`@>^kEM5q)m܍D;N m֗-.tIhnP"W<O8v1{Hk?R;$$R,aPzW75zm+\&`u٘ 5ԥz+4W=x?`it{ ~T[ V`[^O@%vbCpזm/drZ^oydḦ_h&t mF *IRa_M?巺uݽ !R?}<UuO'2V E? As 1Qq(5 G[E[^Y}M`ӧx`C.-Iێsk~nߏm|ɞߤ*'_~!X-e$b6H8Lʠdry s^*'|w×PY7ڕ^>eUR F)FH'zu0o?xsL&M6nqtuVɹ냚_/"kRë1KB-P ě'nsr*w~*fm3ǶfpOyo"o1Z8ʪmlY5wukM%%MBm1!|V70D .B}8, "{]u=ZiV cc}mqqq\'F8ӑQFK>6_xBӿ}گK#ּ?{G.펱m$H\*5rSq 31>l^a/ᇈxA9[گ<%a̫_N-1?nVX-UAVK7M]AtA_zL:O5y9XG v>S++m#Ey ZI n䓖@u>皟ږXjNk[uWx#ob9_$غu{_ ' n+g1'_tї2__M?h >ԼQx]WPN!X\lrGt:-͖kEY\^GY8Z3< ySӴQ؏Ggy Սαwd\NhyA1`I=[-/4GOӴ?P]FWIkY,h[N1N/~O=Ǭ$zt/{o@ʻ,rGhI2+]Fe- YC,Dgee!zAsB5 {OכLӼ/X6Y|[³@kweY]K13\Fx^i^0q(g*TDx넛jv^r~W/?owؠCɾrf~ OƏ ڞ_im澣 N7o^zW~͞'c:x^^xNkIcf%Ty*v/wH> !5?oZ5֌֖wDyP E*@)ϗ}#k[? X<ׇ5`{dmmU܍w)W|ǁ =Uxelx1#$FT j +ZR|\-_?ópZݵR.5Ÿ79~ h6^+Aִ˔qԫr+c\o ҇YH\ )$ߵ[ kII{/ i˥6vWRI+e 4y!ds]? i'k_#Ծ"|`>j^mahDI#ed;RWa=NZ C,3 9P! ^Z|Kuh-axY/4 T>drYm29TrYAAҩu6ޫEQEQEQEQEQEQEQE~98hdЏq^^㓏(OZ o5OF%$c? _ o5OF%$c? @QEQEQEQEQEQEQEQEQEO[-V/3᳷=P?/=/BAEsB/=/tPv}(@3^ (^A!렢9A!^ (^A!렢9A!^ (^A!렢0<[N-cpsZoٿ63z~bף_z_z(_z_z?׮% v '@ ?A!^ (^A!렢9A!^ (^A!렢9A!^ (^A!렢#춱EZ1 V Q@  O_ ] O_ G Q@  O_ ] O_ G Q@  O_ ] O_ G Q@v -Rw89MVNH7ߏ=? EsB/=/tP?/=/BAEsBՍ/Ÿٗ3rzآ ( ( ( ( ( ( ( ( ?@2Gկ| C'{-Z7| ~\1脯o7| ~\1脠z( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( +?ź߇-_ZU}ek$m>"+ o;J@Pdt@Hda5}sW}#5miqk- dv263Xoww]ۅStRvi|QNEimW~ g_~ ׍Ml-F-f\nRyuD?;qvF#*6~!_k:_x?:,0j͵o3:ı+9v@dFVvjW^z=*RIi}-~,ceFx9 qr|i\!1>j.l WdÎW|3?J^+o--. ӷMwqjNq&t° 5oz{5𕗎5X~e{x[|VW\G!R0Ӎ~(f($"\\^Bn.%RUpb դO[,zV㌎F\I:Mj>9cB|Ot)iLƿt>2iVk~{Zi?zobsir+(Ng9 ?56ƶZ?>%i vZ蚵v,5h]u&&)dF6c. ?h֚oS:}]խn& 73mV;A=pz2DŽmtKYM" oT]kHg7>R[ږ3]˶uUQrD)oWx]=mŵ0h:R7tvSn1%iXoV)r_ ӴnL ]nԺ[+ ;QEhhc.Ǘ|qmǾU?i=מ o 8n5&GFL}'JBٟoj.l Wd[>K9 Zji7%qm})AYXD;rhz_k[񟋭u BHH+KJYR{[tfib H"PIM+]wc*R K[H/dm4)dԮd8̞cD|(?+A)N.߷s7&]wiEUQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@xN?Z?#j׾W B=z_Seц.~ lBW7Seц.~ lBPQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@?ů<1x#^"1xICoXgb[q,#i">o>+"~zF[ GVNo ՚}.IcK#VK0#w#;I&8/-˭WUI%HzY+]K6 !m>6Zo32OuM-)m3rY@"hQM| <5i'Q4T.r9H(#VzELF<󅖽U澗ؒ[h>2?$/7[ i9ϥN[Ŷ]3F~lJ~~)?|1ND[I=m\Z#AyW mZoU*RgÆQh%~gM8.k+SQ_.|'xԾ%x7Pxok\q>>I\^ZO{  uM#Q^i_os6nzuܫ5\ʐ!HITN#'%kі,tIiջ[zwWhg;eώ/$҈LJDJbkYbObTz ~'kj#ӼS?;ۉfRB9?+cFԵ^3/;OGXDwֺzvVg6+JFL,dST%ݤiRl4tR)&{sZmVa-gſ5W𦓥Vo*|?)+%@kib] G*H1Cχ>&MNƺ/oPRc?hy 'yԛ_hw]3't kZ7m4+_hWFdkWJut }/`g'Əi4mBq{lGf'KxEoW:W5>" ođoيMlv1)iY"qxC>'hֺDO[#MBZƥH:R SHypTǴ :QQWf峏-Qm]KѦA$c}'g'ir&I4S~Q?ݦaqV%ŅU!+ѕ E|'&/Wu~}QxR-nV B).m.;g19G( Y}[%nkD֗Ě=CM5n>)ͱKc:ʕh +&~%~Z>)_~/4.58ւ[m?L&no2A! i-%M81JX q^mQjW挬]xG>~5߂lx;.=R^.jv7=<d"!ډ_;}|Z3o4 Ss;$"<wS6`5ς_Bwۏ&M5t {1lc\I\S_~Z5__xc׊i[h̡0Lg~־'Sosþ$$^EbPi-᷺xb#6 >%/ `+(}[,a4Rj A=n--]Oڏψ>>xo77*|-xFCf>d_Mi7K 1$XpbKaڮ6W  ImKΝ th1\n# /`٧DXuw:3iN#O[cJHsṣm~]>>-}h> l.Ji%{xӍv6ynڳ8_3'?ş?}7~J<;{jkw]*Kbn%3J#IbF򇲤Z}.f|}jK7s%d%h% +/vZ͸AT]CxsAK;M7TDMRԒJX"Sa +v^ZkBX`fVVTQ/,RBwvVuiOP6)oW/{N{4OaO_ƻY<i7Zl^[gi< hKTϏF|cj du mNu[ɭl;ko礪`BĮ3~{|__\sCŶog,v׺kiИb+Y#ʡX3s:~ϣ˨y67SXxm"W)5{|^߃S^1o'şvwt0XRI 7ʫhc:BTJnT7F[3{EhMJ'7{^Sm鬷jBL_Z~;Y _U<]jqX ,^鋲Ȍj|_>"wn|)ܛlЄI'Ye?wZee{>?ZWƟ%+߇SB7%O`ncy)IۇG/ [/tkB_MzJgv[{Hd3(K:E-c墼SuB,R.7RIjW z5IuV\UhRL7>j\xL] |#|=u:l%jz^\m#M vl s4C"*)isF?,RUa]R+O*NmpT7  IQJR]֊vcxJfX.d[onzU>|Q[KqyzźiW.=#[e*#|rJl/i_ <;ix:s sI.Kps _48ߙ6/[^Ik\DcA"vuz˒/ƿc['LP>m<8#I#oo5MuUQ_?>}suikl4+Mkπ=žp G,m#C?jo*M+_ j6=ϕ`C4n-呼6B\}/_x=5ExAk{]+>Ě{:a~ #z[T",(fo/t/%:7 3D$@I3RW_ᘮo_ݢ)((((((((((+rqKV'P- ?hj/5sKHDŽ gQj/5sKHDŽ g?]袊(((((((((((]mxKm+[V>+ڥwW6)."Al*ëϋa=K>wywb/3yl̢`<hJ5kyZ:ucZSnIUko~z$kx%.L>Gt%s[$Kq",, 775SN\zn8fi(֒m{w{ww~o'gOTɣc#_kAGy]ݞkq4Kukm*kMZ%.x&Hgıs ̠Uwb)K${;1~>?`QZ𼚷krou=OVS?y˛h܁$|^| x}c7Km&@/ $TY-OEƄQH+7J rhKDKEۡKRRUetO+)=I7wOƿ.xJ:/X\]-3?6;ᏃtNH֯JW.\iB乺VfU`0(6װV✹׿^0b)Ƥo{&}5}H?c!ǾEMbRdRH><`4`Y6P'mk=2;+X!( `m1=*z)(E_M-]51Uj4&mE?1^7C +GkW5? i=[81m$xl?'>#Ҥ5RZXw:]JXfk#L:FhYo:%"2hVtesh7_l#xkz r.?HVA=l3gZ_W4R:4K/ XyXx _{^읗KN]8k[Jm> S//⏂>OG|Xj^!! ƙ^-u̕~wu,GW 7!ңSQWޜc~h$Sm$R޶͞7QWZ{}zmOV[^}#ClG 4ҲČ4qMq7o~$|IS \izZj'5=QmJolcʞw24aۙ&ڜw^,uO=s *խ;;O3} WJ)Y'YGln-|y BR=551D Xi}(6gyK\kw#^Y?5M3GşxA]!?$ZZc4JH8т0U0>[򫾞?RԗA<>:/kO/ɮfe62RڛJ3x_iv[MJ/*6~xv?ٖ㩼Kg v8?<#l\ =JQ"MzukhhW#9E:] 5}ۺ/kϫ|_{ˋ(ѧRbmج"K䑑f㞐oNtOD˃%o=uUM;EwሩEU)GkG65׾דK= Wj^g]7ڞal`-E%4NJƊIk韲t{m;Bj^+ ]OP_.9?o>F/MO9:>*CBFwE++_ً'ϋ7TC0>.ҵPϑm:CȺLu*.HEA붉߯i[ ^0PI[V%'yg ./Ƽ0 PgO43D𖟢iGt %FV Mcox{dW >J%^g* eps]?{pZlp><oPmNk+ou{e{9|oM30( l\|Է>-Z]>|̼m7Ex?ڸS?Wgh >7EڸS?Wgh >7EڸS?Wgh >7EڸS?Wgh >7EڸS?Wgh >7EڸS?Wgh >7EڸS?Wgh >7EڸS?Wgh >7^-rZG< Z#%Rr!un kV miq5&£> > _}>˥3mSž$MV-'K=݅,;okb[֖3LLS rjYr\K~6]s 7.?g)f\~*S|.~|Z𶳦ݍ>D(ԌGrs>O4HXL )UY ;Ak}OS7GK.UA?q?O5__ ˒~O<5O>"F1@U}3~LjCI I.x)6տɿњF`oGUA?q?O5wox_ ׍|/3Ooki2yڅI1$ICb7mt&K4ڠ1ucJzc}w[?.?g)f\~*S|.iLU?N΍ xZvr|V֣cOL𶻫A_xV-kʻo.>bA?:{ߚR0R{ > _}l/ i_n~}ėZͥmB,"Ȋ$]cgоj&Xu[/Lwٹ~UϮO8\y__[(;i > _}~CWPO_Uu]kZyi̷CR\`m sp#x %5wTV6oy K|?z 8涝\oqP3ݯϥq?O4WgkE< w:NW_:_i@< 'zq~۾{O @5t{]FKObmodcԺ|D[NR> > _}tvV^,5oO Yťi%fe>opI_C_YkzUaZ}H܁ *rLY"쭯}c')Mk _}3?3\S?Wgh >7EڸS?Wgh >7EڸS?Wgh >7EڸS?Wgh >7EڸS?Wgh >7EڸS?Wgh >7EڸS?Wgh >7EڸS?Wgh >7EڸS?xK׉o|a[=֣m2+ @< })*'O{:IUrO+,ELM JD}NI^"RWwb(h((((('P- ?k+rqKV=/q_2_?xG!+q_2_?xG!(ފ((((((((;,wI]jξCOgq)~EW8QEQEQEQEQEQEQE_qIx7Ft :7f^$峠 <>\`Bu%JJqzJUeFJp|_<3|UmCľa4]V? Z#f vX H9V?O!>=oai뫯E͒(h,]bwttWTsVKGz/*zz/?/7Kkl> ^nx>n>6&He [6h'>76d^1wL@ \ѡMIZ*iR{Key-w!NneExgbJߊwYzm?wwݷ81MoR_Aru{u: z'Qmt;yM܂F{Eg,MYEe[nKO8+ow6Vq ^c̛& b3 '[F1Y/t:~|?spVqm~ ͚hb9^^^Hsſqv}vDyFdeb#!K9`bx}rZKCei1^lrW 7E3EE%)n[}©V.}Kyy#|O$Yx?j=m*K<,|R9' `W ?Kפ|/smǤ-iMȫ)30G \e}1ED1XK[eߓh#t]KO9P(>c|+1f۟Lx?e+(v&|I}hȞMm,q21,3S'O繝5w^i'+)VɚQ< 㛝 Uyiu ~ IQVeɀz+?ֵY/wn:uz|LF #߭MEʕ (Q@Q@Q@Q@Q@Q@Q@^ ҈m'AV?|#߇/eO!_kß\=/?(x(((((+rqKV'P- ?hj/5sKHDŽ gQj/5sKHDŽ g?]袊(((((((wI]jξ,8|QE|EPEPEPEPEPEPEPEPEPLKKy%`ĥُEd}Ajmť&EVNq>b 77Y]m}6Kp˼G歙]w{nx,@~ =|_kgxv 4k,mFr :z g͗+z_| {"2A?va1'x't^)fƺY Xc"!ySqp+۝< 릶wkݵOW[`4ٽwrmyt=sgMXGmk&mx[{~g)[k]" mNŴ7p[wP#W#۟kRE;o k:vbQ9 c` #g-!:<;XYel1KahDzkH9mUR}9XlZnfI]_KGNdI'~c6?|3>16,P7)~ΊYT>0\luL{%$ʊjJIW>:N-Tv7m<-wcekmjhpW̿ b_||n,4ͤ1YC9'o[5;%$ZǝF$L0~h>|z~kӖ'ǒ% P6'cqcW`E|/cXuVF,91C~U'sR~ wzwakA*$M8ZQ~M-'OM?dwoױ߶Ժ6exkBD[zb?;8C_{=CYxwQ}: <}7q3CW|:>9*'ßzU~8>&mBIYpaA4SqRț^OtJR~jY;Uxֶ:fm<6yFgrӚ8YWee9 B | 7.Z𮿣xE4z֩X}tn[& pa- <- R5 ЭmCݣVo9y13\hT*sw9q41te}5o#+ ( ( ( ( ( ( ( ( ( (4#߇/eO!_$+G^J#[$Bׇ?ݥ'#{_,QEQEQEQEQEQEW B={xN?Z?#j.9?_kD%~|.9?_kD%~EQEQEQEQEQEQEQEywj̱qT.n\*+Cxۏ wYM6:faqyws+m»*$W?}~~&c|Agk;yc\]i9Xk;nH] W+-Jn+ٵ~}+j]ͦiV4IN p(Osux+şxOzօ['ԦђD6G}w4s4jjy4z߯d1r ,fW(oлqzP4v-U͗m5o|-oxYt#z%`ak XgDc('Gß|)G:t xKNtv[[I|0J"Yc2 Waok>{46bٻ?Tk† kǨ On?2W|_J~,xt H]r{X-n簛XTKEDx?'Ÿ?u+; QӠKwѯ~\ui*dYGl%dNU6wok[[:Yae)Ahٽ?̵WM_w7?]_=G(oлqz5*&2[_l|G(m;mfb@E7(ĒHSx#kτ_t}wEԼYiZڎַw1$M@EKf#7ps _]sr˿To[m伏+zw~} Ɵ.e7?]_=PU0U]GBӴi-oL.S5:[ E\A_|0oS~ ݎ{k*5M=,u(.+hL#g%޾MJ_^g ;nS]W7?]_=G(oлqz+<;OXԦS7xVZ%_뺖gn5k[(;$H: v_ol ~oZE5wе.{;۵uh.Wy%]]6M[~C׺_k Ɵ.e7?]_=[?OOZx{:ީz. 坱d[xarr>c1<=U׍~KmwV?混Vigז{kQuwqE 2C]7Mam{>{` *vig Ɵ.e7?]_=^6W=>}&OU$2Id%$a`Zw^d %t| Ɵ.e7?]_=_RQK vy(oлqzP4v-}IEN'g-† kǨ On?2WԔQvy(oлqzP4v-}IEN'g-† kǨ On?2WԔQvy(oлqzP4v-}IEN'g-† kǨ On?2WԔQvy(oлqzP4v-}IEN'g-† kǨ On?2WԔQvy(oлqzP4v-}IEN'g-† kǨ On?2WԔQvy(oлqzP4v-}IEN'g-† kǨ On?2WԔQvy(oлqzP4v-}IEN'g-† kǨ On?2WԔQvy(oлqzP4v-}IEN'g-† kǨ On?2WԔQvy(oлqzP4v-}IEN'g-† kǨ On?2WԔQvy(oлqzP4v-}IEN'g-† kǨ On?2WԔQvy_54v"$pp5f oU*'a0tPpz\%<){(:B((((('P- ?k+rqKV=/q_2_?xG!+q_2_?xG!(ފ(((((((( ӿ 5?m4iiӧX.&vMmYcll0&~ k g<Zz}" 4}QhLC}cq;]xQ|ABxO/. Fa"hi^{s%i4Sy36|,ִS,ZhZ+/»Vg9 |$O |I|Q5֍eC^My\AMA8I` @TihOw%Dc_ 隞o}_kMA)QO۲e ^_D]5t GQ`GQNc#Db7xF(Yͮj? F,_o'Ã6/k}j$l?j7BcYH;IhWG| >DiAm^,=s BaBKu_4d޷V{RW]$)k|kgn|Kk>G5rUlEִ>eX/c\^ 4|!^x[S?o|1/-t9 }No/ŭW>uq3*ȹWPέaN|#c~%\߀#Gԩkkk٤Dkvy#c檴f//aU1u4 iGÞ˫SPn$KZ-ċ׳}UD՝VI-WWq`hZu޻ Oq _T1MFfUd[?L}^& 7ƿ5ht߈uMEӮ-$ G+7kί?_O_g]W>=4k?sRiIu$ۓ}wvFzwfg';+oxkúD7g?/md) ]%㻴trlP2 ;ڗ<iz叉-E.<]Īaa؟n^5]$xiٟ._:h53ĞdԴK[%hfY#e(䃉~!|]-8~ɿ |kᏄ|G,#J4.5J.Cm,q+[xWƞ q:sJVVbM"'C>;"ø~&5kc>߂4xh ó]oy |0]I˽nfq,W+mo[]dQ_6:GM>GX%KۨM>iHaH@K&ʻz2'>tj֠{tm|ӳ_'\'2'>k3Oe?N| O7G2'>?ᖾ9'-?_ n;+ZcD t-|1sOZk ρ?AiOe?N| O7G2'>?ᖾ9'-?_ n;+ZcD t-|1sOZk ρ?AiOe?N| O7G2'>?ᖾ9'-?_ n;+ZcD t-|1sOZk ρ?AiOe?N| O7G2'>?ᖾ9'-?_ n;+ZcD t-|1sOZk ρ?AiOe?N| O7X:W |4<5 Ú}gٺ|V~˽'n-Fnlg@EPEPU[$BU}'AV? QEQEQEQEQEQE~98hdЏq^^㓏(OZ o5OF%$c? _ o5OF%$c? @QEQEQEQEQEQEQEQEWB)?U/aR4QEW˟akhyk G_s2xOuݝ]q^cZ\ _( U)*~s/_CҽbIɧNԚMYeSxTxi.C7S6_}G?>O$3f xMwVMaOԴصsVm {{[GVKoű6MY1zuKgw{}ΥŞBc?4xsNj[Z{k=Ι2Jԣ]ɰX~yM-Y:Mּo⛻?xTfpпOxoKcL/}G_ž/zU޽mR}9m[{XvJWi,ZG׾C0G]uūxC7Em_ÍX#Hij:2[N[r[rS*g&_ݹz[ko~]~-?2owxȯ94 oR-մzƾBPR)5+@PU"} EZZ1J$I$I/38ǖmXQE ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ]Jdv$׺F]k E|EZOƟmO~X5ݪyU=uI٫ٮ1=~\'<_bzwux{Ns+WTEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW 9د^]p!EQEU}'AV?_IUrO(Q@Q@Q@Q@Q@Q@xN?Z?#j׾W B=z_Seц.~ lBW7Seц.~ lBPQ@Q@Q@Q@Q@Q@Q@Q@?Ob!X딟*QEx{Ns+WWw\'<_bzwtQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQExNs+Ww\'4 oO x⇍?O(6m-@ ac m-Uy+5~@ktmր'R]ou𮵬H<]N=7Y'm!kP 85]/㿊 ~"~)h4%5+>mPu-iRG$cT B"Gn}P嶽9W-|E~m_ ѼS q~5.y %Kff<Бܴhhй]_  _P7,M[zMLJmuWo~ߴ`'ku'ӛ7nws+/oCv<EQo|"VtoKo_Tfid|ݫ dX'ƟOF;\tb.&3+B(]9(s{/].).Vgo=ڊ%Us Eڷ~)g񗃴}kY5 <-ȷ1M^<:tV- o?d#ei|E P<;=֚ϣ^隍ޜo $_{Uy-x~S~ 뚙u'S-#SWR__*<$?Umf?_>%ZUI:o%ӛkٵ+%ӡ2'۞a$.Nvd;\WJޭ~Q_?G5٧D縲_>Fhf*$VGF A5_ xSľ.4 ~<-acuit8gTOrݙl~d|ص*vIJ/{`EJ:>墾Z/о._lޕ_xC1jWUޫuorڑqgVӣI\*'GqGEx/֧j-?˷/A}{`w!$éD4')ʝVq\uӹ 4E|z~Q_:(cwҵx[%xvV<]M Y[Iw kSM oXͬv#"~ V( ym/Å8]:weE~p]~(|@3Ce|7gĺOaKcGq ٢*%ܐy\<D(o/(N MhYj%iE6u'[qk4Tٞ;E1*n FZ6~/2N ]?KvxKC^ VnZ$e@ &vH(pFFG5~((((((((((((((((? IXO!@((((((+rqKV'P- ?hj/5sKHDŽ gQj/5sKHDŽ g?]袊(((((((/aR4^_ \iV(((~6gN'-F& qm5Ԧ0vd /aZ f[%e1E.EИ] WοM>4kV7fjE$tD-dWuXJ˺!! $ntφ=Os-ZD#FF́(UQ@UU>4~|+Dx#=-V-?z=kꬫ*p 3ɬcP[6~x *ш:1+e@# yQc=h^櫪xZanvu=:s%I;1{O1x8YC_Ѯ'K{7QZ󄳻v]MI H5r}{d&vENq[qZj˿>+|/|7펗{[iv-";GK$(O4$"d-uCgy-n)1#*1k|N}SK;\[xKӣdZVgLiД]ԑT23_ 57έxŶ <{ ZhEQa? C>w֋KZGc%_SzW1tF-K{[(#PQ *T kY?>0c'ľ־x^Zq{jwr閻 Ee \~?Chubּc [Kz]hf:^!%;2'cSmu请~֕gfyw捯uKgIgǟo᮱ ^&7krL^,MI8#5x7z?ß 'Mд-,4:-m,`E C `$h@ _7_~>/X#տ8u~tg1y vU[ -Y*iO_ P&LxJkj fG[;V_kaRU[t*}g艋U5|՞_ioX~|=? f4+[)n(Ԗڙ 9so\c+_Lŗ? k5/ZhvI1,|>Ztc˿_ë?WRfoRQȲh:UZ)2Gq+8Y.WdkW/7[ xK|uw!}B5߰]ͳHFa4f&,v_ϑ);;(->I=5m|P>u X ,rHɻ<38Uzw 柡i^kgwci(_3A( 1L84ox[ž׼ \| ̺/3=ԶZWVxg&h،]o |[eko>hX$\`3<חmj- nld mE;Z7g)9O1[焇 ,2~߷`oi?z{喩E*CjkbV+:FNXMNu P_,Vz}!~ʿ >-x:O>.W\hlI#- l6E#1yڊޮ κ.ĚE R+ɿ)G{}ȾLxaqX K@zh#>_GuV1A'/(|=Oߖ"% ]|EWZ$:yj.-pCv[٧~\/4j]z6_ۥ>W.oۓxᧅWxbh`5mRM:Kmz`&W ‚],)sÞ8ϧxF_;\ 3w}hwΖo~e[2VB"ggI[?h?2gjYʿ6LIK%aTB.Jtڷ-j[Ms)Hfѣ,ln_cF~ө ( ( ( ( ( ( ( ( ( ( ( ( *'b? IX(((((( C'{-Z?@2GՠK\sy̿0/#-JF\sy̿0/#-Jw((((((((IҬUy+rX((KnbX04°fEpgg>j+~xxL[IQ{l21hܨw`o2?^ kgGּ+%./=}gs%,!{}u'*)ss\ҿ~g}'gum[6em1'mC.Jx9| dꗒYs$jHbyUF@+ǼW|wiy~/`:>m ~ i0KrZj-HHnJC*Vs*wwo>T#o_r< yj9m: YXmy+d.iʈFW~şODY_xW_QlBIa{_4~Qqq ]QJ'n1K`vqm暷NV^lK^7뛩Ikw|XZq:{[a=FJOy;Y;<u>(@Wеyu[e&è[gImYUyBBR.w}&7q ~_ %+X^OÞ}|4>KdC<6k>IpR r?cZrlO޽Wx^Px?[3nwͿg?d[?x⟉Fu_ivUn嵖ݿ-'X?}oJ7 }^EDC/cYOIKܶqZI;ߥI}U| S?~:x>6zmfG$Vޛ)H:3yRT ?O_㖻zӵWִj`δC}̼q\FЇ|Gyh'yoۍ<sjznZ^^ۭo0p;ʱaY@=+oTEWs^nڗZcNo{hEgm_ᾡ ,5T_]OF$R\ƲG"@A}ؾ%1ž#<[{,ڌZ̾cxV#i-CX@䷘rAVX.mI^xd"1GBAᕕ"k:Z{ifӭeJ7rpk'/4ɹs]_ŷG CPҾ<4 IhWFM*X嵛sY5![mn+Gwhu-^?:E֠Ir3*fXٍ$oB*^IuY-F DPD4Pp2#"qZt^}Ok~~o߲XVVzn뗚mh(ɥYE+ﺙyRI[p//-kǺďEO>5'tSO>59-Z ~q}O(]i#myգ7zGF?)))n>oOM61/m w{vl6,ֿbsXboo|6: }[T(Ӡ8aoҷ6V=SRԭ}>{^XYG (31@O%@SIMsH!fk DD Q N3iii?*Sw}z|_ H?VSInFM@˻t2q{x#/ USkt eD*sGr稫; 5[nɢeX:J28 #jZ~o+(((((((((((? IXO!@((((((+|j!v GMU'٤x/ˇYe@|i:Y]hC (^Ip9bIɯ-}Sן O>0@HAHCIn%巴{NO"-3ZJЙe%Ro>O wVt@Q@Q@Q@Q@Q@Q@Q@Q@?Ob!X딟*QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE_IUrO*Wm\ EPEPEPEPEPEP_6Ԛd8ΏUQ~ť7aiW"S 8|f;:.n k誄^t"5ʵRnPj2{tQEQEQEQEQEQEQEQECqiʎ * qOPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w4}OPI?w5-#Q(((((((35韴;od&F < ;q€I<^^WR-oGaȹ{p?f=|,|k$_G?Gú|-qxr >#$ҼaC*J < /oβ<5x ^}F %5}m];\1\k?<;(i+ 5!b4*Iyoko1iF}b1} {4xwPT ?Ux94|MʜA_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2s|MƁ_i8W?[hoxO*[ÿ2"ygĴd%aPTvS@ax/oZGлKoa ФL+| wB/-Z^;7@JF+tY!e|Mggy؋{$+*4`2ze\k/'0Y:X)dFVE@uGebĴV]O_Ġe?߯ Ew']@sEaPNc`A9˂_ LcgCu}A9˂DV%;. |3 3?OiW|Q}4V%;. Xx'X?4?+(>?~1]G ?WPXx'X?EaPNc`??+Ew']@sEaPNc`A9˂_ LcgCu}A9˂DV%;. |3 3?OiW|Q}4V%;. Xx'X?4?+(>?~1]G ?WPXx'X?EaPNc`??+Ew']@sEaPNc`A9˂_ LcgCu}A9˂DV%;. |3 3?OiW|Q}4V%;. Xx'X?4?+(>?~1]G ?WPXx'X?EaPNc`??+Ew']@sEaPNc`A9˂_ LcgCu}A9˂DV%;. |3 3?OiW|Q}4V%;. Xx'X?4?+(>?~1]G ?WPXx'X?EaPNc`??+Ew']@sEaPNc`A9˂_ LcgCu}A9˂DV%;. |3 3?OiW|Q}4V%;. Xx'X?4?+(>?~1]G ?WPXx'X?EaPNc`??+Ew']@sEaPNc`A9˂_ LcgCu}A9˂DV%;. |3 3?OiW|Q}4V%;. Xx'X?4?+(>?~1]G ?WPXx'X?EaPNc`??+Ew']@sEaPNc`A9˂_ LcgCu}A9˂DV%;. |3 3?OiW|Q}4V%;. Xx'X?4?+(>?~1]G ?WPXx'X?EaPNc`??+Ew']@sEaPNc`A9˂_ LcgCu}A9˂DV%;. |3 3?OiW|Q}4V%;. Xx'X?4?+(>?~1]G ?WPXx'X?EaPNc`??+Ew']@sEaPNc`A9˂_ LcgCu}A9˂DV%;. |3 3?OiW|Q}4V%;. Xx'X?4?+(>?~1]G ?WPXx'X?EaPNc`??+Ew']@sEaPNc`A9˂_ LcgCu}A9˂DV%;. |3 3?OiW|Q}4V%;. Xx'X?4?+(>?~1]G ?WPXx'X?EaPNc`??+Ew']@nCV2<_=3h֡$m ;|KԢ;~(dF2Ӳ+_C6ޣUZ7("%fza۝cDE_iW1,2v<ƐӡBd]:}ۈB E /t [Z٦U'$NI$IM|1~#пj G[xRDs6q"*/vfyB;aPiW> 6desc,ddscmmmod(cprt-XYZ q0DeXYZ a)(XYZ #XYZ Rsf32 B&lcurvcurvcurvvcgtu ! ! > %&s "]#%Q&(@)+5,-/V02635 6}79M:;=L>@AeBDEzFH6IYJLMXNPQ]RTUTVWY9Z|[\^_+`Wa~bcdf g/hTijklno7pTqorstuwx(yIze{{|}~݀.>N^oȑҒד۔ŢfJ-ǩ`=ϯyN$дn@޸wB ּc)t7¼y6ůl)Ȧ^ˉBͮdЍBҠEԅ$dקGي.wܿd ޭSNMSc{1S ?i5yS&r:c ] ;p!AL!Y"$S%'I(*2+-./1[24(568C9:@1ABDEUFGI0JmKLN'OhPQS T[UVXY=Zm[\]_`(aJbfcdefgij4kTlrmnopqrtuv'w:xOy\zf{z|}~~pdYQG<2&ݜɝa<٣nI&{U.°rK'ص`6 ⺴c6 ݿU%ēe7ȡo> ̞i5Й] ӐBի_}0ڛPܼr(ߑEi @gHq)YCw4n,b Zk-@[v "(.<R^T !"%#5$;%C&O'Y(`)V*+,-./01233456789:;<=>?@A}BmCXDIE8F$GGHIJKLM{NjOXPCQ+RRSTUVWXgYXZ:[\\]^_`sa[b:ccdefgphRi,jjklm{nRo)ppqrsltAuuvwxryKz'{{|}~jH&߃{\<ΊgAҐ_:ǖvQ+ڛe<꠿qL%Ҧ[0۫i?ݱdB͸zO"ǽtL$®ÎnO4! %Cfҏӻ@׊T݉ +efK~ndin6WeM((!GP T93G*6DSdu6Ro>e?l/a@6s7yL 9 % v  s x , ] O^?#"2Hj'U![ !I!"#A#$%R&&'g(()*R++,-a.)./01`2333456w7Z8>9"::;<=>?@ABCDEFGHIJLMUNOPR9STVW^XZ[X\^_`bTceGfh@ikQlnvpqsXuvxiz{}}L҈{ohtܝ9F]Ű$Xx<ŘN̫UӪGڕ޻ Q8i92y $/;HWgw)D`}$JpAn2e C}8wEh  S O Z  p / c4 yY@/"%3Ie$X*i  [!!"d##$%7%&'d(&()*v+E, ,-./Z061123456y7l8_9Q:D;8<:=;>ĸ:ˆeԳG۟IQW"\  /BWoBk(^"a+psn"}< ,  o S = 3 ahx I|ko$O F !k";# #$%&q'G(-))*+,-./012345678:;<:=]>?@AC%D\EFGI7JmKLNOOPQSTOUVX+YtZ\]s^`)abdSeghikllnXoqSrtNuw[xzk{}$L߅yZ[V R򜋞B𡥣b)lEõpM羵u'ň3fqQԽeضE}ݍނߟ sX(zX5Z"desc Color LCDmluc itITfrFRBnbNOesES,fiFI>ptPTNzhTWfjaJPtnlNLdeDEkoKR enUSsvSEdaDKzhCN LCD coloricran cristaux liquides couleurFarge-LCDLCD colorVri-LCDLCD colorido_irmfvoy:Vh000 LCDKleuren-LCDFarb-LCD LCDColor LCDFrg-LCDLCD-farveskrm_ir LCDmmod*MrtextCopyright Apple Computer, Inc., 2005C      C  _" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?!~|ܾ.E^]LIGގ9*|‡z|e-lj6v7I0°ޯbcI^F,\u h߶fiNQR %eO0!H`ߒƶl]{m-ҿoϧWWiRjIGk`zKh ʪ3b[> x94BX讂4ewb)oBT:͞濠[8Viw8:ƞ1I6MY*>Z3 v7G-+OV>˦cE %6R} ,eKNV۱vW'+|WoW4P.q˜\˯yu_F,ZkYk V!i  93o/w?&e^_U1$mY$A [!xj%nۭ陸&>}Z/3{z{+Ify.D'8c3>(|8|MhZk|1O̍%]UH "[?<%:fk }7eY 1Vbc` pj5Ki} oWϴ; Kq=nom'o xK?Xi171\mT7s #?&T ,cv=τ7Þ;Ҵ|Gn#{in(ܖYCle`+ɯM_ϝusgʼn<$#%fg]۲AxwYxt/Cn&7W~V#;듛ڿlF4OoMAec$Bpy$6{_i%xw-^=}ߕ/򴞾Og=&?Ufexa9k:^ $; !oWLSh܏+sa)[~$xP~>e@Bc5ddY$vqA YKjQ]o[ҟڳu~ڗG?s>!q WOko.yF۰0bc?d$M4?zޟs$z -;[nV;mت.&/;9_RW_.?ڗELEKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKw\o7kkj6BCIܰ"(bVq[^x#U&}/òhi[jmY%?"/13`(@xGc+c>$xi>HGF;MCMӧW(ˁ!I$ >8ω<7Gmx^kwHJ9dSta ĸ>P$)mo> S׵y} x-]2V jJ[+ Р|3|,񕿞ۥq}{v 62qN*׉ax~HRy7 1^E|Uؿ hWue/vQn.5].TVQbHqҽHHHHHHHHHH eIKhC2I=ͭܲ?iXGJ3)ZI{X(Ӟ"j_1J?h KN_ǻK_ C+I .t8Fr-%~bj;Y>l+eVe"?~#4~ ƉK3 Gl|hUw^],/iW7^.RyJvꝮjwaEWAQ@Q@Q@ ƿ/ΩǢZf^jm2E,1Nۊ0NH?j?~?t/F /|KKWi.%71* WAW_Y/?^|Gm_;UV-Xmhc\9@+;p3迉_d}[ؿ>/kOxN)YOsmq>JJ?lBY6 -K۟Q _"iih캅͗|y1o]((+ROXe?C>}[RcY o>6wu8( (?~:4|m/n"fۏ7w9ێ3W~6'½CVK7۾ٿd0˿3ny((((((((((((((((((((((((((((((((((u}Oaoh.1*Y݁ C6O?L ^)|LHY[)dvrb j7mu.==ڮWҬ>MM !w"[cs&hTTFoOgE5|+xᾷxƚy+<9y[!,Ώb8ăLs?ٗ %ZG_4dYD[wi{ w2,?߳<1hvwOk@K -c$DbguKe3eg?oi oo4Ҭ4 ^\b9]6 .5U˴j^`yr$FY-9?j ikv,."ӭLn.n}(_Y<=amugƱeQ f`P/ri?/_޽+~(~0'$/ɥŮ R)$2gK҇`*aC '?Oǝ& z^(9/5x4TfG+{79e#?b7?-7Ëo?cM_< E KSڎL:0|{D- *M;/ਗ਼[xjTX/&g\u[f'rg$`Kߴ#h~Ɓ\}Oƍ1p `0*ӿWz?Ut4k/t~3~.-h(u+<5Kmkaf ^SDkɽ?)+3 ? ,oO6/7e.|ߛ'#?J5O]GŚ$:w9 j^ʖA1A_ df?e~|iX ^69+wj"#EFOwq߉)۩IOӣ/Ȳ̟tؼ!g?/>KH",!,z? ZGkK]? _ %5 nIC3 oZ7Q_/(ľ'Ҵ}KHviyK6+He%Yq)fcX7mz9|/Bn=֒P}/ˮj?kTY]w0_&$gkO@HC".\iY[pLJ]I$d5amCEԆė~=Y5/ 7NSj, x.?J_"xp յ-7?ӭcnv0rl?>kD4U-a[F1E$[L8VJ1^_kZMկr[pZH.}=T}|\0x3ķwiKG$?@9UkKX^zlr֓I>ŗi~g_Foğeׇᾖ[54N99i?'Uw-׆,M A>?Oxw⭵LJ5"xDdy"7 ,[G^?r{_Xu4z涵!'KyRUe*q( 03^=~ + ch=A|yGokn?~o:)F#m;7̧9{UiocNfZ5:6V}GV(B`ȬD~IW|k X9p yv^OjzvnȑȒ,`!X!Gg%-5F: _Iwu ݛܟ$Ai3[m<ʨu:Xՠ6hf@̌0xe A@?hwqk<)qtxט8-tgIJoo>8|Mwuaj/t{9eH"8., .C[7ތ_qxc^a/:%~k6 W·,Ř?_|_ŧ_kB 3JACiVkKwh\ڤrZ&Ͼ._U>*kfVquu>nm@cp~.ccT0D\GF g5~t!?dRQ/so'@.P!g^H6T erx3|u4Z[gIos@E|WĿ|Zկ~m+H=P j$jTe:=Mq2C@aQ_ŽEE2C@aQ_ŽEE2C@aQ_ŽEE2C@aQ_ŽEEv?|Kŭ&t|Zu80ȫHN3P4W~~7gmY}PMA%uؼB9AM,px}x7(P?}}PTWǿ2CG(P?}}PTWǿ2CG(P?}}PTWǿ2CG(P?}}PTWǿ2C^.WMeA9[7J 244W>|K'ŭZҴڮuƭFFX1s ;/;_(P?}}Q ;/;_(P?}}Q ;/;_(P?}}Vσ4w>#}o-ZOȥk.ʂ0x9>OڵE^o'K;bѳ|*q8kQG|eq"QG|eq"QG|eq"QG|eq"Q~|C yn:xE.YvT5_4=gğ k/iZOwʼnfT0qaE|{ ;/;_ŽEE}E|{ ;/;_ŽEE}E|{ ;/;_ŽEE}E|{ ;/;_ŽEE}E|{ ;/;_W;S. qEk80JѰGܿ29q@Wǿ2CG(P?}}PTWǿ2CG(P?}}PTWǿ2CG(P?}}PTWǿ2C]?_7kI)]";]N%2*(S*yߵ|MY|+_CPIdn/PSt@2>_a^ ;/;_(P?}}Q ;/;_(P?}}Q ;/;_(P?}}Q ;/;_(P?}}Q ;/;_w?_7kI)]";]N%2*(S*y|MY|+_CPIdn/PSt@2>_a@E|{ ;/;_ŽEE}E|{ ;/;_ŽEE}E|{ ;/;_?ÏC?)}.GtּTKA|&Hv x S\ j>?gYǟw21M/E;-m#n?\6 $K{Md6 o`ϖv1X |}1iZjMs=!i&d#GwU0H!gݵ]>f?7JL'O?/A~o>9F_ImOGѾ*{Ëj&g{tLM cozjҼ7jx=z67s9ੂ8 ߻%Iax:<ݶ۽1nfo:@>_-~S[bNm-ЭCW߾7.69?ukkKX]>-dzDF?$$׊ȹ]mv (\߈ekT>!bզB@c?e$N0~s9#C_ZjcTy_fٿB;,FU,<~r1p6/_|uA:'۾{nl SxZE^ϵ @X{o}́׆Ɍ|9ho:K~# P݌:m"Xg3@|۽@ʅ.?jqkWV"a ~jy2m(H};S4jpxѮk(,4aӬ浹oIs 쨬#hj3{"5ɠXtO1B07-:]_ݭ{?/_K{qpi] 2㉖8_?=J/: 閺خvJ&Ab )2S?*O׊ޭoizR-HMqy 3$7 lZwa&@9潫_ z~~Z'= ki)4HcE#Id +̼?<[c&u#2(b&r/Rc8~دVO">F-Z$LT;j|"^.h xsGVϩi3=խ2pK(y00;OLn? Ǫe.]ͩ#ee-v"y\Cp|mu=htK]}'Օ&< .9&Yzōާc v^\9]26"p6݆ᷯ_]mGa_VuoxHgcj6Kt"Fld@%1tdUs▕? 隧$WK{x ytJ!1Wjς4gk.,3 դ4ڕiI-́r6'Wx@S!^O־6}:Me}Y<[;b[< #9ckı4[+rZa swFu~9JKrmK9 b.ح+W `ט߱(4+펭x6ne'FP8ݖd/#MGׇxc D^Pࢌ#o./ɾ;}|v&2B3L;~zxKY6Þ1 %%nbxShvC+0z|;cCMNxs{"l{vYYrpYݎ2qf ~Z^|7igêL \|#8Bw]9)=G] h_]F{ YeKg<+-d=ho~au{24FɈl LC٫_n<-&_umeᛟ i/kX'X>fo:@>_-~S[bNm-ЭCW߾7.69K'E7Ζ}Z3n~Iv>IsDxÖ3n.n෋OiVs*Cr|Q#|Cw5Mb#s~MI,`%sxG"*Ʃͳw=wy~^ޟ6s7|Vn[鶟C^ixtK@.oW'ݖ7+b5@S!^wo|?lƶ/®;s')UvJW𿌟7gy}IVi+6ӥ’[%)GmPO84[+rZa swFv_/5Iү'rGt`,Kgc;swJ4M7J&cj:c^#Mi&n%YpѼ*7eog~oNߊ=:㟄$-4ˆ(R2er9 nx6)K.Ie9 $ќ:dFFAךxK_{? {;[Aomx|)V0E ( 6|=iq<^ugԒAGhs$fۻ=꞉[~2UK' h%3iI޴U#B9 ^еoN= YԤ6,)d <{^C=<}@xm1q-wqpB:]`2j&>OZ]; i%2VϚa@@21dne+6G-?Oe5-Q(d2iWh" 3 VF35Hty%{Ti>aVbomq*3g :B6^~ߟ?-K><:.LݏqTu싻_<M7-o \}G1lX+#U ^*?5?ugR7~^ߴ\>do= [VUrh<gKR7⵱,QF˺='yD7̺qPup.e8B2/l5v)ã>fcXewYyeߧM̻9/ ~Է.O}ytQj[7iglHQiJ$K R=2;>$(IS'+v%G1U#}[k>7\j iO'Aq⛻쵻-zzZn.lcLn BU$i?.߭-Hյ?[?hOhezvum+ (B#l1 …n~q.lќ ~4mIo&k իOpx.c0m&];x{ͦgI$$(dFX&M}woG]Gj;yƺeiᇇKZѰ|eI'x_uɫ$| _^޵}GH CAUI%}L蠟82FsҢWb/__|Wo|),fM& _PW{XDńVGJ$''rq]e$~&t{F/V %8I#q_|?ӧ;H-{m5-;^lC) $Lw o~wK>">si_eTFe;Cv{go߅7?ԷGɥ]7 $LCd,Xbf[Ư /}j춓=3.U Qj3;s?_𗷌IͿ%ѷ{wާHfkѵ(u=V{x -ϛ0!+9{I^~ Sw`MlxAQQ|!Z*j5Sl =+ UX촋}P\3f=1<=TW/ ^/mOԙēBKyfXdJ܈čf_n~*OxLҤ淽Yn"cx{jӧ5~ hV-ή$2_OV,v7|zz~kFx;R];We]E'KX+"nFaTǟ xN'm.-x-ɆXHΡ_n<xZ/ąլ3cY5c%ݵ1_L&*9j5/߉xoj#NKkm+ɵ[s`i-#9s.9W[݄o>?i|w}$ү>iq3Y? ;"̄^_}Ms <ڼE?g %^#?Z!?c0Y$7q>`FB y'$ d{P XhQEQEQEQEW~Ӟ'4[e\2yv#NF}y& >"^>+:N.뵻_ⳚJӺn}}E| Ckq Ckqe/9,7_}qd9`Bm?¾Y^_5^_5X/Xoܿ_q}_q}5׿a n??5׿a n??<7_e/>&z\C(&z\C+Mu|E[.Mu|E[. ņY}ϩ  ?  g]{]{c,aa_r3oBm?¯z\zMػ+6s;}+Mu|E[.Mu|E[. ņY}ϫ//oݼӼ F8  g]{]{c,aa_r3oBm?Bm?¾Y^_5^_5X/Xoܿ_q}_q}5׿a n??5׿a n??<7_e/>&z\C(&z\C+Mu|E[.Mu|E[. ņY}ϩ  uMY3cOzO]{]{c,aa_r3]SKVܗUVpGP&z\C+Mu|E[.Mu|E[. ņY}ϩ  ?  g]{g/>&z\C*Ǥۘ틲n'8Ҿov_??FY{hץ>g/>ٿ𽾣vN|d)cڡ&z\C+_??FY{hovK|_}z_r3?Bm?Bm?¾,ov_??FY{hץ>g/>&z\C(&z\C+_??FY{hovK|_}z_r3?Bm?Ÿo kk7le2}+_??FY{hovK|_}z_r3[$m|d^fk=.?g/#~,B7;Gץ>g/H>/?!6G!6_B7;G/#~,}z_r3ik=.?k=.?g/#~,Ǡ'o?^ܿ gڿKK|U ǟ$?-㵽i;KO {5FsJQgJLQ\ӥ4:SK!6G!6_-Cxh$֟^ܿ#OK|_}Oo kk7le2}*j6 傾2W?ҾI$ube5OY\EK]^FܬX Lê7ZήhEΥ)Δ^Kϫ?  ?  g]{:񎭢xSOkc8|ޛM2J3ƆwK.ZTߢ3*9,Diӓ~ϵ  ?  h?^?|@eK|_ϙϴ  ?  h?^?|@e3$^ܿO_q}_q}?|@eh?^>/?Aϙϴ  ո\Ju|@eh?^>/?Aϙϴ  ?  h?^?|@e3$^ܿO_q}_q}<+C!Ku/⿆mm)\{qT4ۜB ^_5뒶{G.J~Z* '_q}_q}5׿a n??5׿a n?c,f_e/>&z\C*k i41dF==?Mu|E[.Mu|E[. ņY}ϭuM.=ZGr]U[w@9C_q}5׿a n??5׿a n??<7_e/>&z\C(&z\C+Mu|E[.Mu|E[. ņY}ϩ  ?  g]{]{c,aa_r3oBm?Bm?¾Y^_5^_5X/Xoܿ_q}_q}5׿a n??5׿a n??<7_e/>𽾝v@L1cެ\z亪s;kMu|E[.Mu|E[. ņY}ϩ  ?  g]{]{c,aa_r3oBm?Bm?¾Y^_5^_5X/Xoܿ_q}:_n +3.ߘ1{jC]{]{c,aa_r3+Mu|E[.Mu|E[. ņY}ϯ5׿a n??5׿a n??<7_e/>Wouj^Iѣ\<Ϋ@vrN2qkkۥQVjGfjEZO (4 (>u`?uyz7U%fA+k3ڟ/T~H(,(((((((((((+?!f~oTwL('^o[|a "tPG:·Y:ԩ4.cr!XdF+zN(}_ )TRN?S_~0sasi? 㷛ċMR&Pr R6(1aq?>9j/>|*𷆵;g@4mGG.8gKkȣ$m`Mn($˟zsMyybc^3? ߋ|W- [K7WQ4 _GU(ЖUC*Aǖ_O|lOѼ'xb_/w4lm8 B!-DA8`wm(cwYtԻo.([x P rqKo~CVq/kſ Oxem4=OUq 7;yИ%$btQ}4uI]5fTN7K+5տwU&MKD>a=/Iix#xwW.>$ %l+[693f`=F_)_8>8! ãxYH_.W̷NL_ៅg=x>)Cj 3XutKo"*ҬHci"ѽncFCAj,1%X?tms/ǑϵcmMŸ>wzJk}n kK=Z;{O/,ڇ"PCF'5Y,oF͵{Y]bYC6"kwÿR/%{š׉5= Nφm<ͭ[jACY4t7&Y0``p3). ?|Wf2MX/<>FMחи)(029ώg.#zZxͿ/tU~g4t喙9m6ݮ[5+e8&zJͪ7':u,(T擨j0C<hxkG> ?uO L76WP:[ 'sȅv ?T'ō/?<}oغ]8[wOInZdR$Nq,No-գuM&+{I*$afImbn{1o~ ~Ͽ.l<sChnt4HZId0xM_Ot&5^o?Ķ^ IO`{H'ˍOx׌eG<'MkcwdDlu^^)6;s9]^wy,Gr7a81^y~,iWZ\M/.1l𧖀$8N_OZO EՔ>f'[,pAǽr3s`oqMY oKֳ/z\;s)](cm T'g%6ʧJGu>_*WCp/&z'5|/G2 }Q_h}QEQEQEQE埵w_.Z*ڻD/O-x|.AEWxEPEPEPEPEPEPEPEPEPEPEPEP~ȟ"k'V)?D?.Oo^_`?ݩ??FR QEuQ@:_VaD:澨cCcׁȾZUm-}7$iV[} }Eiyw$wVEgN܀r*=O_'WQ%|E}WJI-EVpv8 ؊gC[/+ (VK?տ{>ogC[/+ (VK?տ{>oDѓ<R}2jXYWU =O_'4WQ%|E}5VFF3l3dl8gC[/+źZ32(v0ܪITjJ?՟{oO诤(Y/VKO|4|)+;#^w$3;;pP{eC#ZtPj_O8__9G5'Jrz/!YR9cgbǑvk;AOo<_߹Ԟ"}++Ca+Hg/.be%E*H*8ar_?g%O8__9G5'Jrz(S~/_jOϾ~Rx}/G2[B\:`3';AOؿ wοWQ I/ҿܿr _'tE8gͽv|5Gv/?'Rx}/_߹z=gb)C?A/y5'Jr?WWGv/?'Rx}/_߹z=V=XҮLʕ_o?!8jOϾ~Ě'?毩]mt8'j]9,UP2x^W.-bԮ志ȶIdTk63@O' Ǡ4gb)C;A/x% 𛆓xMKQkvxm˂% V< -LU%WQ I/ҿܿr?!ogC[/+ (VK?տ{>ogC[/+ K)deX|u?՟{oO诤*6.R14]c,70pQ%|E}!E=O_'WQ%|E}!E=O_'WQ%dȟ"k'Vm8̒VjvJZ(ӽt)q{%QZQ@+rͫ<]i-֪fI63I-Y7_q~Pz*M\߳dϵ?@O|׼F/־~1GöO\< 箚:pD$|} <ھ9W+cWx:>lWQ6>ǥqu4O]l ɺkš4[r`>Q(RT+_݌omWKOJr5w'ku_1CR2_."\YWDݠeIho ٌ#h`p;"[_OW,4K}Ok.s_ 8Ef7_q~Rci9e9+xԄ]/'D秣R?xm.^W'> ⿍ni7/,'>6[^ZҴ ui -HtKoQ#B4 ^|C/oCug]N=7YyV%ⵍTB努{M\߳dϵ?Y%T/%SjV+V?n&}? JU웯g(ɺk€+V?n&}? 'è`_ ??_𕥻3k!>.Aoc|è|pbH`Mbif᫗mOGn[_>"*oM\߳\ȥ^v` 9?_[|nd?{?/4B4->q _O=yG ?c%-hkIӑۊ_k|ToWwTWzml_k 79+ƚMnPxōZMn鍋i"`e㯝S}xMƃr5szFrgl-S{6 [4(!MX^ ݷJӾ|/~Wvo[Ad,B"Ŏ2I4%9Mdkm<ݷOSzucNq$߯[vTև矌kC–-gzty|+H~)AiWZF{]jQ{[t->J J>!T;o> 'Zh]׈4eΩ$[>yakAs "m0ѻ,@ETڶM4 0?JE^;1vbUo/-om;xĿgǓ|G'e՞+Yu8fXW6-Q *Qc&}? ?n]_-U웯g(ɺk¤ x\e^\HpCwcROҿ4`/m|F m53j:圐\$nţ F󡄖HEɺk웯g*mtɦ~Sv;ӵ/ڂo=nG?ZM:K$5;O6Q(cڤIH˹ݩC"bHw|etkiK&zEw]BY[,P`홿R_F i;+ b$R>q"mf_C#V*)ʤo/z2$uƯ(ˍWP>? OxZ_ǎ+s^MkKm2} !:/"ijtRG̷]$ܼ [73{T1v'n\#1G-ϙ3ӥ.}onVnO8<ܭԂ? j_C ;=]={M\߳dϵ?Y:(5#SO?+هƿ٨OOKῆp\"A/-PXi%YK)?5x/I79S{v6{"gjv:];A%zP@&}? Dnc˴rI8ߥi %9JjynW.֫59Zd<]3֫%;V(|υp\F*uʷ7s"{YX` ʑ;PbGNԜktTo]:49+jWr~ktފj~p|E|]u-VxN>sNKiw~>q&+ i_}_ZU\[ˢki-Զ"'b{T3o .kU%ܨIB6joO4mh a |cz͜S4n\KxE!`AA?^#jzFWWy| i/>Tk˷DO #-~dϵ?GM\߳3QeyT}JcoKgmRzuI??_h?lؼAŨ)g> WVA<\4YM}V?n&}? ϞVywoKsӇ"KlU웯g(ɺk ЯEXɺk웯g(c&}? ?n U웯g(ɺk€+?T/~7٫u>>,G%GkifkH$ .IM\߳dϵ?IbF/ 5\M֧|gſ;i7/C]ݤiu{Le4R6q|Ҍ_MԿk_J57VV4 xBCDhp:ޟumo"β:E,!}t[፤ (gIcq҇+ߕ_k'%7o#Nc9<axq} Hmd;, Ic6Hrf |3ƾs|7e4}GSUa<"mRɩĊ~.ri8GRdϵ?Zʧ46n/mviWoSU;El߯[onn>$4) kZ/> tӵBcgqw4jt[<mVѾ.xbO iZTwu _JM"]:;q'dHP{qhC~ \3pOrJD>]˸8^Tk5q~m7{u+ٱ9'+Knm43kS| A] loiwP[?"%^9W.dXy6 *8yrSsux֣'4Cckcf/O[UgXnetT M\߳ط!}}c>Q?*J厚51WY嬫(mtӧh۳|M/39_xB :/7kok \CIc1<>XmߤU2h˴wҝu>iVAF7g)mvII{Izt/"c&}? ?nJ+V?n&}? EXɺk웯g(c&}? ?n yl|BndׂngygigOA%wRA(iXԿ웯g(ɺkˆ ~Mitnӄih=Z8<1C6}[\th䉘7?M/zO%įXҼC%Z$fʾ%qxQ|$02'O웯g)Fi:~^{v7jJO{_ֿF dϵ?GM\߳U웯g(ɺk€+V?n&}? <- (?_ 1萬)`A 5~ ( (+!YKȴIn/X ;P2I> ? \oOR5 hFWR0A R.VIO_^<%k[kpAY-eVhb7ЈHC )9Z<xVڞh5-L9.ewDLW;bt;/4񝾛e)% mQm3yZBU1o ֋ygZ[MV̬BF(Ezfbv%ih?|U g:^MRx~=>m WY \eŕ ş~Wu*/KZ${evؔ:&6 w?fk[g${a2\]=Y8D~[d*hVt_FZ Ӯu&mV5_2T!"E| ɴ 89kep#azh[HD:bѪJ2DvplÚھ|-|C7ko-˫dF&N/L\aۓ8]__{/'‰>*\ =!9؀:lukSNEu ًJĨأ=R |%ߍ\t+]CS' ̒,2:},7;\4J%Tiؾ?+⏂k|GԴ -ڵsǩX]66JĿ&~3Foǿ_Lψ侲<-w ln$DIB(B"ue-{koT[N׺~'?)ׂ> ־EWGt]KŗNͨkywsbK$Tb3}W2Xh~9D¯Zu_:OkzdIuڙՂ].'X̮ :-k-ocxQIִ.m0s"m+h4-Ov_]q #t uq-mAE\޻ΗtNoW%^VmY@P4 oa⧌Af:Uj{iXP]VKosp"8FJ.>5g#[ռgiBִgnn Iՠ^ \Hut_?n/ >!|qŸu\^t 3XTx~akEtRW?cϟ/JN] ݾt'("-6l[3cŸbfX|8V͕oO[^ͦ]}y_no)?'|^Ӽ;xWǖxgþ4yglck>me\B^0e?oĞ) K_iiu,2ܘO:?!f v esL]kz*h>u!r/.vw!o ClW3E؋~|3úgo_?iѧ\<a]. (rT {ui5{;i]U{~p g keKoE;"+[Q ; HݒvUqr?o{^9񆑩*`NsB+ߵEqzN/>ODlDӿ_"5.߈?9χGMoN4OiZd3h.f7 u.n/ЌxQ2C?)+χo_>"n>|ͻ6F<6o+7~3UnܯnGۦh=/Cg iމwmޗ@wwrZαǾ+ynrA=q_|#h.mu-{W{" Դ ~U֑oizw)< E$Vvm+٧fø*Z]~z>*Í'[&Aw{v&oeAKƻR(UQںj8Ԕ6*q}mmn6v}>mnѭ?$4%׼_&n-%]'g,*P2u/o|[ߥgfu//ZW鷙QE[|`į~2xNHkh_gQaC4w 5<+y1c+'UECWY<'?6q[xGYK+qk,] $eԫ}‰ߦ;'gfU~Jn ]i{ok6^Cs~'x|?73"ngeur+3ώ~Gx!#ռ_y$z4/:L d{MW?g=xS)MAol>[H wV%L|財Yea5m~-wI();jͽ-ZjK֬?g? E-Iu}y5}imeqB4wS;֚1[}A^K]~ |)7m : BQ.`(Tڡ%0ĩ*}7zTl,=JY o%uP ҈c Ab#DLT`~rNݾi?N.EQE__/>%|._=ޥrDԭVY)rmg\4A_k'On5+Mz-օ>"Gw 4NдqzRwחnʏ+vߏ϶g?o~ XxU۟^&/uVͧ2)ٯKO/{W~;д_|V ?tz.gxT)}zB3ZN C/ď |M ?QҬ5 )5 ۛ r A?|{ Pпh]}~뉖m)A#+f-BWmzZV-ݛpM'=6zwNd{?Z_]iח|sHdVgbIhXPIR9zWD)þgbg<)[]8b=K6E$Mo\\ݺieM5( (97AP!<>ũ3vؑK4:L,m?'~ߵ?SWlx3\x垓oϦ]G~)>mV4RH#D#Sjׄ?<'/컬*ҵfkA[@5=/S\}q&vňoYZ4)j >bu}/k_1y(oO)\MsSؼo%D:\]AkIe8܌smtڿKa|nuͽݤ\Z<3q"HnЫ E&RNdzOuoŷkW6&Gw%G~DUTJ^I?zW}6Zum`<][NjZ5ΫoW<(Q"k-[:Rmrң"S.|#VU*s+i'z[Ci{,{fi9;{]K#úwI{i-%uRi}ԓup~&Y_x?o:vV?|7iѼ>M9/H@%kXiigenw-+dѧOJ[9+-/kYZkkG{'c/xKRo|oZjپ'mGLy㶾\N[hlj"M˟63b~<*-{g>5<3xjkZ7KKXzqj#H-%~SK[xp |MOu?Y[Y!X:E 񖝤"eMca;^@"Q q}%hT>0j>xV[uoHoΰBdD7B20I# s`7{?xFOwt8?-k?؉JGg-r+v_r>"Vx2x~ ; "OaBwxF)ir~zmt MiO+Jk~G?9:Ѿ |:ԵQhaۯ\hC..&!WdFS (sz [ψqx_x;I𧄮CRXگ4k^N%i6U5<3xjkZ7KKXzqj#H-%%? G76!ѦTѣӿ"Ԟܔ66PqmlL6u:O:?m,d}L-ً.k+i1$oh&7Fv|mid5^O_ß_ѥU#Z/R#]XYz ]nCǂ~|>m=Xѭ< ukð+3˩ZdfٓHu"eW?+Ei>ֵ+fOڮew>VBtP c̍yzwoDilmSĿg7:'mm [ZEQpq2 o^wMicf߽mw] M*o%᛿i:|MImh{ol${i$s9Bgkï^(3_<$|í~CnXcsQ卉$/U>d=3'|Kuq \[}mosXS Ov+sß.-G\g<[-'AuγKMEmk ̪?4(ı/qn[ۮt֟ɣu+g( iV߷_~^$s_^4/z.|@'i;;LQ#{92+c~J} +ǿ;ix3[G42sl' dDP 'i~࿋nj|L,<fXSM#[POSj 0Kn~Οٓ Q|$SAk CLѢ+9Xb4a .Zw׻\YnJέQ5as~oC*@* Ƒuyj毬x\)wjME*\OꞠo]'ς|b X2IGePY *H4o#7>5GV[EF6rT۔!M iO᎝s/xAb|wfj,0]=mop{iO9q:~ƚ ~%cFfl(8li߳)aox\l.ݛ8[[Fs"f jM]KvoObObŠ(( VozU?b>}\~WZ~".Ö±gFi ƀ?k6Jk÷rxAsf^F"J6GT$D0%fU'GY(5hch-qai+09+WmF])RmBSy;] ˌ`!;$4I?_-4iI]_r1Y6 hq6]^X70X".XxĢiU!ٿhاS_ _~wCfj7:$"J`M+;,:NV7F<[EҼe?|=玅&%/veyZ5ߍW>?qnB*գҥm6B܅S1sxb=n$|=o|5qxG7(>=_Fu ;P(ov^ًH "Q]`O)𦡡~5-IZOg4lv [Ms,O*6kn7m.y^Zy7w_#KÑO]-[[0gZ_xZDy.3֟q{gg<X=Efd5xwEQ_n;h:GO;Q i}ӄVRqÿ.R}sqR Hz`,ho19 O@7}ͯeVԴX5i C\ݽ7y2rMM;{W^woiumۋߚ+IZk?&a~X|-s^$~"[KJtjkm/>";!">_ *ş^_%(o~#}2j[]5>uO%#@X)> cklԭ]'tJᬬgMO1tcɿk_ß1f)?4>C-)7g~M+r=V{$o^7ziusk^>e]x>Wui:RR>5]&K4;חq(V ?׌<3I|P. 4)[k{;6Pɽ]nf$^şI3o 0il<t67UHVJ#duߐLo[M 2_m?g>/^&kV/l/u}iwH֗PX,RY0 Eza|Qg|hiK犴ۍ#TV4RFea4Lք jo)χ{GG_|155j~rȯfOF [,jUHڪ& עv{08õg+j[袊((o瀯'|>4O Ğz:ϔ/- ;8aW] g+~(J-ċhѭ,m#>4>Ce)"H( v}^[ſ u;3^.8+[E9.YDJ/dkxSP#.qI(ch*89MkL~/nb}zk,쮮 ;y=N" 5/{[xGTNvo-uhCŽĶibI-h|ehi!71b ba#7q7@o,uԥmfx4& q"Ox5S'Ɩt4 XȺ}w46[&2`D>Y)q/S|;+e~ռb~$P_ёcޛ[XBJ/rVztvKY/:Zs+}=iT:ٷWߍ*yV.(];#[f#,ftX$,Ri;||m/>1xT|ME,t; C$1kal B/>Ef;O)42h^6PYU\Tm[wջ]ոʴ7۶쿕YjU_wWo:(xs<D^9/dZO"EOj'~)ŭvZMtK–ZW.nu(fF!Bdh2vbRĞ AixUM2mYד:jKĝ ēnxlwQk\TLJ<幟O!-˃B_~6Uۻm4Оk=[鵒N{ѯ?goY8w.o;@е? x[=6rXݭCMIs;ߊZoVŏ~!axL|OɩImK^Q0s)e_TO<Kƭfu}bz׈.O24ekc2GdO¿G|*nj U!ԯ5=ST ẻfkV\K+$ZAUd[~Z&(iݿ+V]uKug˿>-+ ___ž-ծ-[yuN{kwk%7 \L"B A?%|dOûI4.ɵ,Ь]#p6Pyox~P׌~q=Uu)#-4\#vG[YϏKU)5 1_ZiO9A%0͹BGIKW{}- tRpOF+rN[[ۚ $o(" V ,t紵𕦝sRbX՝̷3VnU|? W~0s?>~>Դ=5\Gy'B`@H^5p~׾98^!^cڞ_z_ڑ.wfDPIې0?u4xSңX`6G'Z ŸyWI\ɸޏ~[)Y6zi|sC-[W[hO}ZOioZ"|W珵=Fg7 \IbFjhM~oH sce6[}AIz JxG_ 9|Q&i -yuyuq$rIy T-6TuRMQ\[WiI՞}-ֿޫd㏂?o6C¿מ |oEҴ]V լR%oA +,f ᾇJE/ğ!q_ h!Mr2+}&yicK+r#f+?Hx_ F[rX[q40{%oU | (~)>+~XexcZeyOKX#X̕Gڈs1I'n0m]Niӆݞί*)-ne&ލ_]*(k/iVSIq ėm`,M9dr YWVvw>e]S:o_FS7$,A %ɘ&/pT#ޗCwsM 0 *  }s^sךWt־2gma< 1lb=rk_}t-ϓz g- +A8Wo߫'} <;khvdQKw<,(KK1,15CV>/$VD[ɯ$I;L;p$04$ѡo$vNc[_I}{Xj?k^SM%(yWg{u_x^O6rPP$K%Ŵ \(tBCw~ ILo44gQ;)3[G ҲGU~TQ`qVOš-6i.jMn3Tp0*/e7Yv_v:g{7uF5Xg{7uF5X0((GެUic;ג"utU=z̺67g/Z _w\oL*qO+pR?"O0!l, }sFy|;lP"iB5FH#H/5%epF־{Ğ+׼C? _v ŬrBP O#ҬJ[dYZI.5#>W6sR[?_+nͿݮvx7l?6;M1x.%}nVC pgqs'x)[3FЊ>\FLk ?v9ǭh_<%x^v[]1 d܍r qk6Twi-]b17 &ח?KQ Ş񯈦];i S\vr B+)$ #<^ 0R5j]H5iPCmuoK EQl}G uo\z=5KK먣ĭP_'z.سwh|_%#mJ;/9bYbJ ;31fK&'eܿUaz[]@7~\Wÿr_$̇`!;W;LrZ6:V54RZE=yo*h̲2lgWC7 K9,;Be )KL ~UO|%i4 xKv-]qB#+$ "*c+Vyŏ?mn k}Z6y&hLaVɐP:r{ߎ?%jw b̈X!/±Dʁkė@`Co6o"])[,QU˯oGud*L16ߌ?'b*MK+ P=EV6\?{g1;kb3 M5i_>!d:x6k &3LݷعÍ+Z/qmk:Uihi}[Ј6IoP(cqʦ,ݮ]z]φu]&WKd\4˶Iɉ%(C\SO|-FȬ4Ju{[7LHfH 8/''o#|`yi `楣^h>uiuszZ^m"U*Oڮ n/$)_.W[oiQZWΚgp ۡOtseE-/ih4抃ZNmnğ~'|IOt-/Hӭ!5Cmܵ_^HL/s)o#,GVOg~Lߌ$ޕ7[;m[[_at֎0A,J> |o'?gx/z-^f +E*E 9|)*'ŻǚOwKRLۦy/J#X%'57JjtIykx}yZ}5 +ZJ2-f|; 'j+(x9>%2^]Ct$:$ea~M?;W_tߌ_ >&?[=pF:%eCn n>R~oo 7&R-oFve&XD)f k1φF>o)-$YE^V+}&ݾoS|>E–ގҷ'h}~ﻧ_4D5#Ouψ7){.VWukX-SfxNcOxׇ>xl5c\zԵK+Xρ`Mkq;dIx;_CĞ;')Jw/tVI$y/ie]ى?guZGk,гBۢs1 _jZٚSum?&Ut?io'Q j9OK&Jsikw;{!n-zV/7??f? E_Zq M{yv"e Wpe܂8i Sp zqE,pfc*p%'Ȥtk|եm S <iԴM-KK=ӻEelM7~Ulje%5o zό/6Wɻ67'V6J]A<폂~%О޵>5;N]!.4M2]\yb} |)W<5 xs0}_ҴYYYkmd Rv"0ðkEo_m|/'gYJ#gb 1*ʼn$O4Hr]okAZY8oRjRrK'd]u_̺6y_"@z~3G%_~ tu,Ү@6.յMc1_"o~gƍ+G> RAm;Z]ńXpƄ,`9pj3Skud㮖n땦~Z߽8_(׌K/|N=R6WV&?/al=z;6k&n~:z: JUP9b.p 3Px>-MƱk})Mݮ$o+fo.yTeH߁ϊ^|;7?Bf^Ycc)"Y<奬i>Oދz+yo_a_e{kxS:ݶoꗑ[ lwel\y˴I U\kǨxO𷍼QTM-KIpb$ffo'%gi|! 7~|)y܋ A8{QY(rN~Q CMÍD4-47Nmm,aAc$h@VVitz'{̭$%ͧMVݢ_"2xTb]<˯o@+?!<#JJtχ՝osi2iKC#W_"xv8֡H5W k$RE,OY A$ffT4ߍ?f_Wa_B7uˉ%&\K-ś壴ݤLb ~ eKG1d:K][Ɨ%Ri7[H8Dۨ] Jj]|;gaK xvoVSiZۣ^-1E!XƄc=&|4|Ik?8F _h:-q$+I1я2xW)| Un\G]{5-K[Ngᦶ1yr4I$YIwvf$B^%=Ui$-[?2LJ'>v\mY?<+o$nnL=B.Oe^76CƱvE%5Gv'`Yc9ͻM+CGd,c$CKAsRxU+ƕy4IE,y UIQFю߁,-žth4;Uf,8"Qff Ğ(-Zߕ9]_-y/Ԯe zğhƚ9[oPwq!WI q,R( M.5_ >#]Ր{ uvX Vu,N \M_ Q->9|??sk2KmtŠEW?OǏ>+7 6|@wᶃpu%|f}K!g,qW7~;tk-7s:v1.oCk)RHTbj ^ou}[:U&vZ+^c 9aW|Y4_VޭZS1x{a&jo%V҂(͎) H9o'uZ-c^᫯YrV>&]Gwq+/ G9ئg֯_k:/:u=xnV; TP"wQ뷞&wkSYE4n;h}>Pyq6m%.Was9II鶫OkW?iGGYoVq{:v3\ID5n,ѥ|HGßj_(>ͧxKXCxЙcP%=/|BW𖃡w^ &`Rϸde=.p ҵ.WNnViޛwn{.~,>&>|IG<= [CJut9s5ZiMwu{tmD%6Ϻ8|>G߱_85v{Hxki{}"kkqO46O,s)"~/>x+>7$iZȇ(dܧT~MDY~Ѽ1{&zUu$r%ŴqZ9Fb !] )wRRwDRU-j'X>4~V|_d~_nlk/'񆩠M^e.t˨XM,6q'N]п5 (ۭG_ Ni>'IotK\׷v=twbJќaxLqZeh,"[hTp^k_"V8Cmv;]:J3 /q2$@Uw1\-ǯmCH&ˤ^%Z6KHV ѬF~Hߜގ&n4inav9O z! =u>J/ IE.,[<$1[KIn>q'Sl|k|5[{Tcv67w6K\s$]e#ہOh&ogxgÖZA60EITNqV-[Ohp Ѵ#M,bcK6H$$vO_/ )>_b$O>-}Tj ?\Y2Gq#ae 67~+l-D߆l-#KCrjC`ěp6xgM.PG{K8H"ς}xO )(VY"};Qe'F Re9~_SKzy>]dэV*^ |Oqvb =qSRQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE|m1|Smk]&+֞?L?wgur(dL)-dՃ\J]> 7h d9-/-X%Ο FK:]URM/Ob82QDwRF2G߷/_/@ߧ+οh_­?曧^M)l \JXDǓT}3SxCޖ5[^ rx%Tl.ѳw();?_=JV79bYaB.lN%9o C'+O~zOh>'MCռ1 f k||K"sEzZ|FƧqtWK]Gh$-԰dP+nxw ΋6 } ^iT\~NaO.bxN}bO_p=o~%kūm\Ɖu+Y9REȚ)ٟ/엢^~$Q_KW7hvBbtrk(?}_{8/ ~/_JWLm _3v Dmڣs zW6ֲZwL'Hmd0# FA[*A)Y_?x'_m|KisMqt֨Pih4DMĆPpA%sNigO.y(7H=|%ڹcҊ~OBV (Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@V[h#{kw--)#OA@W1|E=G#G_<TW1|E=G#G_<TW FwQ kz#/^*+OcuQ/zGAQ/zGAQ/zGAQ/zGAQ/zGAQ/zGAQ/zGAQya=@Eyo#G_<1|E=@Eyi`d>"#/^*+>"#/^*+Oc'Q/GAPQ^[/GAPQ^[/ǟz=JMG_<1|E=@Eyo#G_<1|E=@Eyic/^?>"Rf1Q/1%:=@Eyo#1y{Ǩb?z=JF#y{Ǩf"R#/^?>"R#/^?>"R#/^?>"R#/^?>"R#/^?|E=@Eyo#G_<1|E=@Eyo#G_<3|E=@Eyo#G_<1|E=@Eyo#G_<1|E=@Eyo#G_<1|E=@Eyic.9{Ǩb?z=JF#y{Ǩb?z=JF#y{Ǩ>G\u=JF#y{Ǩb?z=JF#y{Ǩb?z=JF#y{Ǩb?z=JF#y{Ǩb?z=JF#y{Ǩb?z=JF#y{Ǩb?z=JF#y{Ǩb?z=JF#y{Ǩb?z=JF#y{Ǩb?z=JF#y{Ǩb?z=JF#y{ǫ]ʹk%̡w|~vC\N_zg~zEe4^'".ehZgR<V>Gķq~ 6O}$m=2ɭс9#ՆO+گk ^j-k1U3Iq,W)qRB99ԌWC[.A{}?Q+0X1㷛_82G&I2#nHdEƙge#("F`*8¥Zx5KG_<ƾ=_5{o b4ĺLpEc6Ӝ@Q,Ǔ:}| Ԯ5ɵ#XHn!$eN1 @O>hZx4[G>cG"_񤶳cty}YI隁A##$cX,EWh )kEӼ{f)/m?UHy.Y"0))!*'E>G"_h_}-[X"߉du%Wj,T|]h-S%̚vw>qGx)u'ҧiʸm7Gz}jpLiH[i)ЀU>I kjZ~ķ*7t/mfs\ifO1ߡC×bϾO-9uo{MH^Idi OGO)9 U,IoeZx4-KWu.<Oo"[i55Ѧ=!L1YV!wA^txK^ZJ ۈSnlo3&B?\u$YƳLd sd&Zx4 3"Rv}1[ nƭYe{k?_{lul.|;qڻx _}ƏE>DZ7/ݲAg]ileџWsyW&HVAi8FP7dc>e[;mGOߦ1G"_;zX|ye )kdV#*dk?E=ۍآI~M3gRj_- |IVk:V}$t2BvdKp+_F:O>(1j^7UB=5C\27V _}ƏE>Tw?HWWRO']y4J[;zrA0f򳽤aQv2a6Qj&HDȝHyjn~\v?_}ƏE>R֖_=OxE{˪˯eђ=9M2y^Apk)eEX9nQMM;EhRG9/ g _E>G"_-SBZ3gk%A}nZZs4dO-:aʕ$KǑ)HgZ_}ƏE>@+Ckh>Zx4-G"_ +Ckh>Zx4-G"_ <- (?_kIZeuFAOjEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\߄|#SKKӤKHI+E NGoG`Z}>%r;e8Fa 1$pDվ(GhMX3 jC;t;Opc܏,%<9 kKKU{[WI"l y\desc,ddscmmmod(cprt-XYZ q0DeXYZ a)(XYZ #XYZ Rsf32 B&lcurvcurvcurvvcgtu ! ! > %&s "]#%Q&(@)+5,-/V02635 6}79M:;=L>@AeBDEzFH6IYJLMXNPQ]RTUTVWY9Z|[\^_+`Wa~bcdf g/hTijklno7pTqorstuwx(yIze{{|}~݀.>N^oȑҒד۔ŢfJ-ǩ`=ϯyN$дn@޸wB ּc)t7¼y6ůl)Ȧ^ˉBͮdЍBҠEԅ$dקGي.wܿd ޭSNMSc{1S ?i5yS&r:c ] ;p!AL!Y"$S%'I(*2+-./1[24(568C9:@1ABDEUFGI0JmKLN'OhPQS T[UVXY=Zm[\]_`(aJbfcdefgij4kTlrmnopqrtuv'w:xOy\zf{z|}~~pdYQG<2&ݜɝa<٣nI&{U.°rK'ص`6 ⺴c6 ݿU%ēe7ȡo> ̞i5Й] ӐBի_}0ڛPܼr(ߑEi @gHq)YCw4n,b Zk-@[v "(.<R^T !"%#5$;%C&O'Y(`)V*+,-./01233456789:;<=>?@A}BmCXDIE8F$GGHIJKLM{NjOXPCQ+RRSTUVWXgYXZ:[\\]^_`sa[b:ccdefgphRi,jjklm{nRo)ppqrsltAuuvwxryKz'{{|}~jH&߃{\<ΊgAҐ_:ǖvQ+ڛe<꠿qL%Ҧ[0۫i?ݱdB͸zO"ǽtL$®ÎnO4! %Cfҏӻ@׊T݉ +efK~ndin6WeM((!GP T93G*6DSdu6Ro>e?l/a@6s7yL 9 % v  s x , ] O^?#"2Hj'U![ !I!"#A#$%R&&'g(()*R++,-a.)./01`2333456w7Z8>9"::;<=>?@ABCDEFGHIJLMUNOPR9STVW^XZ[X\^_`bTceGfh@ikQlnvpqsXuvxiz{}}L҈{ohtܝ9F]Ű$Xx<ŘN̫UӪGڕ޻ Q8i92y $/;HWgw)D`}$JpAn2e C}8wEh  S O Z  p / c4 yY@/"%3Ie$X*i  [!!"d##$%7%&'d(&()*v+E, ,-./Z061123456y7l8_9Q:D;8<:=;>ĸ:ˆeԳG۟IQW"\  /BWoBk(^"a+psn"}< ,  o S = 3 ahx I|ko$O F !k";# #$%&q'G(-))*+,-./012345678:;<:=]>?@AC%D\EFGI7JmKLNOOPQSTOUVX+YtZ\]s^`)abdSeghikllnXoqSrtNuw[xzk{}$L߅yZ[V R򜋞B𡥣b)lEõpM羵u'ň3fqQԽeضE}ݍނߟ sX(zX5Z"desc Color LCDmluc itITfrFRBnbNOesES,fiFI>ptPTNzhTWfjaJPtnlNLdeDEkoKR enUSsvSEdaDKzhCN LCD coloricran cristaux liquides couleurFarge-LCDLCD colorVri-LCDLCD colorido_irmfvoy:Vh000 LCDKleuren-LCDFarb-LCD LCDColor LCDFrg-LCDLCD-farveskrm_ir LCDmmod*MrtextCopyright Apple Computer, Inc., 2005C      C  " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?!~|ܾ.E^]LIGގ9*|‡z|e-lj6v7I0°ޯbcI^F,\u h߶fiNQR %eO0!H`ߒƶl]{m-ҿoϧWWiRjIGk`zKh ʪ3b[> x94BX讂4ewb)oBT:͞濠[8Viw8:ƞ1I6MY*>Z3 v7G-+OV>˦cE %6R} ,eKNV۱vW'+|WoW4P.q˜\˯yu_F,ZkYk V!i  93o/w?&e^_U1$mY$A [!xj%nۭ陸&>}Z/3{z{+Ify.D'8c3>(|8|MhZk|1O̍%]UH "[?<%:fk }7eY 1Vbc` pj5Ki} oWϴ; Kq=nom'o xK?Xi171\mT7s #?&T ,cv=τ7Þ;Ҵ|Gn#{in(ܖYCle`+ɯM_ϝusgʼn<$#%fg]۲AxwYxt/Cn&7W~V#;듛ڿlF4OoMAec$Bpy$6{_i%xw-^=}ߕ/򴞾Og=&?Ufexa9k:^ $; !oWLSh܏+sa)[~$xP~>e@Bc5ddY$vqA YKjQ]o[ҟڳu~ڗG?s>!q WOko.yF۰0bc?d$M4?zޟs$z -;[nV;mت.&/;9_RW_.?ڗELEKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKw\ -|mE{xXm-l羺qo&n3޺o5SFMNxX˫5c_Lկp㍠3J#>`#<"WE{ۛ_^٠k;9쮣BpqIR`T`39 [km_2 Fr-~r8;W^2^Zy/3s,ҜrҿSr]VjjOmZW'Q SVo ҿ:W&t-O WŖ|Ҹ Kqc! VX?&?)ejY/5{uѽ;whweY ;u|ܖ[-R[U\-M[+J?jjOmZW'V?Fw4;^cGRZVտN/jnmGxvʿLA Zi܉Eٜ-M[+J?jjOmZW'U߈_ |EP}*=ͅENQIM~}OqGH?ED -HAA de8Ӣғ:p:-M[+J?jjOmZW'W"S_&䪂ɿjjOmZW'Q SVo ҿ:S_&?ToW *&?i_G-M[+JO>S_&Du5o'6+U?`UkJO>oZVտNToW *U?`UkJ jjOmZW'Q SVo ҿ:S_&?ToW *&?i_G-M[+JO>S_&Du5o'6+U?`UkJO>oZVտNToW *U?`UkJ jjOmZW'Q SVo ҿ:S_&?ToW *&?i_G-M[+JO>S_&Du2fwsƏQծtu3O>S_&69~w4[Vt0B+%cDuC   MT©C¯_U6 XS_&Du5o'6+U?`UkJO>oZVտNToW *_Y? T|-kp?-տNDu\ֳoOLkh* -N]bտNDukj\izqYތ+ѠcDu5o'6+i#5 1Y[eaׯ +O/ZW%.E58,`Ԧ𾱯KooGǞn4Nh֛IZ^Iⳍ_y\SHZտNz(W]K]4{n{$a{ 46;c$|Z#F|Ir(c÷!"BX,JZV rkڟsw{u⏄/4jZL<-u}Y8I65ݮqf&X-oyx-o3wڟ#;mN(˳c*']W Ku,jz-3[y3+dMp8'ejacx(4Vkn2ƛ3`!I5O___ ^i~u]R־}BH](1F,)95^eN<^"K8h}RkOC,5B}ַZlp_/]ߏGxmFXF˟[+`)SsȭhQmP 8P3>A>$x}# F(Ks#o#8O]XSKJDC] <}KoE^]ݵLr236 Jn] dn^=D@$Q{16i#}łu'8,AyN<vP@GUCc S2Ke[?}CZ[E'í&s<yiJ<[b_}V5 6ۚڝE~A/ǖsuUMq%ٮQOdO/>nHXyuvZ3,!KFmhNX|7^ji+]{xKEkelcڢM=4˪(( GJ#YI\n|)!X}Eq_pD8I0n}zyMڽ,)QUJ%~>5~@3llmZky上)nblFXHU!HBd0(k? }Q-?4F [jV͇%#d5ǂ?$i<{yǕc `̓@?O9a8̳<ԦZ30爊QTX~cy/Z~ 5(Z{]j3?hoŰ*MNZW?CO-&Y`],xp?_t=f>'?LҼگ-GNk[/!e* :DHa/qv~f mOtHFuou)t`}j*X_N/ |co|Z]M[3] XY;VyEI}c|KFxkV_D,x^}G(Im`hV-T*+CTj4~Vw[دZ>gg*^RKYm{u~^ >:j Ѱu;ҚxYC^̊@"4V}hZ RcS7 [tk;km2hguit]^J#FIHnO?;||\V R\o5Inb6H"IIo+K1!']ta|"-'6b_u=Utx.K$mq3%PL'"muOZ|=nM#I5qem٭_ndrƪ&s0G _ oxmj~%z&%>& :XAlm>"[so$G@boޒlnWePQryyyѷ pi[ms5C.qvI"ClzPkĸ?#C}gIox;wjo|lmM{F) 4$nlR 53z.M}6u6ey~?^K#1'2tǍ|'b\|K|CǞ0tX>'j__ڷK>u'^yvA$n:m ;Yti]c+ƄmU-d;kmx' Wm(eMoN! F[ vίjl,˫1y1x,[fҿfo OmxH_uZ4{&Z5< `UM*5[㎅_ F4~׵sHnҬ}B*؉IW!zD> T|Qggaiũl"8̓b9#]_JovɬxVOxV֍[aku:˲|bTITyJt7:|޵ߥeG)F/>+ޡy!vqoS.#h¤dy[ƫ1(:-O_V|m>%躆}ju9H4x7G71mgIOZ9=<[*N q^;oiwhy,hykOu-u4(QV1%"s,M8ϭ~ԿωcGO|C?R֡]] HK"@LֱGVi>m T?ao|+O ӧ_^XK&^ydRbN>,|^{u+m3ڕιsg ]Mks1mnY> V1m}][?|3_Mw˽{w])Q߆~"&KN~"x2Z,>|OOLΓ" Kߍ57Ut{U*Q9 *#mFugo tkoD.P=^SբI l.-q%LN(|/.<3o [ k%՛n'i[  3ۚ+xZס5{Coj=QH-}5-i?h'NB- EƗ OS>!h:\<._IIK;m+y^X8C_Z'_^u#AӟJږY `b&9'HY^dVUBM?f'fܝaM'򒓲.NN+dGs`lWxp(@$|XOc\[mocL0 Vno+sG+*,wĭ+o~5:&o㵵&""Hb>>s%tO_-<O7x8궿:^s$ܺ'~$rwq',y`J˖N-}IѼWGmov?Rݩ$d~5KCEW^/&""["ʼ  oju TmkW{ߊ4vݮuif%hK A|I#?iKHoG?U{&;;HJMbʋO&,̠J Cr/O>}oڅ 'EsefV̸" wm젭62p]S7w֋m(GݷWKy2^_i}Tӵ .k,e-Mg-2]xⅼGT|V־"/|)VYnψO}ai&b rɅK m.{/8޳7Ə: KFMB]]_@-ZZƺbٲ"i'YF79څc­;+xIkڷ#aO3Ӵ7еH䕶BbVJӗM3 Iy1L˧4|7x^gċ}{>1xzo.=Htm/cݵ,,R1,F?' 韴@'xooxY_ Xkis >¦?]$a$BV ѿos~-ּ77ŪO<ٓό'J7=[@v`eflmm;=e`^GV5N|/oq>˯WԢ.a_Kw+mXmm=Tj)TU,ھֻFR|j95PʝvѷLUoN3W;>'Y @A-:;%KX{̸Au'0>ϳZTi_ ~k/\o ʱYnRTʶn4Q # *>?F>ǩx|Ps5=GGϊLB3l;mq4Zo h^ ťtr3K=  ?R_x_žVrGWVWRFZ$.y$Y:17=d}S9czw{5gk_Ee (~V< i't>׸"&5M5 &1ۑn23n Eu;n5ȷV*l9R HÅ]|wfLUNQW3Km<,} u\JJ6^{4얭ꝝ>r麶:ٯms3EǦMlhӵΏi$Pk[ui>ͦe~݈w$JꭠݍBqRw}j`ݵ{_Ŀ 7]5pϖZ}ZNoƱx#V:dckwxm2KH1rheJ+ [~i*|ogZdZ&|8^,qzll7;;W_íS>>> u/ J.-f{H4-&;Y#\c0۸3ϙ׎%ZJRR\O[MW RRw^.mewۋvyD>XWE~O<9_Ś6ᔽX\Gy)9HVk݂9'? -?ߊ3i&&u :ͮ$?h3DHZiϛ믧[|]]_罺w1!6Tᳲ*̍S4 K(1|Yu_]/᥋^ $S*XȶB}4[@"Qm7qF=KRt`<)x{\u B=Jks./n-%xK* )E!Ӷ_M{kJ=WϦ}?[|B>4v݌7$DIcWPFO5Ut[4{K[-H䩚઀^M@8qV=ivQ (#֤aEdzEdz_:YA>#I(iLBٛLr?ь>=j+HW<@?F8xO"/^:,.Ok~&ޟo2IlW?|k)fO?n 3׆ o+Ś>n~B_iqsgCop 9ApA1|m8/xxbom,la0ErُlWYڛ[eM_&'(_[Nf.cQz(爬5땟>ֵv,smfmw~_fhthRkDl5ִv4z2խs [y!ѼW,RGGF ^ERJ:$K#ӑB`šKMJ^E1 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=i?#׸@ 6@+=#Nu*# j?/^ExB: 8xJ[W^Ex--#k5?&5Gj&#A9]Cg %OPz:(?Ko/x =C ?^/z#н_$Gs<3L{ĿIGB?Ί3'=g %OPz:(?Ko/x =C ?^/z#н_$Gs<3L{ĿIN_0?ƊI?%uGvVMWڈ'ohlK PC:*/ MĿoi| sЙf :N SH2#9+k>>|3"m[K B Dh-g*Vϑk6/_.ůh8?੿L_`DA=jv#["ȓL@Tn0n;S\E8U\voE|^ۮ: A|5{: >[#,t$d~O7Sߌ?> ŦxM{u#PC:1,:$(PXvWeYS^6ߞb䲺t]rVk~+Š(((5о+oў84KP&mZpVH0 ~,xW㏁,|SSuO3ZèX]r4RyWFdD;I#": +)?E%]^mgċ$f J(.t80]HBgEfw#Y'zỸ_GԗqƣScTѮAx N +)े4 b y=jC,m!dlRprPEPEPEx+3?­KD^!PZkhh8 }fNF@EPE|٥~ο oxP4'Ί4y͚8WjU',8BQ^m.^|y?6zŕkqdH␐#L9_I((((((((((((((((((((((((((((((((((2[\2 ,@IW U7~֓! "C 9-HdMK\$?c?.v:3Mʖ~rXw_}b9:'gMO*[˴O[G / uoƺmzҠC4:.y)lj r_4ys[wua(k47h-Kbl~g"x Og7*ĚYLo2q9)p0It^.OJ+~0A>ͦ_6Z'wOb̤z?AIzs?|#t> nhַ%vx#̱[6_gk %|Xkh%>@FܖPBɴoaڟB?(j7>GiKynH 24&#t?XϏ YJ|&+ 'K}4M%)UeR<-61@?p?]  Zdˣj-uw(VesTU!VVaO8g>xg}* O9`66޲L{Vt)8Wk{K< ziq^\Fg#Xov BFs-M>_G.5k^?:GItf] __%ȓ'4w!=kjo>7%~|=y8W+3o{"ر%ϕQ6/???T? t/xΈlbմ{g*##mUm9g[oLƯi֬5 O6tPq&Hv*d;-8s ^D4b;ku ܏-Õ۷ }i|sk/uvσ&Iιx{T͢H:Hbؖk5dcx>z?cO .puIGW]BDI9|-/~/~k7 ^.N~Cëq`䀫` ^T~ f|kMynuMv`S+ʯ:s?I0_PlyMTde,wh uh$n%-^C<81.gP?'z7?J;(];Mm ?h'y|}z* o+·:ij&ik}UMđ?^f\6>.!B?o.h^o,sj8vBU=Ǎ? u]cᇇefm䥦kh' Wg>r@| #ύK3M|҆mg_P]m=kFn7{^|;MPKfNDc $@3|P!a\xg{ӹ|ζO<o4t6Z]:3Cï_ |'xfff3x_:i"XA$PW>i[uM>'^]659 < |RkQz<\=liLݓknT|w[N:ιKm|k݃ _f~q+n&k9%x'i@YYNH؃U;-i-f]_Z/EɲK2^̻GP_t|9/{c{E;V(縌cBc9'N_h=cfMw:հ+eI Fu%,Îu:Yy]>%>,JTjj`|Qx tɃLݞO(Kb2 f{Ee'M{Bm~dd7$rǕjE-0UUU9?]-"hC0e?=~Zs/3WWůxXo`[X`XcM xp rTunl ծSľ]mbJTwڿ|E:|OgǰZMh,-d{>S/&BeG 8~ys]-yj:CVQڣC06r7ڼEhPDN%dY_o>APqU*~׿ h-=~EFWd˂V;5 )v F fPŐjM߅?'w%hZSF0Yc/Āu@U>A?<V9UA*b_*vR}-^_#%=4]#]t;w-9Wξn]MԳ< z~_E;y;_z|mjM{JIu+}Z;Wk4kJn [€I&|+>?N[özm'$K$8'^EV4{OW:m ,N0Uс pA5 >8~#yOd4ַ

m3Gy3Zڴ&8 QT1'$&>cWDgKy>OtPx%1:φ|"axHմ/6vZk"$*FF+G2ևž}#MsdʨFY)$B hqr綽 ^4^T~ͻ߽Z~Ͼ/xB7SHkuk_60_ p8  4,>z?emv<*)XQg jآ9c|Cx֢ ƛ HGLJXcsQiͼGxC!ydHt#i$ $s8M;9s(_/U?i_:-<(\,j`¦ 3F??yY߽^k9&+{x[>4MOfiC ߘ̅T#@&³χ;iӡF7J7mq㩮?_ 5Y/C#iTd/TS*j( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( cJU(/KLJlt;>s:\1}Nӭ}> M&mmmcXa ( P5PEPEPEPEPEPEPE|}Ǻx:li N#fFv}y译)9€>E߳gQ|w~4hF12=dJ+ȿjW> &hjs+'{WSGsK ;{_Q O=/(+_JhiG%?w4)9€>ESGsK ;{_Q O=/(+f;>W'yqQ'^ W|w5|VbI./A(_h8}E| O=/(/%?w4;{_PTWȿJhi@]Q_"SGsK ?)9}uE| O=/(/%?w4;{_PTWȿJhi@]Q_"SGsK oُZ>;˿H{#mw2u{_NL~f}9Ǖ=ȿ)9}uE| O=/(/%?w4;{_PTWȿJhi@]Q_"SGsK ?)9}uE| O=/(/%?w4;{_PTWw5|v~5XN N:k]_'mPѿq.;{_Q O=/(+_JhiG%?w4)9}"ė t~-|?|sgOǜ]EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\>![q\>![z( WdGcǂ+'r?hǎ?]?@Q@Q@Q@Q@Q@G'u?k?W-cC@QEQEQEQEQEQEQE \ZǭVO˯e~˯e~ ( ( ( ( ( (:*O?=?AI]OZO"3袊(+F<- (?_ ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( />->E,<7Ƭ.H!{o|[ wzōݔ/1"5yK ,3O)^ÍqvWu [YC~>:<(m<uFWW?2?tú5C΋[Yjv pi3?PxZ},Zz ]# iq @[fw$h?fSSu߇ZfW2+)I!T*G7g{zW_k~z7Z "^`.XGD.]ʆ #ݸ2ЃWk \Z _ ޢ"FW:Fo;G 2}d~d͏oWdG?(E˯e*o]'/P=,OSW_k/~ukoi5N &bxk/<PD + = I[}}tt<_f۟̏ y;ErMQԓ:=w%]_K,aU #rqڹ/|"m^=-<3Vs<̉#|r@*+5k;*i_kvK{,KvnK$"@I_Wz\M?W4k/,#C4 #d`pW+m&z=tTqvm(Vda!Áσ^{4i~-ق-IQnO7h$ ycXau+{wueWבImAQJ䚦lot.zΑ/Þ bu]?oH/bXt>Z/W>}(J`7Bmāw7mszW?Yo ͤLm] A:F`Z+6Ɛco˯\jw.łbtۄ+ʻJ=Cko鍴n=b,x[EAGrBzT mhm WWB$&f*cy>=זZƋ}JXuXnO7 96!veM(ԟҬwu(ͤ^q[_ Y\! ķ!?+a#ictFUݯo]?=)=cv7-tWD_I-jIDm13 i]nq63_ 䵍-j!UBIh*OST#} ǚRN۔}O.o7e|SZfXa +B%c*Hi_|i :=J<\lϟ aE<5+El3XФx$ H;ݯ~-3Y!yru/J̛a\M{jwy#4ϊ~ּ?6Bҭy OoV6IJzSυAm7PU|iv䁌^I~z%="%މ1Wwכ75@xUP8 92|Uo{_ŚbX̱xuk;ewsԵc2Z##e[/p+vgj?+xvW|M[i7]BnrBXzVgi}]Y*keT rqξ 3zZj7֌;֝^77>P".+tVq|4[I$Ѥb-7pZMko?̭ͽSźVOOϹH ,n?*TZ7OW4MJFk{;PŒ6RC䁒6y#>)k?a:걘ENfPh VI\y> AXe5Qikw*Y*dcB_#z;]?h{][K#{DK-L ybKF9KuW!Xvb氾7|l3iqx,"vy&Uqq=Yx@Ծ$Ct.' $s_^G~nI,xIG';C|= 'D& ocڎL/ot34sT OC;t3o%xwKFnķ$F`.YCt$ޒ?jDm*!}VPłɻi #i56׈xo:=:vPZ,W3$k:&It  5u%O^Ԛ?R^\IvFm%a pk/VOcwE;=OGoǎ׏x,O(ogTŠDgO0E"C@qFr@aZ7o\|/ksara'ϗhȅ A$g4[4ϏCC/,N+[kK˸㹾/m RCdyHMm|;i;gR\[;[|jŗ\XwWاP|EO$VR )ͼT?x2Fx/zF2=#PnjO%7̑vF5hxm,X;B_M~Lom}h5˻<-R!4E3C;c}k¾!/ ĺ톘.`!A2:py$t5umIdŴhI,O pFd-o.WmXx0Йwe,ҴD Sy vP徶l5Z~?gUxHPcJHKIh x>?V7z΅kH`{Y2nB)_թ?7ҵcXAqʍ74脿`&͐xrT5\Xu=5I r-JL1 懣K~:iV[Z~)xg^?hZZr{K[e9nN:J>2xBO >8xjIj^X1MOAe2#qI迮_]f:%ͷoirC[[b'9 3U>𥩟!2]_Eɏ,o@%'웬xnDt$_M 2.2?Ţj#^!ƟjO,.H (#_/?xDu;{-WX.b%%HMN[qVH8XzG Ŀ+}1X^]Iiych?*ERJ2>Nk'XOO#̈19N~&&G |[m];>}Ӯek2tТ"Jb'>Oz5{oy^.$]BKiUhHf*ppzU< ^1 F|PEos4`w#nz7ybJ G߅4jگ?m_K[uRr##=j]xM&PY[ؕ~T;<|_/7 ='DTgs -\,T(Pbu Q"k߳h~÷~ Ρq5@,$roV$m*:)]?}SzR:ށS#$H\E2 a՗>oAЍx [%ѵ"KR4F//iC߼q  iDEEPPQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV߃>w,i9lyyN}krף_z_z(_z_zxoW1_jԢ3 kgwg8A!렢9A!^ (^A!렢9A!^ (^A!렢9A!^ (cڴ^ggn;T_ i?6o˳8}bף_z_z(_z_z?׮ף_z_zQ?8..quA椠_z_z?׮ף_z_z(_z_z?׮ף_z_z(_z_zxoW1_jԢ3 kgwg8A!렢9A!^ (^A!렢9A!^ (^A!렢9A!^ (^A!렢)O=EyvOUf|3:ڶ(_z_z?׮ף_z_z(_z_z,#~PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPE?W{ 7|]7Zy]c[r Bݶ@8Kc|62hWJ]i]ZE|''F<9cTz^ui0vSi[KfmQv/-kuoþu񆥣4K=v_l\Ip3y"mt?;!#ki< x$t{5f>WRեwV7"h?<i/ޑM Piw]]($ѱFdd4ڿߊ<+O|BGu5TvLd ݤF?uM9$ƅI^zo[}<?׶_XpCv -y]@ q<Ixw^(x'~9ĂXŹ-ɷ4ӓQq#➵i |{:j6^mw52.dɍy 9χ_ÏMxK7}I-mV̊F_5)q989MJ/tKEeZtay]ܔZi7E.Hm?oo|i7O>æ;quYekp^!T\goxğ.u=_] |05VVvZ{kkOAY8(s=:-iɾl^?VIەuRbM.Q5~H-π<5Zv7 /\|I# > ZwI,H1D&6]RVxy%a #|ψ:ߌ CR[9K`AK>VGr[297QR| x5 U.n$1Ej_͑HCT#8Ux~ `k~:Mz ZZtc,q"Kٟ>Th҃挬NZZ=iԊJi蒺rI{M3Y?ldѿgvv~0/ZM,x(}ᑍn3,8tžVo#v >xnm׵ ]m:C{o%2Kjܼqď+BD^ZGß|e|<]Þ!/u{m{Nld̕I9$x򈑑0AOS~׼/ݭ֯a[\btHLaI3.+KTQ5;]u{qЇ-k6[EjIEIiF?l4 ^ ZwM/HƵ{g6o6I}q4qx!{{KtHIY|Yx.K_ھ|GD&֞wkLqY 0]<'°׉|=WxbԴmBWu8uYfRA +./[=|+oI Z=lU*Msn̅] gIer%'FOmI"^`xR(NFQN?([E}>oSӼ Mč3|KMkO&^c bgi6?[+IEUz/qfc(6%dswG~!N槯kKM EEԣQ nh\Řp厧?k/ϬxZ8ak{;Ry0ӝ6@_[گZ4&h-z_NB,I!"8e=r+h~?[F4a5 ŵQpgI.@? rB|Vv}5֚}*{ERRwdOho  „jF}k^[ayTvWҾP{gxCOѤmpd;t[AGDŽu:WYNm-a)6iȾBс"ô,#IYJkzƷX{ mRBMgxN恇fO/xW^xYҴ? o$wױڋf^q'烍59T]V⫃+]RI-9[z:;_W뿶O k_?KCQSA%PѢJ l *4.4OFƷx?C=--ͶdHnwѫD3:8' YZjռo_Ƥ狼1.6a;`WQTjp98YQL((((((((((((((((((((((((((((((7Z꺆{&8Qd[m/:9#ާoG\T+⯄^?kQ4O:x==b/5+}Ϙ8 Ke1LHو%I[8 6plTUM$t.^-_'k];íCF6,iV2gΖ /yT ;%EU+]vT7 w#[\x[iq!Zj1Eev${XUr\^/~G}U Q8i-OUkIGե>7߶ͯms*z< տ܏mP䷐y*khMϥMf`k.MŅ_iS_;SM F+"JtyFԤx'ƥxs^[9/h-ki--YeEUL|Ji+ٷz=߃_5LiZ^ZIx|eGca{ss"YosPu)Γ~uf:,nE6]=}t;; 7ixVB%-{B 2noҚ9!V;VĊ`ͷM+ |!4oxPQ|Kh5-K/$uldT߄?uoC5y4_m=[+y6˿Ϻ(V`:ǖ1?SDa %f\ڤڦ"9V9~q[tVWm{[pL-5FH떦R}t7{&ׯ~ɟ=&Ю9'$ 4iL3_Q-;CO_^^P=Wm*I->_6yfʥTIF->&GxWI񖕤jS^S&5\@T mpF5*R~t4V8ySJ1m\m_IVWj*)~> j΋SXkjHLJ3[̛n|ၗb|}⿄_ZѼ?:7Hqtk/{HZ.YGH9$ [ZDzi~?hsaa{S^ѵxfM$o{vE4R,SV,cK{6ыL631%NW]M]JkUZ;d=)O%8͵fߴ-RrM>Tu/~_N{هw!\Շ:L37k7nndҬ >m Aa]c ?\|'hɄo4aA@[KkԒUQ~wiA h˫ZXjwO@wp"GC(i7ς?2]5S. gOY!eʈ 7FʲR+U:j}ʯmvG_ʍ^IBNRNɽvu Sx\g][Kn,Eio|bm>9!w底Lj:_FgA7ނ҉u;9Nkk$Cb7A@/RJ{|~ xVԮыiTG0 a!j7?5׃U'|=+zų^7[Hm=4C"S.tM%J.ϧFK1mz5(R]ݥҍmymx ?_H4o2F{oxbIk&\YFZ+[uHxHmv+6]x^2֧[6_jZl:u[( MBUaZBt^/څ<x>Cum;B}[i,[M$tk;Go?mY'W t/+SKc\7Xk^h~[}~}j;Rkoq:ˊpM; V!Viek]]ջl%$M[[jVI;Y de(4SXu$$ C < u?O6խ;pd\MݦۿdY^մ=Uo=QL63]4%gY+,r@/~3~?n|+[xkN/hڊmKLPƞ-Dv9&#oйTҢQOn_%tQņxkH͵iigpZ]j5߲KHw>.? XhXki xّY *1O#֗ ot.o\kaA4z|mHAjx'O3LVԮ}(In-vd~0D_V4QoKm/1eIjwI쓴kZb(l۪`V=޺r廷i7TLc+Sa Ö+Zy?a7YEufN&dl%̸nEv o;'kþ5][O^<׶!޿2ARq+˄Dox:o wB, =~?1֟n<)ωz]S\,nMƒmWiF tRPԅw$_\4kZDnm((&xOfANiKIJҚiQ]%񽕙nj~cόg_[燴5i oV?ı-R@'Nz_ov֟7߃|C ƞGK f(_OmZiByD=Yc~x1th~1]^5VmXVHm[L+Er$ð>EJwn+#Xc4:-H.D7eeZ^V[CcK㛫9mXmZ_3L.ꗟn᭮PA5LU~Zo?d_Ph ou=:T!-nE54NJƊIk|z!JY|To ޶:}a3C$b)*i\Km4R" ,2^1&4xÞ+mS*kڝ-fIXt1[hPrrqWjEԿ8Ro{'׺ֶcgv&?@t}\aΙyV5KV/B.)mJPCMKᮽ P4\. +՛K6,hVrD'G,ʼnPG i?|^|TWEvm "-t ?h_^<' ~ˣE^a#Wnِ+Y{'u%[+hs׍,]GNOZKKz= @>gDzH/|PɭamMbxZToo .9-ʴv;z&+TQݷk)/u6'~i1~ "EojF/W=宑+ZM6s'c{ˡaW,M[>'~c$,n.潸Gi縝YII&?g+Zh~![DIã[KCdyh3R]G3{'Fojz˝KZ\ to+kϧEJ1]lXHRDZs7$^2i#J>O1I˞1ҳJ }8->|k[1XF:֥8xV;lb_ge 4`my@b׬5-o.M6jsX&KkbwB(xkO7^#m8/3.u%Xɑ\[>_ x7wGNj)L%8ş4Ohߴ /zj]xXx]ht7KSOi+G3 Qg&"rjn &R׶]妗#ʒ^'7M}%ӣqi{ GntI nMֿ)ELJ@Xߴc+"m^Z6jOXޫk\H^o6R쐂#7$K=񧈾0h-Vk_{/Czl]")d)q%^|,Dm_>" |W/O 5K+[? 6.(V&6h1*,dE5 |*m[=x*#*_>sm;6 难hZhhZ-GE6N{kHh  P|Oo?ZG]O2P,|Ikr] 5QM&rH`5u~|\⏍Wz hφ'Җ@犑umٮ],P%ExP)*M]kk_z}ٻlD%3Y4f=I>xzۏx{Zw:vXZqI1\Tm|+CxkMҾ(Zj3C_G6ޗ}ܢt5Þ"wtuπ~wih兦[$im/-1+&saEUSk:wS\TxA6ۙ"fN+k%5}^Oh&f[ ;K@-dVQ;9'=-먬(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEyo7ZxcN_Z$ƣCac@\1 Ӟ>HS/3ï Uqx3,ڇlt\Amu$9Ufۯo-[ĺOͤxUK"Ԭv6Wm%R0_?x? s|;~gKMkšέyxwJXUsGI*۴J;>a?*-]t6N1Z}W%˧ھ3/޿~~ҷ 0ѵ=.Z-lcfԮux-WV`tm*`uOW /oTP5mJZt=F{uPɔm i{y|9W ?&|V0OU~s?世Hxxd$F>ᯍ~ \ouh,kN yG>mdמE|O%eZtk^].ezxb? s{`G glkaI%>CK3XkzfSO..Id#))&9(;ٯ&{$ܷms|хj䯥dG׺AO=sË=k0Cu>Gu1")l2G h<jϋk A?|J⛟7ѯAim/ &wHvB+q0c8l+}OIY>Ys> 44o=5vX g ƍ# 6s+&f?.70Iztt>C5Ϟ7SM̾&4R$ܟF;׭';|BO]'EVaG 4q8>q!im%}9o'MK|_eF.[\W:iO_SzJ6W7mK{y†1<ʮ0=jߴíF]!v7v"g:mSTFN>xf~! _ t}"{,u쥹mR]XFbdþ'čg㷌mt4ywO|T.s .Yζ[C΍%]bQ9AcUAwM~qOM_fwoi>?ioLj<lՖ]rmo!y1 (T`U.xv_ itrZY "`D2YL7O-! (RDB57x$|ݷtkX4tEo(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQESe`fTD(&^=cZt_xM֮kGmucg2Cb x5i'Ȱ^t̉k%ޯFpMeYďi$IXmbU1 [0p/9RbRI Bn]3mF!xRi>l3}S^/j|{M⳪u=zZA"HUms +F̸O*rn-75ύ~44i)/ٯ:C)&YQw>$D`I I{y˦uӽ_ҊK/Z/>5t_MCE5+mC!.%2yҼ|F'U.I$Kx++洵Ҵ,궆Fmd:h˓?Wn/\ a?ieΕ<7V GG{:ï:2~C{F>%l#Zy$ye,=Gvοa j٣~x?4/xů![1WS5+-RMbtR^D?7kDgtyu?I;ugE~h=ūx&EK⮛XKͧΏ}ooq:[u֭9X]M%#ڡYُ|2x]ViሮcMGw橨5=U,vYZ(icmgpO&ZvlJ\gu #'~/h?/<bЎEky&{{/>H͓(S0i<-17Ľ^GnutIg4y&Yn)mTmeM)6嶿u}oe^a%So?\={^l~_8|F#W OPEgN~ SR"S%Gl[2Ds/#X̿ƭT}c|GѴ5o^]?S\q[Ym*O۶RK/tWz~5MEx Sax$W5oQ.5?LIHmۀlE# WMKv%|=׼ CM?Tӵ-mOY[mb; 2͖Hȁ]c&E/w;^_l];x㕇~|7F]-t;<;[n@>coHc.^9]xOH*ǭx>8?[7Oρ4+Nf/n.[Hp)_%%m&IJ+ocoï9GI0ڍX@5dQ) +qWOf⇎l;?WŏMk 5}Nu #M[auiC.vOq5As3FLʓQv8WE~R|2x?wnx~Oxo~z}݌:$p4]I 1.ҾƐN |oHi#oO생\0^,yۧ׮wdS^NSkŧ~3,QBd$GSaOA֤2<3l}sO58%[hYDFc|G-?i?? Omŭ_T} ҘAdǓkEjxw: KrWMr\;o?e_^>'F -&xZ&Z6-q} tďs^Er$rvNdSW/~0㣪>|?oZAamVVIp<;B7nD*(]|炨j{^ourxBƑn]kI_KjoSK7׀60vn7c5_o|O:|Q~(xuO gTntM.qK+*'w)hĬ?g7-Ş4sh:}CO \Xk(2I[,j\\[%,0S򿌿n',QM%Ӡ]6$P[Xe糶w!Yl75߫VW.Ny_*{ i~uO+?RYj߈z|aj1iV1OlțjNMET {*~_7gH|GuK?4˩Sx,Lqx}=md-nֽӱ$IQӣխv>梾cO ^| mWᵆPҴ>Y-3F0~cmH? o_~|IxJ;jnl4K EҾM!|#&VK6BJΜ%U7ѿT;z.fq_~\e{c *v 1FOrHw&ҵ=zaY-dU7)"è*AWO{B|yd/㟆s~!JD[{k$lZHb`ЉHw/|SOj^ ?Y21}AM8BQ?#&єSgsnn_+OhaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPE|v|11rk.> m,02O45e22 adR$FE 2\f/Mkao;>63lyp!v(@8l\?i#Liz?5 (5[]W^ܘpyVF?qD`'9/]~zz+_kzK b7pr2:R<+&w Ǧk|'_Sƌ.K [6١9k1#l;Xwu^1Ǣi0[;LՒEݢfPGw$!w+EY6<xSNw+B ?hcDY]|5{ouRhj4r61 lun~}wڟK"+MYtdk.!X$6FCpm_ڻ6ņu]#RC6m;:6\@?<=wׯ?+|SqxS6XCkYŶ$(=ȞNG! tO Ėz!e-jf.@7ve"+6I6 íOG cGŏizKӴˋ[N84|,kKeJ wm[p (財Ye=AƭU(F6zb+㏆:xzXG#Zk-条[Ceuy{-R R$q c ,`~1x#_m+\iWş_F_qxYBMǟ^P%`1^u׺Z7INM>1Ar8CFTTdt>OzOoA S4N J֛s%5KtT%ܙ<)- {j>6~ Ӿ!jw|?{qd!VwhbI'*2kQr;|m}6>̗[_QҶk>u?,<#kE|K3V}gQkQke!;\so,hgUg W+o^᷅-umgR摯s]o_ðY^$3yr>Ji4I?QkiЛJ'~wٟNjꤡʒ9J<7]ۻ5?k| o7_kާ;MLe9m ;o XCzis 4@{+Aq-LϲG.D yu>/_q}6/Q ĨSM VB &?|5$YtOt_j+e`gZ/'V{$;Fe]i_Gx 8|1z-λk^^e?# xFë j-޻g6z5#XTO{feᖣoKa ?Zpҵ{l䶒o,olզD.|{@:'|bFЯ|Qq:mepPJ{~ۡr?k;Ϫ 8?+~~^S-}/{KńoymxnOGZ;@ |qAy~oVm:wL|̆kTuXL r6Eq)ϑ-y_{_1v]WKm_t}pP rH~O{x|%cSoNwiuu[E__Ὰ3oELvXS!_ZO-3M{WԼ/tb]D Cl _.G~ds&_ICqiwWZ[mYu#FAukφT|DKψ>0@|@Uu⯅7E-<_w`i667+os% =%b]ēF'uQ^c_3~ѿݎqov&=s_->|5cþ0]Ğ10= oIeu-6hy!PW)?S=VĚ#7G)jzRƗ><d7<1)ѕZR8ގknqrodtx[}go>9 h?ExQk ]qj^WUeZu2öc,Po |gx?V4o%̌#I$34J;ğ ;tM>¾>gW|Z~Mamk_ PXGf~PH( j\1PYxZ(DEP?cᆏᏈ|:tV ܶMm4f9QfH#0܌3hvzm[iPX*(=ZÿmC^%oNFFp}E:((#b@(UQQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@sV,bԮ-2J[?QӦ]XΪ˹ +)ѕՕ O\į:/O&{a{ ...8a5/#AO@M'~WbiP|SxIPe "Gwl"-IpHA}Og%XMX`+ cֶ;Fxv떷ڟI&Kt<ęT1B2ü0FC8o]~nyo-GFWm!+yKHtGSJEWŽscS +­XkQ,?d(>P7W 7c#'U]zM[[ζY {A6I$̀7#81P寅tB+6Ӵn=CPy]#<1o7rWn+AG^+]^kV)?K.kUWLStk|>w̯?^#ƽGŦv|:ʹe1xӉdB21W#=1e;ľ1!=ciV@,nm<ZLbT8h8wf XkM [Y!fA;Z9ەI_Ռ_xses,WWzY7Nm+:I<{ލO֧ խ" tx-B߳Fp89E+_w!w<ßXj{"oƨ.R5@6/^wS'OWKxo:LzM̐Jm$Yhrlۣ9},0a +#,~x'TJflSI $\4oAM<.OּGXZ={gIl# "RAʬ<>h~ |i?lܞn",hBX;lpwՉifm8᷈b~!.Cmo=ƪ;3Xc ?|mE۸QH6e΍kS>ּ-&Imh7"IyxHI]]|#&xOT7gMo(ojƞg:eޛ"#Nb72mfvic7ƽFI5+RAiigk#gƌp*9߾hNo=/Y|L];[wk|4۝Ly^EZgY|lp:n7k_KI7w|^[?J_ ~.ҵBgNu>Z/XL!Aptm2~ +~$]|,~\[`,ab>Fպ+Ϲʴdxph;ZN9'9YIɾ:s׿?+Kd|- Ɵm{O (q$=VLBn%;S ?`;ʼnu!i}_P#?JCCifBnh@2z7r7;AAlzbd䔝m}gP؎۳IcYxw5-%ɰeDR"ZMP\\umpkǞևoi^ƚ\;Eix4 -F[9m12 }HX)'e6}6ӿK|rn?įGzCn]2t}GUŭn$2reēl;:BR׵J#ȷqNQyk-ԊBDZ&ȞߢK$K[_t7</Cf!NPHV]komq gf`hZu޻ Oq _T1MFfUd[#8'Fn)ElKYz++-@~}>XY$ {O=jHnf/p[q V'KWx/.mԟQӉž74f AM\dQ8Ϫ4)?Y7m?%8t.+BZMKic<ᑋGj6ިw`o&o?o4~5OwW6cA ywncK hjb(&\Gg"ĻOL5[&I4ĬVcOsI H eO&ÿ_w>xM~~Hb[-V9e( ¢ylݑ 9Ś_ĸMK^>&xL-ˣjZ|\+i`Ms]<32,~ pApyFvF:j^0{;MN<ژ.󬤺P`/W4!,B@ E8Քe y(ExD5̜_[7o?|FOC3_ ⷆ;hXVU'dȰ6|U"5<%̗^Gua,%.͕#'ﯓnwjj\\muMz5ti (Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@y kZLMz:_KKiad7쿮xǏ1Νis^FíDfFG0Ni:o4w2nD-t3=nT$PF)vlWؔϳG7O7wJKos~zz|)Z-y[K>k? ~M+^RX.ga78?mB( `U5*BA_zMOA7TԬ #1 pPϫQPJ+XoVO,~xZ[)4պxWWgϏkle0MKbCxV;dR^ȴ6~y|"hwlm5}<I|*enK~Vi;M\gp@Cq mĈ,|A`urt ˝&moA!b^ ^T)Vܾbѧ?e|x~O{Жn0lMG3/a{+ n-b7>lpn%R$ryfٴ  _ { Z(IYX(QE|v*>/|q"l ɽXKӤ 5㍶2ÂP{yxs%xVү'խ,n煢kx~βάKM¾vѫu~M4qMI$iׇtO __jIqcXuV"'azX}b<$8%NnNInhxnJ]@/ex/ߋ մCm2)tc[DP_&j]p._7'㟆d>,x"o>#^IzoZq a[c05-yPOء_<<ͣ~LǵKNgN86mv2/[khY%HLJlF๏ ϒٿN?W[qm7,`oz+o5wV]6$ ,{J%wVuRrWqN7Ei%WM;cW6kNz(>Ho<Z_m;MɨC,3]%Й$򣅒D.Lgٿa~*ľ1MjwҮ۫(o5Zy +Y(G=mhzZ+ɓ抃k.7#~*>VxVo4їL:wGq-`۹/(Ofv=K_;>[j~(ҤĚž ~MH"\:Orn"E (m#VQOwE&h^ψ\]RWYC[i/Q2YT4A؇¾)ž##i^IzoA3D2ak8Z6򡌟 (.$'wKGs*kKu?/,:쳢x{4]'3|@Kfh%svM1aPYUOПU(|b_8*,>xȔaDn7f [kQ6Hh&UtaR2"uc(ᬥ![*5]om~`_.|V>~Ͷ o,)_9e5+o6Gj/6,r^\nЄ>>~GĭoxwjPiQ,pj3-׮֯A*${b;/[⌷sH'{iwoMmqb7/_O>|)s~tQMcIHo[0+T$V5Oڜzvj~LI5׆O5oͨZ5d,t (|]d^WIǿ,?VE]nSQk.'`Xz]__'[]RO"RCQ4||1~ϓ|<|y]oéhhru7`Ois1̇.)NIQ_(1_MݶY(Qmu[QEQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@yh*^,'űqc;]ʧ^Y>2LK/:. l㺉H a'֍}sMwM}o_<+O Lo^!|?[kתVQ$d🆴+mc{DvUG+q}?F72-?59b.usX@ 1ǣjU],u㽷>g I(cdnD8? /ďc{8x^v3x+5 i0ĖSK1p]5ShHV G<{[ܭZ{}V)YVU0g\=~K `wᴋ:z.3&i,eU{Ip:/+n^;'ӷIv E X|}#}3߅kS̚MB88M |vHdPR(/ď|?⇏|QJwP@F]T۫hD̷[X "ɰk _ߵoFFduNpL+pp`od f˪E5،t;hu{̤׋E>Ty -?1p}^,)I+Z$'՗x8ψ?i(~'>߇7ߊ#~&u{OK*- s Wa$-$3⏈^K|_#n Z- sH[!XX/q O_~!յ_ x{Vג=JM՝ƠLrIAY(ć1l 2Y{x4๞&D!u+&%H8k&SzuT*S7G0| _1ALhy+zյo5&RK{yn"GLϝ4DII/ⶋD? 5ȼo3Z}3Eb+9WMԤ_JTKi?8nxZ6 f ngx`y@!;T!9|#|"| ֌HR,9g"Io[+ydK1tu'%{i~ vۑ N7Z.[Qԟ6#:oZ|/R.Dڶvᴘ7_*5ҮmXL1{x G-<)x>KNHȞJU߉!2qrNk&[xSzMGLSe1ܖS@lO_:Lsǿ |9?D|Gbmjvz,2с3Z*Jf_yx 菃O~y폇z/xC>#KK5]'KƎ)L^3e?7x3B&BDkxu-s_[ܷ3^I4xV]>]y, Q<)O;LcwkCk-YK*nVkc1hB3do:o & "&_GE֤&?(ĘvNT81,VުMvdUGuY;?;YfK"Ux3Oѵ Ş'+~7~+j9xÿ1&H6,K6]kqeƑiަYbc'>>|,Oφ_ wZKxrZYXw$q;33'q$h߄7At/'7bhJO677ryoÛ[keaͦV_k}7]m|!uXKjSkv7tnXKibL 0Hok?>7,_|+wx~}?OՔ:3k<(d3H7 Cׄ5a|5_ xnjzy?|]˕얾\OŴMZWo5;i~q}Q"{*8@2I {'lh€4(F2RWmYy?TL+[nxzQEŠ(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((kMGfyhk}1'ݜL`u]-b4_ȴ4_ȵ yϊýRf;Y]]1K$D*C;_8G[?3Qk2UpvB:dx/eZ?dx/eZ>&چhZf[J &P)BK=Vsi =)ծkfRVhbd0J ڏv;Y"Y"ܺM\Hl XA-5ű Z97!$/si>4 7u_˖Y>c _ֶv/Y"Y"Ox iX,NzYU ocK]_{/h9h/h9jGf$n[9E[ipzG9?dx/eZ?dx/eZ?G"X3+?dx/eZ?dx/eZ;ڇV7ztwcyO>ȗ1oC'y2Ǟ)ԠL,`j<3O$p \ۇJo-G_EG_E0j?7սKpIo0O +of| k^J1l9%dER'[ o)rE%v+ J$ĖWsl' \{Fask]JӴN .Fî6M_^kWs/h9h/h9kέh;;[5YU-$0۴2F$*e2GbN\8+vX,Mq4SH8(:kn&/h9h/h9k4BKo+ӥ4Y"ϧт!)f+!Wn:ȷA픱a?0Rn]W_z&;Y"Y"W'#5%gh}Va7%\/PZś/F5KXt4)<99 #9u=X 5mG_EG_E3k j׆{븙maxc1v8RHpEO_7B𷉯Be/n vD%(e2#m;xnMӯ~Zn e$R =pXdc$g ~.bLpe*ݵ`=G_EG_E"fkej-5p $ X ٍdq]Z& >v"ƻ$%ݾG_EG_E2пhKs"_QJZo;C 56Cy%C<+[k>F,%iV; \Y"Y"Tt.%`y9ѮVJ6k{V$Emzl"^j[Ͽˑ|lcq r9W_1ws/h9h/h9k4]O_dӬ5k ʳI*@;</! :jskZӦLEvl3"} ?xcВeb M4-?.Y #_s/" #_s/"4P"oY"Y"&/h9h/h9j(oY"Y"&/h9h/h9j(oY"Y"&/h9h/h9j(oY"Y"&/h9h/h9j(oY"Y"&/h9kd-漍"X˪1X>j4[$B,QEW?uTsEuEznPqUe-ge7Imxs_6o~Qk>xW3Mim,ʴ?fc6JxvM8$wWʾ|t57-%vlpF8|]Gƫc}٦,k5qh|d^}Wɵk?_c)^'Ix@:Gzs G2G壡A< ּ?6m/J}ĥIls_c(ɵk?€<~O^ouHYkk>6o~Q% 8z_W6q3B-/`.w8k?m&} :_<|Y?Zǯ-hKkɭ%2edՇ1kӿm&} [ {*VM +C ˆgN$!<1k!9d;dfBV2.D(_w;_c(ɵk?•\?|}>mHƶYkc/e@ #Zz>u6o~Sno-40>۫{B-$ɑ|N}g&} ?m$Kۻ4cmUG Gq"0譞> h^d?[pNI3ox|%r3N}&} ?mmC*]š.]dGtOމ%ix-û,T5e8+ yL.ll䱍򽱎+?m&} ;sZWش;]7I`K;z1ky`>ǠFk7neʶqF.Tn`6km&} ?Pc?մ-nn0E4.byW* i?|9=?RcSn&k7_\}ceI2 *9潗&} ?m$Nk}#Ⱥ7"2J}c'7pqӊɵk?_c( 3FtP.DxOloZdϵGM[߱Z v$\쀟3+ xgP..ld{gMb/}kٿm&} 6~"|͡K]^ٮg˞6Lƨ@+dս΋ )ƠM} ώ'T#:q^k>6o~P=O1Z5871 REs$9M0bʂ9|;}%ΞJ mJ z_c(ɵk?KwR . n&i(QI˟h𩼒 /n L܈B"&} ?m-6<m|Aw\YgX! !x]jVRX2pD%̩n >d*9 g.1WdϵGM[߱=uax燾 xsIf_>#mT,Q硫>#W"CN.IJ)O7R k&} ?mL}U1 >lKp;±4as&]]MB BT1+Q>& ,Yf;Qg/ d6~Vfg zM[߱dϵIhW1oo-~SNcYVw=Y3ntL3sw-ԳISsI+3u6o~Qk>&} ?m?m&} &} ?m?m&} &} ?m?m&} &} ?m?m&} &} ?m?m&} m\ ?mh0T`0(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((/$Ӽ5YɠDlEEuAOdesc,ddscmmmod(cprt-XYZ q0DeXYZ a)(XYZ #XYZ Rsf32 B&lcurvcurvcurvvcgtu ! ! > %&s "]#%Q&(@)+5,-/V02635 6}79M:;=L>@AeBDEzFH6IYJLMXNPQ]RTUTVWY9Z|[\^_+`Wa~bcdf g/hTijklno7pTqorstuwx(yIze{{|}~݀.>N^oȑҒד۔ŢfJ-ǩ`=ϯyN$дn@޸wB ּc)t7¼y6ůl)Ȧ^ˉBͮdЍBҠEԅ$dקGي.wܿd ޭSNMSc{1S ?i5yS&r:c ] ;p!AL!Y"$S%'I(*2+-./1[24(568C9:@1ABDEUFGI0JmKLN'OhPQS T[UVXY=Zm[\]_`(aJbfcdefgij4kTlrmnopqrtuv'w:xOy\zf{z|}~~pdYQG<2&ݜɝa<٣nI&{U.°rK'ص`6 ⺴c6 ݿU%ēe7ȡo> ̞i5Й] ӐBի_}0ڛPܼr(ߑEi @gHq)YCw4n,b Zk-@[v "(.<R^T !"%#5$;%C&O'Y(`)V*+,-./01233456789:;<=>?@A}BmCXDIE8F$GGHIJKLM{NjOXPCQ+RRSTUVWXgYXZ:[\\]^_`sa[b:ccdefgphRi,jjklm{nRo)ppqrsltAuuvwxryKz'{{|}~jH&߃{\<ΊgAҐ_:ǖvQ+ڛe<꠿qL%Ҧ[0۫i?ݱdB͸zO"ǽtL$®ÎnO4! %Cfҏӻ@׊T݉ +efK~ndin6WeM((!GP T93G*6DSdu6Ro>e?l/a@6s7yL 9 % v  s x , ] O^?#"2Hj'U![ !I!"#A#$%R&&'g(()*R++,-a.)./01`2333456w7Z8>9"::;<=>?@ABCDEFGHIJLMUNOPR9STVW^XZ[X\^_`bTceGfh@ikQlnvpqsXuvxiz{}}L҈{ohtܝ9F]Ű$Xx<ŘN̫UӪGڕ޻ Q8i92y $/;HWgw)D`}$JpAn2e C}8wEh  S O Z  p / c4 yY@/"%3Ie$X*i  [!!"d##$%7%&'d(&()*v+E, ,-./Z061123456y7l8_9Q:D;8<:=;>ĸ:ˆeԳG۟IQW"\  /BWoBk(^"a+psn"}< ,  o S = 3 ahx I|ko$O F !k";# #$%&q'G(-))*+,-./012345678:;<:=]>?@AC%D\EFGI7JmKLNOOPQSTOUVX+YtZ\]s^`)abdSeghikllnXoqSrtNuw[xzk{}$L߅yZ[V R򜋞B𡥣b)lEõpM羵u'ň3fqQԽeضE}ݍނߟ sX(zX5Z"desc Color LCDmluc itITfrFRBnbNOesES,fiFI>ptPTNzhTWfjaJPtnlNLdeDEkoKR enUSsvSEdaDKzhCN LCD coloricran cristaux liquides couleurFarge-LCDLCD colorVri-LCDLCD colorido_irmfvoy:Vh000 LCDKleuren-LCDFarb-LCD LCDColor LCDFrg-LCDLCD-farveskrm_ir LCDmmod*MrtextCopyright Apple Computer, Inc., 2005C      C  _" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?!~|ܾ.E^]LIGގ9*|‡z|e-lj6v7I0°ޯbcI^F,\u h߶fiNQR %eO0!H`ߒƶl]{m-ҿoϧWWiRjIGk`zKh ʪ3b[> x94BX讂4ewb)oBT:͞濠[8Viw8:ƞ1I6MY*>Z3 v7G-+OV>˦cE %6R} ,eKNV۱vW'+|WoW4P.q˜\˯yu_F,ZkYk V!i  93o/w?&e^_U1$mY$A [!xj%nۭ陸&>}Z/3{z{+Ify.D'8c3>(|8|MhZk|1O̍%]UH "[?<%:fk }7eY 1Vbc` pj5Ki} oWϴ; Kq=nom'o xK?Xi171\mT7s #?&T ,cv=τ7Þ;Ҵ|Gn#{in(ܖYCle`+ɯM_ϝusgʼn<$#%fg]۲AxwYxt/Cn&7W~V#;듛ڿlF4OoMAec$Bpy$6{_i%xw-^=}ߕ/򴞾Og=&?Ufexa9k:^ $; !oWLSh܏+sa)[~$xP~>e@Bc5ddY$vqA YKjQ]o[ҟڳu~ڗG?s>!q WOko.yF۰0bc?d$M4?zޟs$z -;[nV;mت.&/;9_RW_.?ڗELEKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKwGGPKw\o7kkj6BCIܰ"(bVq[^x#U&}/òhi[jmY%?"/13`(@xGc+c>$xi>HGF;MCMӧW(ˁ!I$ >8ω<7Gmx^kwHJ9dSta ĸ>P$)mo> S׵y} x-]2V jJ[+ Р|3|,񕿞ۥq}{v 62qN*׉ax~HRy7 1^E|Uؿ hWue/vQn.5].TVQbHqҽHHHHHHHHHH"4ۋǎ࠲^9]Xt-^A0 qJQ hj~%Լ|Z<qW5lsc3*̬WEK a$_F[ ]q%br,uvX9r~G_?f_:ǿ߅.zEkxK?+ϳy[Eh䕷M\~V+{4N!J}Z#H?ͫQ@YQEyq~_'|]&Y|XH?ޠ+푪kP4d뺍sͭws.s*Fnt#yH&m/Vm[^!"?xլ&8i>0iv+3Un>2.<,j>uەjOoƖBn3į)=3 m-dFKCuܽ?@h8 Tş(߆~/KDVh]?SVݵ2(K(HY Ev#_}^_ӵ  0nE`WMod#%Ĩ[)6W 8JVG#WZQ[8,+RoE eS5U(wi3{^T5_3NO>6DE_P7jˈ4(xIխu.CgA$S2:H 9?afq#h "Hh1>cEMv~sL=V[ F9TY};,?崁h#*|ି\ZeǪx7Mm4Il٤k-M %RPv?T^,m[\G5=_VMў e=* ?P߶ jqվ^5(N4׷Inmmw#LdhNO[> v~,78#vځdm^ܪ0f4yjYA *_uWH͟Scڳlbws.Xb%0a _#gk'{?g 2Q(|)Z=ltS̝Yt`O/'ƿBߴ?؟i?_H7xM>A6lP c_/ǿOO~%yAy]s|nDX)e[UO4oj;U𖋪4xy2fm_QD0PP̿oO/_}C ]_P$k6YC-Io>Z,'"@"e0gG߶ 瀛~n,VsA )su{&I7#;m2XF?1P?4O@_& ?x_L!yL_jc}%NW +P~Ծ<>ٮmbg ~7gʏgxN|W|k Y5K?{@op_ě xC^BMTdܱ33Ss(%N+?ao۷Gjυ}՞tYV09\)P|3TRK,2~$WEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_/m:T^d6ig*/@So$_ sfը m$_cLڵs?/%ZM}ukzy5kk`uI0A*oH_xK ;ɨ;E:u;6VQ5ظu[xe}GH`/?1Njw5b|govJ_0bE||F04#n<9wq\vRG|f!BWƏL7|U *H6Tj٥uAkiܕ67o!x:Co+OYm#zu)vGZ{;ÿ>9x3wOτЮ!qd.nmB٘^K,kAPJ)Whߊ/v`$C[-HnxxyG,p]~moi:n`=;} d:d.Mg&MQK ?1^˭t:{mKLOo#!]> om~վ"jڦxRjwNOr[l*8]?>?}ڣ'_mƾ$}|ɷҡRIdle<d˓:(((((((((((((((((((((((((((((((((((((((((((+ 'Zcʋ1ZE7 m$_cLڵM|+V>((c{x].4g4f Z6\1#(bw_(w>( w_(w>( w_(w>( w_(w>( ?2g-ɯ}d=ב ܝ:砬ڏǏ_;~*COHu;`%%ĥNUd +Qw_(w>(*+Qw_(w>(*+Qw_(w>(*+Qw_(w>(*+_>,i~?|G4}B[y %K]`s{Y'mZV7{1bhپxa 8t4Q_ŽEE2C@aQ_ŽEE2C@aQ_ŽEE2C@aQ_ŽEE2C@aQ^='^ 5웯6ց;]Q8gsRzzi.slQ$ؔʲ ~_a@E|{ ;/;_ŽEE}E|{ ;/;_ŽEE}E|{ ;/;_ŽEE}E|{ ;/;_W;S. qEk80JѰGܿ29q@Wǿ2CG(P?}}PTWǿ2CG(P?}}PTWǿ2CG(P?}}PTWǿ2CG(P?}}PTWǿ2CG(P?}}PTV?;S. qEk80JѰGܿ29q_*ŽEE}E|{ ;/;_ŽEE}E|{ ;/;_ŽEE}E|{ ;/;_ŽEE}E|{ ;/;_ŽEE}Ec<xj}WSC<}6X5(P?}}PTWǿ2CG(P?}}PTWǿ2CG(P?}}PTWǿ2CG(P?}}PTWʿ>|XSiPjA¢=?G|eq">¢=?G|eq">¢=?G|eq">¢=ysƗ~:O-庀W YmePF<TWC|IVgx X6o0XeC: | ;/;_(P?}}Q ;/;_(P?}}Q ;/;_w?_7kI)]";]N%2*(S*yQEQE1ZE Cl~֘v6E1mZ?H?ͫQ@YQEQEU}[AW?_VUrh((((/?jo \j_z_EPEPEPEP'B?? Tb (((((/?jo \j_z_EPEPEP]ƭ ]ƭ EPEPEPEPEPq*?5q*?5EPEPEPEPq*'q*'EPEPEP'B?? Tb (((((Om1UƓ![oPQOЅqx@S!\}QEQEhx[C]q/a@Q@Q@|!?dLuֻ?Qz_u:k]fM|+V)/93jPTQEQE_VUrjWտs\/េ.K+3oH#73HEc.d5­'2X"QC%Kx 脐5k#JnKKw .:~Yvov1)k/I᾿4jmcKKyo7HZpfynVVcל}omCve Ժ5o5-[#f </Oށx+UtuUk.`2Q2a '' G֛g[*Yy 6ۓ#4Xh\?> ?,|61ɭۭG /w_㢼)xtKSt*402D8Bn'@ VVr<|oN5K>P!,,3)dNnRm* t;O _nGr"X/n1on}Sv~Wd'5?N5 ]f KشѼ @'$"?05Esh5M2]bo+Ŭb2*HGq7 mzú\ZY9L8I{91hfDq[%{/}[Z[1g K q:_sx~Xjz%ZMɋJō?`b'.HGk{8 |3[hS[yC,[1,gLNCv[}_Nݴ', o⛻X-l--' 5۽Ċ"HTT,G[ѤLJ+mVXAms*Nt۴x$h& ɖ3_ggTfFTf2J ">ZVC79n"hh!pd =*c{+=٪+rͪǁUV??S(/ {XLtD|5&f7;VyǮkQ=h6&EҼ[iu#%c0ڡnc 8->wum^G@On`  =I}s隓=4(Moq,#2 WAȌXa>S?Vt]cűuZS&'tfo%cV###5wŸ.)5߇+WM[ )5DjhrNbEweMu턶ڽ//Hcq"ȋ!1bб}^-u!; l)Kczx5O'\߆{mO~?;>/Fgm =^Ddf 8[v hzR^ yF>8WwAn\$j6"'*@M%GCi|9oxJV7%9`YVVVR|xu> ]w7+vi{߂nW/'ٌ63Row|}j Ox_W4-&IѤ 9vI)" '=DPmf$|;*srhk[!躼SY:oika6Hœ) 63we]kI𝾷ya#CiPIDlaj#>,d6@޺i~*wrZ}A,bHl`[x#=Eq|t]5Ub|ܬDjb Ua+Og,o~xtˆX¤PG QFyٜ [/-cP>*̳ibyRBO搵}=>Lٿ˟:$~׺͍dAYYc"ExYUAQ^Km̏"7 !̈;r6*g}S^*x_xwQlt.w],ଗ&b!:hS 37᩼;~yn>99+]-m_=v_9Z׷z֩ǡ:\K#-ԲGXbۂ mx>/M%ZΓKm4QUe< e3}I~æh:veѸߏ37;qr+y_}{~϶6'v|:;]V/W-մ[$B^/5]s[$Zi6]VTR7IUrO+~0|0"K%{Ncpcʙq rr%՗.6Ny@k? /xbF{ Vɜ5D]Fu"TddKLu}]Ϻm}v3$(Og_֭/5<_i xj>Ewy/"h !K_]]`OGMGwykhn+!rZwmۧm۰ֿ>~ZoWЬ$@ˊXpXjH I+>!|IaY%o V@BLzuP%cXM,M,i~vo웤|; FÈ\Iqs=zR2RARݻ~/˯nӿ]=s6zVD7W(M"ClY7GYm@W:7Rqxz[ǧ\znxf)xۿ>st?ā$Gt^ŌKc,4k0/ba>*=g-/ \jh#-p#W$:IIm_޿KŠ֟{_&;IkyM24eFUe8=wx@S!\¿ :N,LLؒNI$@S!NVv< *':sֹ:Y5~:jZ ILuex+k"dʩÜ2:=WEn"$@Cpw2&>lWg #V4uhA"bvD 09f'5S 37᩼;~yn>9*nKe~ kRMoi50[Hp$HMBpy8~1{4Eass2Q69iItaЬK?oI~Db u';+-:h4dq-]6Du]qU/g}OG }x]^tM kE[41NPpĝjKiho ?STh˩Yab3[FTXa83xGW/K|&ܒ`)A ~z m&i-:uv?4qL%RT7* e {o'hzYkg:|pۖ JHxA8fwOЅyNoڬY5na…;޽[? ? 5@5Bw5sǕx9ΫNзoƕU/MDk3[<8d $*We j2,<֨bZ4J,krSg@C0A\J5/IŮ[Ť渻؊VQ;BJ 0 4#&jimcnLE=i ,YOC %FɈP2]s鿳 m'&W>ҾϦKky5i&c+y҅6'ns;]X_ln5k4ȭ&ь0ٵ\Z3;;|rUK}m?DzxSZnSͅiBFSWq\?"5ɠX/?F^ܿO_q}_q}?|@eh?^>/?Aϙϴ  ?  h?^?|@e3$^ܿO_q}_q}?|@eh?^>/?AϙϷ-3Hf3>ޙxz ZIrҫ*H'|@eh?^>/?Aϙϴ  ?  >x>?h!]6 ? o?^ܿ gڿKK|{_9-?+kx^%ܪ,ŝ@U ܓzw x~Re0]nسWj+9zڋ{)Zkg5k-?  ?  T6oQ 9M3$iϙd&z\C(&z\C+R){yPj<[ώM4 5@xQϙK|_{u-HrѰa9I<3 ^JOk6^h)YMNVhe\+` <^_5.2/0vqܿ_q}_q}5׿a n??5׿a n??<7_/ Sk=.?k=.?& >"G& >"GdžY}b,gKK| Ckq Ckqῖ_r0X/7!6G!6_,k/tk/txoܿ?,7_}ehgٚF1SjKYWo@=ǽ| Ckq Ckqῖ_r0X/7!6G!6_,k/tk/txoܿ?,7_}MMQMW?0]0]e/ Sk=.?k=.?& >"G& >"GdžY}b,gKj@.mBBȥN:Wȟ0]0]e/ Sk=.?k=.?& >"G& >"GdžY}b,gKK| Ckq Ckqῖ_r0X/7!6G!6_,k/tk/txoܿ?,7_}MMQMW?0]0]e/ Sk=.?k=.?& >"G& >"GdžY}b,gw y#)S#MW?0]0]e/ Sk=.?k=.?& >"G& >"GdžY}b,gKK| Ckq Ckqῖ_r0X/7!6G!6_,k/tk/txoܿ?,7_}MMQMW?0]0]e/ ]-8+1Y_K| Ckq Ckqῖ_r0X/7!6G!6_,k/tk/txoܿ?,7_}MMQMW?0]0]e/ Sk=.?k=.?& >"G& >"GdžY}b,g6I#yFXc ү&hX+%zs+Mu|E[.Mu|E[. ņY}ϩ  ?  g]{]{c,aa_r3oBm?Bm?¾Y^_5^_5X/Xoܿ_q}_q}5׿a n?_zDž9jzgӭc'.ʊX@3q)"F_r1 F_r3?Bm?Bm?¾$ҿhk]wW,X] ApAXov/?Gwץ>g/>&z\C)I#yFXc Ҿ)ov_??FY{hץ>g/>忲MFᜰWJVo!6_B7;G/#~,}z_r3ik=.?k=.?g/#~,B7;Gץ>g/H>/?!6G!6_B7;G/#~,}z_r3lx^NIy&pr1ZU/#~,x/ckIR.`WP$E1Ri;8`1G j3٬pJIz/>¢A^_5^_5c,g7ņY}ϯ5׿a n?Cx5GQXchԓec\WN8젝gN7gcN_k+ 'Zcʋ׬zoI¿j("Wc6E}e^`WWW?rv= ҧQE~v~|fxO}|&QewQu+O)!54EAal,ęCurbol|_>?{V_+ _O3/~<[| kh6ߍ|1i^ӠYtq[ڵu/<ؔG)ʜev9뫍nիS_⳺N^6P_^hڤ&5ōh#~k+RyK4fD[iYS\&|)mE.մ6U ;; Y ;>{U/<&./?[|WsQX/<>FMחиٸ(ed~̟>x|+׈߈c[\mi42,d,wcyŸ>j9:7˞w.ɴUFGڸoGx K|P~߲6i,| km_E4ŒY`@e0V 'P~)_vsWLlf{aKD@Y>x|M7Ļ x?t_:>^iVMmmw-r]\2@?;9&I?W#ִo x1X拯C_Q7R$~?@j?>|QkcYy4wvp%J bgFqU%Ҽ)ryF{\Ge$iewm[הT_ݶ/m'}>ZT['c < `>jj߉wuebN:mkirZʰqaz-qm$9WL]kuд+]u?ßmΏowq};8hc׉ B5=fÏcV;Ieq+heeSde-zq.go5z)M}Ri+-tidhѱV8=E|O7 5|E;z+u|eE`hMd.;o)>BKWŹWs 2̠dH-go~;w<)Oၒ$3cn.U L)ޫS/ n-1<$l7;ױ+QMKP4F9xe +mt%NX"_+f_n<?ۧ?˯x~.խf4}e}F+;Ks+"V Aڻ=]KɼAnk-|kͨAt=4`HCK պ |l !zۧ`f[l5V8KBWGmt%K`F۶guE @CZqG i6Ѭp yʫ#;(aj%4m˧ܮnJq}oWRD1[bEehL8A}fDn 2`"˨.z[Mz^i?ڛ?kHhKl|%]?3^d͵cUӢ(+/{-&ŽGIdݽ/;nggOVWgkH+`{O*I;*"p"?JVƿ] NmBKiBU{~Y<[:G Si<?Moo47JE]oH؃+ܫM_[e}ޗc}k e_fY\&Eww>˕a-x_g ~^2wGG&k OݥZ}9L$l(S "|Q}2?/mOi"m"啣il#G$5QRM.ezXYIK䷒Vm'okG~ x+Q|+ͭYkvϤ"d;ƲT p8oV[@-RcqUg ݸbK[>|^ǧ\Me\G ̙̒$ly88]g:{o53@]Se8> ػfP;ʴ"ǍO_m-3ė^ƏxXeg$F&p%`2 #vZV죦ĨШouѹ^[R:<;n4˸. } r$8c^_y~hz׋tuO:վq_XĹ;{Hڻq|sO7^6f'Qm=ťݪ JFS V,ؐ_(m~ؖ_PtjCX EƟndDM dj6ߙCZ}4\Kߣ|gvUXjur+}n=Lm #7 mE̩"|:rT]D|3N/%d:y] 3*vYJG5O{W -OhtMNojQ/">Xx,d }c'a_ۧ7u˿ͣK-Eƭ]8ZHda,/J'G j49Ik%*h/wvޟ۶h |k? ϭI:>@r0=jk> ҭ5kS@-9%`Dӥsr_3 _?L~?6/ok!t%5$)E$7Il4.QEf_c]8>XCCs_hK|U־g@*o>YKJ>m{K&X>{ s-V}FRmE38I# ԕCbz?xQb =NJئHl㜸e$J,w__߱t x & ;jj^O[wD#=;DH|&{Q=kjQ~;iNJt+]x-~{&I.^ p8"B l]a0ys/~aF%9$$M-:y3~m[_t1x`֤ӗ+6#Xՠ7뽽& ?d[3Ꭽ5ҵ/ xZKm$D!,Fmvv |]2HI$<_NziA+i# hdXب?qiƭo淥Wݝqz\Jzty|۟\Y?xODŽ'y~=bݵHh|4 5+K\:[2\E.lRUɸK _ xG E_^|/Vr+R_0x._{3χ_7v_(Юˬ}&db  |_4OIX6_Ȳt0@SWU^0MY~)6OO49(^j?ok쯭x.Vz3ʺ\Hs.)nmQgN1_O!o់:ׄqus7?mu]F3ȋWqy^B_H?ߍ5O8ּ;_v:yZ[7vie-1| ~ǟ&-!m"f 5gUH!D"1X tN}#w]wefRO$Cj?p|'dzD2xi16iQէ-a#EDI#0-Y5]#'UlnP3x?a{cž!ߊ-+xwLX$m=jgKYn1F,!dPynC~~ /u/x-&NԮR.)n3O=e!l)c]=nӳJ9*Jշ~ Z~cwB#9f`N̖C#'k/e/uTtgFӤj3`" "2HV4(ɭ߅ 4? x*)-_ i6I1!%2[jrO9yoٟT2^zlnlvȷW"ep+yRŪjrs>MUռ䟒QZ>H9k]͡jɯhw :crPqjs_5?ᆇmBGKD *KDdAy` 1. #n=-b9(vqÛso}_ |R?k}.=ZY-ŭHv-<}7B kcW_jz mWDZj1?vle-#7Ivu~.] ſ|>-'e`mVϔ ){kW'(T|&}o}c:e=+ʾ,4MR\k[LjԠuHL|N"r/Xk|O[/NTӃqKO^[-7)mᏈOn{WYW {m",گ/.UBHp6Gz7_ڏ曬x>:-hj7\³"^G  q_WdZ^Nk?,/1yxisw^-4~"xFoŸ u?u)5^%bYS)r]vT%gfޝu\<FnW}vs~'gkᯏ M m!_9yw"x㟂~wX{ WU`gp\H'a,D+H0>aG!GQ,3D<"~uYiVs]-[[0Cְ7'fVޅZ/ Wx\%\&ͭ s[ytYg:yS*4tZ-o3?<- _: Q-`Ջ4 I) 6Ȯe߈'muu[X#'F ,r4`Tc1%9/n\mNjW#E}NsZl&+j2+e~u}+o4; {kv[).  PCK>@':E^/鷗^颻ʬ!xMvwEZocM?!|Uyat%5EdykO0E׎~ =6 .淸/-UZ<<);mjφگ>i kwuúڝFkR[XeR. `Q`۵wۺPxY7Q}ռWq7.W$^'౼mC%rG8tOwAgxS!lKe.V)nnbY.%GoK˜m]BĞGt[ǾkGm>k ogXX+)^)F~ξ,߳,6:ӮeMqM[C{w,Y»(ElB2]+Fy_f:ʄaRqU4ۯ{EU澸,-#]AkpC)Q#E %W8ch<_k>猼+xñڮm['kury`=k/DΩI9Ϩv N&Y q#}E|ѩ>~#D?x1Ca kkNL/+(esNu4rv+V_Oſ@]{7θt YfZYZ_M RC !;+بQq^vͿ+kev;۟u]Rs?ׁoxK.|3zZݕWfNcJN ~M#MIEtoj5*;@A H8u5|>>&xR{;?nuG2hSY,ius:ȳ(,H׷7okqxOWë; [OAh>č-V]TF7ۭokv|_n%{J?/vk~̟joz|A>skzoshIu ̉wlZ#Xq]/i.  {[Ih.ch"r$0վ 2xSwCG2B^陟kfU;If~<!ɤK𶉩iOme"0hY`R0% 1'7%$zN5Ϸe_5+iIw~ʿk V?*kC0((((<WJ^%_U?%+?h~Lx?_9 ((Я`+ek?c Y;g"{^ Cl~֘v|!?dLuֻ?Qz)/93jQ6E1mZʼ??p֙xJM[Ě5bnc(֒78ϋ2{\C4JEZ?}x_֋Z-|O_'%r h?OwgBӢTe,d}+_߹s/DE_^uV]ESĴUbK Rx}/_߹s/DE_^uVZgb)M?'C I/ҿܿrjOϾ~Z?}x_֋Z-ؿ wK5'Jr?WW= N_h'Z/kȴgb)C?A/t?Ԟ"}+(__9\/ :+_Eׅh"_ Rx}/_߹s/DE_^uVGv/?%|ddv_<7=z)Doj$p1f>>] ksׅh" N_hS~/_η%GMoWW= N_h'Z/kȵ;'C I/ҿܿrjOϾ~Z?}x_֋Z-ؿ wK5'Jr?WW= N_h'Z/kȴgb)C?A/t?Ԟ"}+(__9\/ :+_Eׅh"_ Rx}/_߹s/DE_^uVGv/?'C I/ҿܿr~!ԵD9vX6QI=wo_^uVG/ :+_Ek1嫈m l"<1 O'/Eu/DE_^uV\=={}!_+/s\?/ :+_EMiuiVW\:[Ag V1d` ϭv/j_i};[gn&_k/u51ZE Cl~֘vٛ6E1mZ?H?ͫQ@YW~H5o[ףל~H5o[TQEr tjմ>1l$,e2U.rA ~>]7[kD7sX= xl9SLW1o>2ko xH~qg~6E@.Ɍ[O吶#r\Es/ .tQ=jMZ썥d1Ǚ}?J}6 i{w_w-㧖xnO¿o3qk2X%dZ[3퍉i &G)Ï|73lt+g[PpC0 >CrO|L>/[]os1oĻy->L+$<p:>7xwN?gah> -~ɹcwCUrAsY˒-[M/XGunWtWR~-ߎx/ [͆[ayga$$dLVğ(^?eH^-;o3Elo]+`AK|vC><9|QZj,&mZH$(I"F/K o_O:τ^]D. q}6Re HrI|EFRo_OwK~YsFimMEdXQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWڿhW]Mt1ZE Cl~֘v6E1mZ?H?ͫQ@YWRzU79*z!ֻZu.?>rUֿ/ˏ3G2A}\(Ŀu  _@f/e]k4*_?m#x\D׭n[whIٰa3n oӌo۟%ֳ**c. /s/Gvm _e]k4*_?m% _@fe]k5P*_?WZ.?{m_ʺqhUֿ/ˏ3^Ex2A}\?u ׶@% _@fe]k5P*_?WZ.?{m_ʺqhUֿ/ˏ3^Ex2A}\?u ׶@% _@fe]k5P*_?WZ.?{m_ʺqhUֿ/ˏ3^Ex2A}\?u ׶1*Xw*_?WZ.?r ࠾*F]|4*hzƑo᷵,oe Z) r2__^!s^fI˭h͵Ə6_.8]9U8\q}WZ.?ʺqkhĿu  _@f/e]k4*_?meH-U 3(䲰ԠXRH-oe7@[M D p,r+"5/wV4ש*_?WZ.?u&.‘xO|xTxi/*xQ{6ei=+)@u(6K#.o)bo_|s_V+Ù^\rKo#ںZ0GԧA`+w^A!7M$)|a^N~?ף_z_z9+^A!A!궱Owmcei{E (IdQ] ף_z_z讃_z_z|!< ;FnU$Hݐ V>EtBkw6zڄ%ڍs FrvN@h"ZEŧɪ-нvhHѕ]7dUA!A!^9+^A!k\ktrdi2o֏ ] KX4?͕_ˇ y'Pe O_ G \fu g_>j~~5Y|,4$tb^ݧ;0tql*Ps?B~V?5_3):>ek ͜P H쪲g*K`xޟf)J&-/X/ |yJ?#ߒJ|ca 6 awMaiY}nFV%= lE?W^mc\m50&rnRz.zcM:_ xQ5sxSͳ_Պx ;9"E S[ lI2f|`h|QgO ~/q@Q5Lj cMBV4$]o!?F5-7LѴȯu}nr:$R\{c]+3KxTd樧RTm&4 Z ˽}j{ R֖iƛ-YXI<.e~f LzI״>'ٶq3 +JKlZ+ r0G#֭x>+t%At@aڭŮ\Y+u ?Zxr٥-ͼ*K$۰I<}hu:EmiK! !f'?&נ! ω3?U|U-.m.Tgq=إGyx ꠲X|#sI?Y?;Cq}mњ+ ;x8(Y{$cA!1!(&D26 z|ܞD[n/i}ݯ\ j8>5D?'Dï[z5oUү}D %/(Ŭʢ|+O  tؾxCw/m$_W7ְ2W1]ufqFf?}\jȰ)]3d-ڮuHwm󘨏>c5J}dףͮվk菁?i&NO:># Zo AZix#Hk8;Lm+!ϸ6F SHzO]~ YW]eXGG;Bڳ}[(]%% O_ Uöw,[Fv9! t(ǢA! \Aޣ R1HQ+LKB]G'u?j 즹,D@fbMjxriĮ$ .CZѯd6ig*/_PWcN_k )/93jQ6E1mZʫ!X딟*WB)?P)$q39¨>kZ/>j6Ee@ITVR8h3ʟ'SxO×ڡEPʁ̂+ag\nPS\ԿmO|Y0i1x7^~kO=cL-nOmuygi3 W̤,1WBGYxH*Oƍþּu$V·ex{=.-.[{mF!k I-h.0o#o1nѷ8L|]#Դ{𝶢jW0Y`HWYDw_Naߚ~_jži>;*Ug,etEJXveg 4~4ٻ=.M8r8ݬ4^uvq7'ko'?7ƞ/.WX4-2{v$/H$Kea"_ [φ:u蚟hZIҾ}XuW0f-uq݆xF xEĊu-ww>9׍~&#K4˸,/.uxcm:}D$%̏drgޛA2i=_5?^d՚skޒI+=:-mw'खQ&ݴ#k:Eu}g˨l:a:Rٵbޒ ~8ge5zO׍>gH?aɯImwi$֯#_mb;KIXvuߢ5 qihiI]}nfjOrq̟{~>'-> Y6t[Ʒ6-ֻy[iL"x<(j!NkşKl!M{£~ʞuM)i>|R74hŭ_iw6s![1ܳ3)eR6zZnkVw^Nލ4fiΔ\TwVSOO'˂ߌc㸼#_h&%ͽe{u[Yv'CAh"r|6?(Ɵht:fbӧO6B Ⱥ(x",H0G+?Zou kG—ɦkǝ7-m E&GS gEK3nk|nM m}uOnޖ>ύ'?KWuo:OvtzN  ybh~sۺ?ƿ|}i5 nw>>xsG7X]P6YkAlmSIK1XX*p:ViۺN+j(sCin뽥KQX ((|/D-3ڍL;.^>N3ċFmW) |ES_xgUf/xE N!}6DFhG)o|UxN1Դ{{1qyp<EI%(swU'+[dWAއ*uLl#,д?%ˍ sC:^z>kZnd]"Q,qM,jEGJUOɿxO@ǂ!=Ωej"{XJIs'.(P rH"1qV3{;k}Z+ԯoK=VoKݿI𮷩xlzֵi4 o y:]ռ0"i1鷓3QNCH~?j=SŢ?x8~$h^^\EmU:l$*4vܪd̃|=~3N JE%cC 9s3cj:R˧X]"]6H`xޛTn]dSogW*]]Mݦڲ$geK__Tgy|)s_G|1_}ZJ4zKqg.u_ɶut87DZaeG/ǿz_ƿ&ī7 ~.?6MOV]yu"hec( i|? v+z$vٽ4>nKi-W{Ϗ? w𶏪HcxŚ6-^m2EMp,4Dܴw vC@C p|^Be־&3WޱV|@[0Yi uF][L8J3.<;xÿ_[c&׌5m[Nѥ ɧWRZ3#y$+.fS 1U$QmW[]*j.׿]6Z>h/ڟ?;[^'H֭5}#TRОLQt$ybt/1C?_M ׍ׄc((ֽ2]3BJt$X]A$Z7pr2:ZmB<_ǟ}뵴6TrWJG߭π9ox/)^>&kVWF ^hLM-/,&]^;Вyo4$Cb_yoycx9>Qww^n5m+f3-^&.Sg9>%ψm8x7FK3zn&"h.r0 C@| 5O~]]Xqy*Som-yfzȠrE _ g\"ﳋ_|Z4~'/^uop/Qxiz ئtT6zI77Ro?c]Єg. AxOׁuz'5ɼT# 4uMks,3hf(_jUP0N95|k76Xx 7Q~E}DϨ.wm?#WR3"Hk2ޚj۷Z5jMy߽ğj_4oOXfO]ve֭ͬZ^N*}E@ା,):?6ޭ:8𦋩X 9nu ̫-ȫFfX"|~ |9[D||% |`S-o$VQy6~D#=։YՙTi#JtuaR.٫[;Z6[wYgF=/ĿxS?|g{hN!o5Iռmm|K㏎&x]?^-xi~\vMj5(g]&cS r  zfyCa@MCQ-圐%#$)[Q_{iY5I-%nKWOվ?Ƌx5xF G. (?#{V7>ԓUۍП:~q.<0~v<97Ե? y@~(?xw]$1iKIۺdIt3) jTfxPnj=|%G^{]x+[s$M&\*FA{H1xA|e3N70RMwrrMt4gtB$;yEgQ>"4{+&c&mefVOӭ4xvès8x#+6lcٗ|d/bLww+֊L>iX"F{[\,jTܒ_y7XY~ kUW+N d8PHN[YZKv_ry5t?+.Ήkah#vZL^'L{>{ճXmc-v2E_o/h߶G<5zt0 x6{i.s*'PhKNuH~/QDNZ]qm}ew\\@,SF˕7\RX~E|:W YR=gZ$]]%XMIBnf'yTNi.$wk[jE;($*]];5+/߀φ|gCtMrkkq`e-mv\2G bľ2G3Jg;_dKS|ai|К}3Iv|9"!6ԟof? k7<;"4kb;XYJ!\~6>%|]mOƈxW6ZLki˷ri88i+JV]zY%Oގ%Zݒ]~!%=W\u/Vmdžb2Z+=E#nX>  ~.+*;w>ŋjƫujD~'m@[kZ7-ȿif+q*4?</buo u⿌AׇoxoPe-nJijB0±,m*,I%~^j~ ^|gOFec |N+&,6KMf.I b|!mzKOwis Mm(N robko$Y.qǨ̂ mYSH*`jRikU%j~*OFսl|]EJ < eÿ|N;; YPYn!4#hof? k7<;"4kb;XYJ!Y˸+_ -TM:ik}W]ݭztN~bA ߳>4>ֺ4~S4rZmVYU&w _ԴossOxBۂ$rK)QW=|OYhU +4+ D݊ F-=Yxw^,&Z{jq6kZrv`rv*IN;w}[\Wi;E&ׯ^dwNZ9|c6M Yx#k6 |ONV4^kk8"}] z6mI-T/:WOبk۾ osxQh,Z(^qܸd#F>+_|C/-@x{P <3TȀ'8O]⏁t8tsÚͪjv7 = 2*rY?=+krɷ}uUoIzWvTVKMşu'¿ïu> ^x\zn4.X!5󟃿cx7 -/._>"7g_um" #-g CIĊY>@>q/sΈKyAzBXJ*93yrdcdݲ>_ 4_|?Gk6ݼnNdF2 o:ɥ&n;ꟿ&VovNPS߭V}t[7W/ 4o3Z t?/d#ȝoTɏ'\}^*+o~yKYK 6s^\;mHd,X ^Ppo3$ﵿ4;ø%435cQ/IAf@}`Rxc]P|Q`_Zh% O>w=Yv}=z~%ݭ?N_;߀ -=&|[܋ȖTi#G=*H>𕦹ëܛh>+znvv%"He^]x{@62|.kɇ1I2:ut{ 08)*퓁^6- T^&.mYbs) EDuV{":"2MNh> x!bD3r>N:%MD.5 J|nvy_j3$iu't//mm_]m_REK-Mߨ\jR$˒wūslA!)PU<ΫU쪀>ҵk=n'.mnIdEVHأ*~򲲑AT:4 WӬK֦k{4 "yYFd۞SmK~Z_yqi6o>E8xgoGoZ.w}-/{,@Emƻ6IWʡ ~b~yg?X;KM?N`H4R' *M:UKW0>ƕZt3/ĵ_/m:T^d6ig*/AFoI¿j("Wc6E}eU?Ob!X딟(K-i(PI(@g}6>W7}JׯtOAoog{m.}J8UJb&U?T) FzSPm)/F|M]^q,+Ej?.h*}(h /xMA.-l䵊O0)v=ܨ!Xrs:=Y[iݜh~v|~'_N[A7dokv2Y$YCN0z,>O2LcrxO_/t/㇆~- 3Z]iz'/k67V:lV3E$!&:W,rdQ:҂ ==XQw_ݗj>SOk=i|xS:|Mښ c[^K/!hC$n%R2 rRʣsۻ g.ODJ4:9.~i~~/ItZt=W'|ckLUcewͧ^EjW [KI"LQ.m3pOQ~|Z9m k=ageu:d]?>L13 =(2(yY4VjIvq|֜oIitkŏ9,4/zf|xoGmoomk eet-JE/";;Og|9o7V6~<<u׍1kS_}2ti!Ԧ+I|u|GkTn%Ex \nh{T' f 6#8<6?m}Ţt[.$_-}õoR:QKdԴ"d⬺$|n6៲Oď+h'uY>%xľ$ZFZX㷖[(~wn/"9ɚw&Ue ?c`ߵ-!58|D\_V CBa5H:V|:ݧ6*ysׂ |Rм5 _FYsm]֛tԒ-Vѵ"pLYYψM|pԮnzƥ{a4kIϔH)A0PAR3p'ڴUwݭQ݅O[On_ { EVďW _ˏnoHүѵ}"[? joTAWdh7j  3֪T*E6e)Y8>⽧?M -=xz(z^ŷP=ޭӮMSdfIdfǿgaIlU4xjV^3jR>xm .\,k1F+ 'ogni].4{\M}αY{h/pWؑ͝nωԏO?/C:O]AﴉIl tIH7TGFRA/.k<h_x{F۰bm}=m?3ӮrSUJsrKe-Kؚ2gI'iVWS1Q+V9qeΞ_OxóEbhB1(1m5ВܼY/s_ `>[j/:O[M=]W׍4Bh[x%uT| >~zu7|6CM MbfR@9{UqZ:+Y٧m켗2]z(^E]yݿKw|IoX|M_~!χD.kյK+y`^Z40if>S<)WG~/ƭ{3!5=C[u3C%PgAn$s-~վ /a_jFᏅƺKoC$M5b[K宯y եŧi_NsR_V >*Ӽ?mx%Əs+Vy0g+kU &Fky5z>hPj=ƗaiyvZ: 渐?qU W?Sд75+|A~Dk̞`_-v=ܨ!X*.Њn5uһ]M&.ӔooX/ ŽC$:w :~{Oy?f}:X#Y,vmv_?/ZïxW_ߎs˫:V>崍Ul..͔(lZk0J` p}+hm|<+.smx6Kd 4|mC~"HujHޣyxp1C[[dM ȯI.>,zZ])Iu[')m$˵K^]y~+'(O?m>-xo50dEHz:2`.X|?&ddrGqAFw0JOVKNrR_ފfnIo?'/n??׭.zYu6xtN+eUHV[⯄>)V5O ꚇŝ'ڷƘ-f/ÿdmYvcuWYq @$dxĺƻeik[ŲK>khn]=([Ϊe HRjNrI7)Yl(Ek|̠/?-ο.O|>f-jLjc;\k*SM>mCSb%b b~|/bu៌V?>| ωPU|rm'kU \~F\ sykOP>R⏅|cۡg,0ҰUchB:! m"<ݫ?k_[_5vo>i\xSM>6k Q;S,u_6"MORX%xc6Ĥx$Md\6h^'R\|#Ơ -۔1m:8_ZjWIn#4`O {?d`kŸ]-6G 6`ql4F;럤ϭ5wJ I5'+݊s唣oz~-w-->('//xWıiM5]KSM5 9DG m4S ~z?]Kⶉx6E>xž%[hKIlQQ˻xF̭1!H%Nx_ۿ>!GAKm-5?¾ԼC>bIwB |"LU1vTMKS3^vm=V7Ǎ_~#M/+m o [|8߈Ix{'Sk}tZKg$(1|Rqn|H~ko$W<5kG'4M3AQt_5WN+IQ$_s)4gsN-bFfDeʐp@#šƳ}/MӯKv;(W[f /Eo)Լk6ٹ'丹hDq4ۿC?& <[KZh 4 ,`8?,FKd17OgğΉ \xT<9OSQ;qu\Mamu1sy ~//?L߇/٦hER: Hd-+p21 4:d8-AN-wOakj[ɺ9Xԫ+5-z{v]$own羿/^nw X_?d _uo [է;-X-_-ZO?υ>w>w t.jZfsxڥ^`([ƖQy*iu)04ʫNtKEI%}R(SzǚJԛ{9>_ >/|AmG_Ctt?ZC`7:E7V=3,d #x N>U>!xwZմT~,P]}C/9|-ۼR_+_kúmQ%&qj:Eh46(F9I]%GRG'Ÿ'Ǒx}?@:x7Um=B%j2$**#axΒKT⺻rreg}ЖNMwk{]>xXZu^h~\kԶ%r!T_-Z?57~.,O? ~KtsVo=*Un:rKs=Y2v_hMs֟xM~~e9}3G$,C!i\,k#7km-z$u;YJ;j |'tc[)_k? K cé/^SFR1_*7_'B?d%,>2?Z/vɩWLƫ9@mQE;Y5{Z%>xGz=AouK4o j7]=56)Q")I ǂޫ ^_zڿLjYZ!Fb"3 $mJ;[Kr)Z%e}}v^?8gⅇuo Yּ'u) Z_ $kZ%󭲸f)o X~On<XVK jCZ|ՆoѮ#چo7W՚7N/kϋ2~Gc6f4cOn. ̡bF/*x M.7xL<o ߏl3AEvGM+[_Ngg'_khVS<3@% x>$#ăE%h~l2%I,0LŴ.oړVfxe2¾ ,!e= n=ڇ? <3OnÝwZ[Y0_ig#$Mclz73?g⟃u5|CmQȳhG`uc84M="jܯ֍E6K^V[%~|w$|%o6^Ŀ}äYyMsV"(-Ĭya6; ;W@}/ɨhl1Ggms1nVkNY1G/o)¿>)h ,o^D nIH\ӢVxкR XoWō 7~!/_K=%̖kcC!%;H'Y'%fڽﯿ+-nmJ*ڥbmeE}n|,>R~3xP584 W쬵9-]l-<1LFǒ5tH?D੿ ~'|gx6W,WNI#Y-ݠ e2|#c ;iI=%s_<k7ᦱ>ۻr<lLfki,役.<лm\η&HGV1o/f_n_u:k]}A_/m:T^)/93jQ6E1mZʫ!X딟*WB)?P,'9~#|y=/'|/]Q/X:uɧOq%eXgG?a/,Ye$H,ǀzV-ؼxr+kk }IF+IٖXduGT'+JO{~_oMMFV]o_/if?/j-Z|1iϊc mFM=_G'gkI?w_GwşwPx@}#z=6+bHԥ0iq$Nbἄ`HsiíÞ=fC7-iu(p̚\HP?xe?(W及|/G/xD{ Aul 5I3oIH|rsn_?n䚿N˵~~ͫǿ:rr_X\|>%ysot$X7ۧ.!>b@ :{/|>{e0ԵoM=4}OJ=rr1ncm,!6;j}%Y|fS3@3j(|?2|0ڏ|m 's׭y~fv<;>=9a])-:yij mf|U|KouŚP|4O.[zIњ-Qm>K|w e,|LfxO#Oþ/{ =|W-!<~uc0];+Ky|ߖ !/Pσ|)2\]Wqú^e>a 1:r9hA)@,kVk_ Kkᥲvؗ*uAg\:X/RaN-(KFeJZYM^ N['>hnj<;{Xkcm:⽃Nm4[=u9mn5 & 7jMBT\k| Ox~mWOV;P IY?)|ۤc}Zj״SMui#WҴ>Ϭkxu M>Edx|أo2hbD9Vo6Ni"RP8G*>kY?ǿ%H i^=>)h^<uX 2${Jd+"ȿh7S'/:SZ_ǂV g&wGڛ,olsҟ5Lu/x.ڴ vkaϙ 8ER ƥ jiR~)z~jP0L@C~HE/&@qNUw.]*֎2NwԺ[[u+W_ izŭ I|M~]x [HO h%ncΑM_Κd &@NX~Z|kC 7gĸ.mVZdftՄ7H!<_v6|f|C| VRΏ;;teV\ކoo[o3=޷ ,c67s/G9M/eI/.G>io٫c/C:\]V'gmX{ĕeK̢;\ ?oo+!wZĺ߆ѧ\~ kf58<^}O!-6L3ŭ? kk2k-\Vtf1j ]r$Bt 7C n|g^_kx]ӡu+XlPO= oRu,6۶Jl4⬖(E$ ?f|o[Wl\]dڲ˷B}χ_o^gv9?)ռweWul5/ 4>劅{]F`zr+>y{ITtٻ^~Z)'d|=5t_ h)?~_|fG+[ׇnZKK,+Xcm$u`do&=@3wE߈1 r kcE.{4΄bL6!)&>w+ſ~'|=|+Z->"v1 $3|}C׋|+DŽ6o \Hkv~&qw u 7POK4h%_/~ f>跞5kOA}Ky5ٖAGf 7$eB!/Rs>>W>xľ׍4GiNèxJԚ[+Vq,*ǥ8m+v]G%er|^{OU~!|Cb^|X) ~_sGG7˯zhz,=*zNO4m/j?>.|15oͨW~(MS J(U1\$)3~ 85_~h:IGQ=) e,c,0*?uakyޖn}W/I7Rtǿ&|@ܐ;ן|6|^/BVykwLj,-MPIfa;,Q\Kj;)9IͿ/69ugtTz$ >vNϦo><|< y_]υOC4l[Yx~YI=5LI'I##~߳ޯ{W6jrGn@*.ahLLKHuL ?Í+GuO 'jz_O ^Ӵ-ާc%τCmqHnZK RGR),,?;ǾPgv݂%vDM)) >xk)YkhZ>yUf.$=E lz]*ΥY6QmR~zZ:)'Nz$Z4$]u>;]rIռ?^xB_ j~+ԯ&smF#mlR(% s¿~о'7k)[%O ߏ9e&k_2Fl;kіF_|R|2;[OïeZjzViC$;X;`4jo?Ei "mlzME#4HˆV`"R^SIY߭z[ ɾ-z4}e;EE_aOx񎟭0Kρ (ߊK"=+K;\"y/5בj6P, ȱFC'^ds>"ឯ%7ږ⩮ci5z48pT4G|A|,VXo^7Kv'_YEY~h Eޭfwsճ1M7v =Ćc/o_#_ x;Ὲ|C⟂)񷌿m[wV!/|Cyo¾*G?bM1omʛ]D-`havux ~*wxsĒXG Kp5LiLDNH+ͼk}|9S௃Z<9*4O֭eԼ;Ze֡5s4q2$a.~aBR^H-afKE{ۺ6lU{M+Dﭷi,7| ]xsY׾MFNJu^: CNҿup_ڴ- o9NX~Z|kC 7gĸ.mVZdftՄ7H!<_yx/Y"ű|<z_3/Nxt0~˃ pb|ӌk_eeLw5,ͪM\Îk).x5ѩE[Is(;y|A^}_aj!6zi.{X}B=OUkcYXC)mӮw'?a|luD8CZu K$#Lf̐QV&e%v%OQ3OD0c:/3Ǘg5>?[|:$">oUn032G*G.1NQ{RKQmLvU+Kkݕ6~x}#>\x/Q'mZ3}6ٌ-ФMv><>,xk`DŽ~ |1?_?,-Gv;}FT]6-̉y;{Dh?⯊<OZĶryq۴$naV0]C35'{xD_~j0Z\ƞCy_hݎ 9)N]mgIkrFL2kފѶͭLoٲo_.x¿ξ.?LdE5 3ǏI@̷v8:M|!gYQkw[Ðkznl6wm=3#"$ 򜤥5k-z8?9O{QXxW> xX|6y>BDCȼ49y;ܪU|17~9|iO>/SxMwLKN-F ato$1ɫFIh]7 /Ӗ -fZ[juka-5]:{̺-xǾ]<])/|5Oεf$m:Cjw\֣sF3`;ۯ|[8=5? x猴+[&{aմnq$/;-ě.fUۀ_ï~*o nͮ6m}uK˺fG"9FT4~ۗ|;3?MzZ%֙eku56jp @̻1^r6v5'Vok+~* ^Ioo}Ok'VGxW/>h= |7m7Inn_R}yM35^faEYPx.B~buPm់>*ͪiFޡh=\F[4WmEψk/_O-2^ $_z'km/TAk}*Ēդ'i>a#vneԖ;jZowRΪI2ˠ~ϟ ?gGQ'^>#h'FeR֡|M;h4AOߊ K>ï|K5vuajֈcy!!_,)3dJ>ksįE޻4{;Ej0Ky 1̒ h_fTFySVWkv]nVE{vuKEnʾ .W}7vxk?(.DqI9o-N߄?>>!xZ'TĚ d$_XuIX\\Ȥo65 6ʼӈM}IE FF|'ÿT xH {F\ Ҽ=s%jڿpBRF-̷OKDcBZQԫJQ~N6כEGw}[T'ͨIYKr7ywO+?i xW(KQ-wK5}vO}ul, Ao^8Yn|F~~״]FwGo-xfxfKmZ&G% ۦ[M/_ > G+(y ^<+qs H ]UuVap(kv/hݒgSY}һ骶K՞sO|Fga  5mM5 g>%/1gym ^o{43 KN񾽨xs~%ҥծn.]C YܼO$JHAcܻ_ߴ5ׇ<i|~X}KO jzj-yy.n.5hC4FUNq"~/T{9Q|m$}'ٛSC7#O c^ּ7k>,Ulu.g]EtVO e! f4~?@m%kŔ78XiGH Gj ,G;.cץ[ɧZ:2w_b>4Km;dq+ʅNξ7I/ii׊}{i]#N4u8ⷎ9g|H(ItZioN99tjXoI[}Z}meTҲSߍ|W  XKȾ-G|u]/I4t8]}^!.v a? <}47_ \O^k[{--,絻ؼqKnD/fX'^3O |<nt~XiBeߝp4yuJnkOn ڽݤM>YDrOgUJ.kc|:6 sTڵ/uMFPKM}%c"=J+ ȼG i*Wh!>D mR8ࢺ~\iZ$V`[Mr[^q@v$q;$_\)>|Qm|D񕧂-|;-#Xo.dAqEn`K݆LL8]╵٤ ӋQ~=4Wѭ]7;ݣ~|&[N)ox[Go}\?(7e fkφ?Qo|FkFӵjY̖51[`yPRP"dB%K~JT֟h^Zjr[ ܤ   A*|MIu]K m.!۷OG wf]dwcι{MOyUZhj"NbԞwLI4y"L[7wv`k)5#|L- ɱXƣhv>'t1s <5hֲ[ė &DJl^SF gi Sn4}.?xo0G [ѫ$2,sWr%.ߋut?|QgK?q!lΪdc*,f5v@b8=jGJ[]K 39RS~#ž/GEpK+UݕIA(P|h_+_th~,Ιq֛xZ2$-fȔ$[qy| xY ͒b s̠sN+|P׋o_ CtrV+[{" UbSac>=Cx NtS#Yjo#$;?,1]śp i꟧u׺#?`Z>xoáM6wp?g1O, [dUyDŽxދywujRZ8 i V׺|+όڃRKI1$BFXݱ&dcAj|WBvi]Kmqio}\i-4 .(%oօYɮ~>xdNVE6G{),uBH^;Yvp,k&9 +B"JO@gJ__ Gn|c=DbGcI1Q} uzE#1 k|!?dLuֻ?Qz_u:k]So$_ sfը m$_cLڵWB)?U{HoM?:.Y"J:0e#aP4kmĖfl_.Eŭׇt؁繷Hy aɵk?_c)uXG_ᔖwm&4#٫ o_' ~ex+A&ڋ>/؄5Io嬄*p~ TbaoV<%{o S^x{Y_^j֑Am{Atn{&} ?mItJ߃_¬G{aj.hW,^=>/ DMj|(b,ٷ?"L|q|j`E?vAcq?b[ ˉr Ghɵk?_c+e^Jp/z)~q_+Ogg*]˗]>i|Z]x+6o~VP|vӥcII58>hz_ځ<ӵ{5쏆촠X`y"ŽФ$35xs+ź~%6^ƽymKPԟvn:ݤzwP{:ډ]cq,ɵk?_c*䤥n\QR^M+' MO~*m 5׹|}׺ Ɵ4KY-iQM <"L'߶NJ4Gyj%tR$kihKۯ>4e_}_c(ɵk?³jKkѥR^!i~OkwVo%/?x[dz|p/_-oƢ;uuN[ *K-[cc/럴O TwBb&~xZ&oVfO.@ Cf͹bg_c(ɵk?º#yl{hRm-6I+ KH_?;dj_?~>+Oė2n.י4/~^g&6ɠ[ ۴e]5bNɵk?_c+cmQ|U^OKC埈?~"~Wׇς|MC1lSX__WzF![x*9aK<<>8KxT'Ɵ L?7>#:ERm$[Iɵk?_c*RRnMS8T&_-8C-{xMFj66QHf]fRHt,#u%ݹNT5?b'޽0j_γ?.5?|i^`^mUaO2}&p̻_c(ɵk?ª9sEwUETu?'(6o~Qk>dSYxǟ]hSM <kteTs vzR&"t+B#;@!?qdϵGM[߱.7j]W;5IIj*2quM' ]d#1 OƓXbsN/C$d>io|rge*? [xM^Kţ[XgR;ͣcz5w(6?6o~Qk>j9Kv۫ǯD蒾l⯅Zgwč]y/lQEB`c*vǻ{# ּfk&:"kޙh71,XoUM[߱dϵQS'?ӳVi5jU^_ܿ6vwGZ/7|K0^{[g7sK[{yt.[Kmbd7E j ><o_|~⦷+=_Mk`is c3Bn_- 䏾m&} ҭYVKvZ|SMRdMֱ_<':ZOդC^xzޭͭlJ`ee( ngt$;㴿\úfZ}uhu*m:;Z$x9൴LG&} ?m%'O[{^JT^ҵNZ>&|"\|Jc?WQsq/w5xuYn [x>:1'ҫ);ui.&ixo|ie-Hce'Ÿo#|lw.',o_6o~Qk>JMtҵb799w_O_UmxPX<ڶh i4+=J^YeVcSU|?ψt-2QHͷ}2_$ҙU H@m&} Jrl[FIMͭ_oc?>'Htߌ~ O ú6sJQ͛QR73A,E}GmKh-7W.a<7 {%VO\J;uSAl3M[߱dϵU*Nek禍ke?`ox-#Hw7%wGT6rGM]|whD%M[½zga>A9?>2խ&kxty_P1y1 +I vUk_Vǿ |/Zx/ifkV=@Ѯt[Rynd$Iٚ&} ?mjuN;5}Kf|YYi=ϋ|y|v񕦁˯>*x{5 HI4uth.M^Twr)6_~şt d>⿉#AŬ^EAkd!\[.$Hˍom&} JMAS蕿}фRmܓ]KG~'?cWh ZggQ51shB5^D3*gfr 5 3g:&mƾ/xUv)\5#'>y~g٣p6o~Qk>9srכVkӷ~VWwRZ5o~xc ikTd/bM7>|/iĞ(klPύ?bso;"CyD0O+/ikG m&ɵfid>TX1l۟v&~ɵk?_c+_ϙMvܛ7)>$*=/!?O_lG=W~#h>33լn4>^~t {Acs3yq4VTy_ x3|G[LЧ;BCHO[jVmPkLr0m_1Yɵk?_c+˖MEkwnW7s[JzmY+'hWĶw~κ [Ϋ SîY #D{q.:q`U=;^yt5CC/<; KTkku K/_c(ɵk?­՛~k9'FdrR拃^뺷ֹ߰?|)⦷GYx;Iį<1jlLӬR/\Z[;G" $uk>6o~RSJ}{U_c(ɵk? gx|u_6o~QT5oI-إ9+;6?5|Q~1h~ែd>k:ޥjd95լvjJ,!I6HQfc/ПZq.rt4Ҭ_uo+[yI[P9V>o6o~Qk>:uֵNɦ+Z޻-~|sY|L/o./6g>q?5Iq&.ėet[yѿG-+ow㟇 +BW^#syɤ^Cbbhޠ۴e__c(ɵk?¯ڷ>wMȬ%$%m}O%ǿ-_Vf-KRgQ׵ 'ҊqzT[yR0O+?f߆s|<%xYڇ C_m=g|DsOTJӥ1ۤYwmL`k>6o~SGMz]itL[#ii~{[CO^2}zyxS|[j%tK{fEo_w&h&"Qs*A*u,Oh\kVx nx~W[BK{k,xSȘF6m&} (}VZɷ(no˭Z$5g/|qᯅ^{-~>)}*[`\E%A~ѧaw/ZƩqcwu=ĭ=ighYgp$!I&} ?m𩷺=}mv|kѥ_G#M GZ+|sJ/|5x2^5Mset魾S e̬oP{O1`]{ ?gtj)m4{N+m%v᥊٦)X'{M[߱dϵU&j۷o+(>Fm+z~*㭷>0j>"qXz{2iJUm+,cϽ/Q$ֿ SDkwG@u=#gyGGذ[&} ?mU$Z~Ze1^];ױ~<]( "j/UN*M2QѴ0%Kk)fBdk Q=Y~ɢYx@оo lDдk"+$&} ?mCw CZ^(ƣ_ j6[I˺9ЩVSdϵGM[߱q}G8$u;ᇄ;Zǂn+O [M] v%~Z1I/?gmOTcφ~VR}[}>IH+Q"ع!Hc?_c(ɵk?­_q)(Eo9 |/jjC5IbY%&I5e;p:=kN:Əwh&B<[}Fr)m&} 48>i_(s[ȶ? \nX^iU[Go@Ȋ],_eG_]Iu99kM6i-6J]<3+)($c5?6o~Qk>Uܽ?W_t~E͟WtIN72&De<Рqϝgjv9=cYnT^@Et7Csy>Zb&} ?mMYk|Rqm?tڦA^:@mb)-"tȍKk>KvV5'8Ug_3K$>_u:k]}A_/n߲M&dC3H?ͫQLL.-y@IZ(Z( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( |ii%ӴmWSյuVk4'-rqV|>?|@mnwigS -]-tn'"`|I=-Lx\k6Q3i8c;(h|Qajes7Zoeg7,o+(ǢFk毉׊.c_nuqCmm}Z̨>0.e̊ʸ< zYĶ#%դVVgTh|s98$=_/է٦Imoi{Ѿ/ MOBʏsw2` 1 ~5~"hRjDJ[-*y'g|AWAuC-4Mmo2E3K6ͼyhIgík/þ.-ͭ侉Xd 4A29nJ87$Uo;KMj}G,j R^.>jqR/PMJyb.T1 J2ŗZ\ַ~Ƚߗ~Oc*(AEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_ cZ{? G}xbE1F;C 6*C67|iĭA7x-cA]]ȏ!.9W \}5fo@Jmgk׭=#W S<=[hw[a#d<J&xO|l Za}oԶ ctDLQjBZFђ ]ݿ=m{C^_GOkֿ->)@lauOZv?E!f%*p7Sy>vS].R)Hr3m![[׭=#Qju}KY [ ZhcZ;sqX?u{mWYk 40鯩^Iw4,y/;PmPءkwKOkֿ z5pmc▷y{^D~{$.O.%Bo\ۺV'BchdhInsd-f_=Z{/F'5_e\5.`eIN֩{3va\2|>q.wY 7/o4 LRݖBO$#NQ`R9;;yDk׭=#W^75uOITe^Me3Z@iܹ$Lg{u!L>߈Eތ|;[wkesYplᑙf@@^炥o'v17=k'5_ekO \"guAMt*o<6q"𖡬kMX-DE,g!ا y9׫j}SKD$8IPX(E*2''ѭ]5-gk׭=#Wxk6z}֗aya^o6n>p%8ݹ0t|C}:(nmZd[ۉ\_LH %='5_ek~-XRiΰvm΅3URB혱*{C^_GOkֿ7x1[M4q\,ȮB@<M@{C^_GOkֿ⮳=Yg}Fd[}fxk5P8H 2]e7X-ec"؛0v]WfpAݑW{~5tgj?{C^_^m:q{'t}h_ $:. `@k?5OxZךnE {*F]B0 H7?Ц;׭=#Qj/5Ktm PlbxX(;$ >"h Db-ena]gfsGN9kI7; msֿ{C^_GOkֿ+]nm} =NN[CKnDs' Pk_eicú=闚 ~ֻc l%x4-`R z5=Z{/F;|W[0:Mk#r@Hڭ샸~*Hg.  by홖v$f+% pRwW[_Vv?=Z{/F'5_e|?-[O),."[5x@ۚEr~e`HQM`x7+6jZDjGwuc+K?QfrQY.mV z5=Z{/F?ocg⛭ zrjr2Ho C1+o H>x?@tk6Gx+ H2neq % slzOkֿ z5y٫j0bEdƏ}$!B)Qy9>~6Ƨ^.uǫ_#W&!Yn߼FrX;Iw84oOkֿ z5x߇4_{}7M.Yn `x ᕋ+jomn5WܖH(lGh0jbG6@ڽiq+'_׭=#Qj]s%֐* ق=#\!`Be~KL?UbM*Lܹ 1J>_g~tw=Z{/F'5_e_xG^uF;^աd7Hg÷Ȭ9a;NPl^,PD!WvͶ8G(2đK-~_9._'5_ekQ@=Z{/F'5_ejj?{C^_V =Z{/F'5_ejj?{C^_V =Z{/F'5_ejj?{C^_V =Z{/F'5_ejj?{C^_V =Z{/F'5_ejĿޡEE # Copyright (c) 2002 - 2005 High5! # Licensed under GPL for more info check GPL-LICENSE.TXT # REQUIRED!! ---------- - You are using Postfix 2.0 or higher. - You are using Apache 1.3.27 / Lighttpd 1.3.15 or higher. - You are using PHP 5.1.2 or higher. - You are using MySQL 3.23 or higher OR PostgreSQL v7.4+ READ THIS FIRST! ---------------- This document describes upgrading from an older PostfixAdmin version (>= v1.5x) It's recommend that you install Postfix Admin in a new folder and not on-top of the old install!! (At the very least, make sure you have backups of the database and relevant filesystem!) When upgrading Postfix Admin, make sure you backup your database before running upgrade.php. 1. Backup the Database ---------------------- When you install from a previous version make sure you backup your database first. There are a lot of changes in the database structure since Postfix Admin 1.5.4. $ mysqldump -a -u root -p > /tmp/postfixadmin-backup.sql or $ pg_dump -ad -u postfix postfix > /tmp/postfixadmin-backup.sql 2. Unarchive new Postfix Admin ------------------------------ Make sure that you are in your WWW directory and then unarchive the Postfix Admin archive (whatever the filename is): $ tar -zxvf postfixadmin-X.X.tgz 3. Change permissions ---------------------- Since the database password is stored in the config.inc.php it's a good idea to have change the permissions for Postfix Admin. $ cd /usr/local/www/postfixadmin $ find -type f -print0 | xargs -0 chmod 640 $ find -type f -print0 | xargs -0 chown root:www (the last command assumes your Apache is running with group "www") 4. Configure ------------ Check the config.inc.php file. There you can specify settings that are relevant to your setup. Comparing config.inc.php with your previous using "diff" might save you some time. You can use a config.local.php file to contain your local settings. These will override any defined in config.inc.php - and save some time when upgrading to a new version of PostfixAdmin ;-) 5. Run setup.php ---------------------------------------- Access setup.php through a web browser. It will attempt to upgrade your database, and also allow you to create a superadmin user. (In case the database upgrade fails, you can run setup.php?debug=1 to see the last executed query.) From version 2.3, you need to specify a setup_password in config.inc.php - setup.php should guide you through this process. If you do not have a setup_password, type one into the form, and setup.php will echo out the hashed value (which needs to go into config.inc.php). The setup_password removes the requirement for you to delete setup.php, and also closes a security hole. Since version 2.2 of Postfixadmin, setup.php can perform the needed database updates automatically . If you update from 2.1 or older, also create a superadmin account using setup.php. Note that admin/ has been merged into the main directory. Login with the superadmin account to setup domains and domain admins. 6. Upgrade your postfix config ------------------------------ Since version 2.3, PostfixAdmin supports alias domains ($CONF['alias_domain']). If you want to use them, you have to add some queries to your postfix config - see POSTFIX_CONF for details. 7. Done ------- This is all that is needed. Fire up your browser and go to the site that you specified to host Postfix Admin. postfixadmin-2.3.7/DOCUMENTS/HORDE.txt0000664000175000017620000000250710716665746017250 0ustar davidpalepurpleHorde integration with Postfixadmin This is taken from the following thread : https://sourceforge.net/forum/forum.php?thread_id=1869141&forum_id=676076 Namely : "Hi, people, I was wondering if anyone was using PA with Horde3. I want my users to be able to change teir password from inside Horde, so I was wondering if anyone has implemented a custom hook or defined a SQL query to make the password change possible. " Solution : "Hi, that works for me without any hook - with the SQL driver. I connect through IP to localhost. You can also try socket connection... my horde/passwd/config/backends.php looks like: $backends['sql'] = array ( 'name' => 'Mail SQL Server', 'preferred' => '', 'password policy' => array( 'minLength' => 3, 'maxLength' => 8, 'maxSpace' => 0, 'minUpper' => 1, 'minLower' => 1, 'minNumeric' => 1, 'minSymbols' => 1 ), 'driver' => 'sql', 'params' => array( 'phptype' => 'mysql', 'hostspec' => '127.0.0.1', 'port' => '3306', 'protocol' => 'tcp', 'username' => 'postfix', 'password' => 'yourpostfixdbpassword', 'encryption' => 'crypt-md5', 'database' => 'postfix', 'table' => 'mailbox', 'user_col' => 'username', 'pass_col' => 'password', 'show_encryption' => false ) ); " Thanks to 'Kope' for the solution, and of course Luis Hernán Otegui (slimshady76) for asking the question. postfixadmin-2.3.7/DOCUMENTS/DOVECOT.txt0000664000175000017620000001003111415442052017455 0ustar davidpalepurple# # Dovecot configuration for Postfix Admin # Originally written by: Massimo Danieli # Revised by: Sampsa Hario for Dovecot v1.0 # More complete Dovecot documentation: http://wiki.dovecot.org/Quota http://wiki.dovecot.org/Quota/Dict http://www.opensourcehowto.org/how-to/mysql/mysql-users-postfixadmin-postfix-dovecot--squirrelmail-with-userprefs-stored-in-mysql.html Here are the relevant parts of Dovecot v1.0.x configuration for Postfixadmin setup. Please refer to Dovecot documentation for complete information. The setup gets userdb and passdb info from MySQL as well as quotas, and uses dict backend to store used quotas as key=value pairs so that they can be viewed real-time in Postfixadmin. 1. Dovecot setup ----------------- default_mail_env = maildir:/var/mail/vmail/%u/ (dovecot 1.0.7 calls this mail_location ... ie.. mail_location = maildir:/...../%u ) auth default { mechanisms plain userdb sql { # Path for SQL configuration file, see doc/dovecot-sql-example.conf args = /etc/dovecot-mysql.conf } passdb sql { # Path for SQL configuration file, see doc/dovecot-sql-example.conf args = /etc/dovecot-mysql.conf } } # Valid UID range for users, defaults to 500 and above. first_valid_uid = 1001 # Change this to your postfix UID 2. Dovecot mysql setup ---------------------- Below you'll find the relevant part of dovecot-mysql.conf file regarding our setup. Things you may need to change are db_password, uid and gid: connect = host=localhost dbname=postfix user=postfix password=postfix driver = mysql # Default password scheme. # depends on your $CONF['encrypt'] setting: # md5crypt -> MD5-CRYPT # md5 -> PLAIN-MD5 # cleartext -> PLAIN default_pass_scheme = MD5-CRYPT # Query to retrieve password. user can be used to retrieve username in other # formats also. password_query = SELECT username AS user,password FROM mailbox WHERE username = '%u' AND active='1' # Query to retrieve user information. user_query = SELECT maildir, 1001 AS uid, 1001 AS gid FROM mailbox WHERE username = '%u' AND active='1' for dovecot 1.2: (for PostgreSQL, replace 'CONCAT(a, b)' with 'a || b') user_query = SELECT CONCAT('/home/vmail/', maildir) AS home, 1001 AS uid, 1001 AS gid, CONCAT('*:bytes=', quota) AS quota_rule FROM mailbox WHERE username = '%u' AND active='1' NB! The GID and UID are for postfix user and group ID, NOT MySQL user and group ID. 3. Dovecot v1.0 quota support (optional) ---------------------------------------- Please note that you need to use Dovecot's own local delivery agent to enforce and update quotas. Then you can view real-time used quotas in Postfixadmin. Add to dovecot.conf: ## IMAP quota protocol imap { quota = dict:storage=200000 proxy::quota } ## POP quota protocol pop3 { mail_plugins = quota } ## Local Delivery Agent protocol lda { mail_plugins = quota } ## Dictionary DB proxy dict { quota = mysql:/etc/dovecot-dict-quota.conf } ## Default quota values plugin { quota = dict:storage=200000 proxy::quota } Change dovecot-mysql.conf to return quota values: for MySQL: user_query = SELECT maildir, 1001 AS uid, 1001 AS gid, CONCAT('dict:storage=',floor(quota/1000),' proxy::quota') as quota FROM mailbox WHERE username = '%u' AND active='1' for PostgreSQL: user_query = SELECT maildir, 1001 AS uid, 1001 AS gid, 'dict:storage=' || floor(quota/1000) || '::proxy::quota' as quota FROM mailbox WHERE username = '%u' AND active='1' Create file dovecot-dict-quota.conf: driver = mysql connect = host=localhost dbname=postfix user=postfix password=postfix default_pass_scheme = MD5-CRYPT table = quota select_field = current where_field = path username_field = username Create database in Mysql: (This is automatically done by postfixadmin's setup.php) Enable quota support in Postfixadmin config.inc.php: $CONF['used_quotas'] = 'YES'; $CONF['quota'] = 'YES'; Note: The above text describes the configuration for dovecot 1.0 & 1.1 quota table format. If you use dovecot 1.2 or newer, - use the 'quota2' table (also created by setup.php) - set $CONF['new_quota_table'] = 'YES' postfixadmin-2.3.7/broadcast-message.php0000664000175000017620000000601611173630034020355 0ustar davidpalepurple 0) { mb_internal_encoding("UTF-8"); $b_name = mb_encode_mimeheader( $_POST['name'], 'UTF-8', 'Q'); $b_subject = mb_encode_mimeheader( $_POST['subject'], 'UTF-8', 'Q'); $b_message = base64_encode($_POST['message']); $i = 0; while ($row = db_array ($result['result'])) { $fTo = $row[0]; $fHeaders = 'To: ' . $fTo . "\n"; $fHeaders .= 'From: ' . $b_name . ' <' . $CONF['admin_email'] . ">\n"; $fHeaders .= 'Subject: ' . $b_subject . "\n"; $fHeaders .= 'MIME-Version: 1.0' . "\n"; $fHeaders .= 'Content-Type: text/plain; charset=UTF-8' . "\n"; $fHeaders .= 'Content-Transfer-Encoding: base64' . "\n"; $fHeaders .= $b_message; if (!smtp_mail ($fTo, $CONF['admin_email'], $fHeaders)) { $tMessage .= "
" . $PALANG['pSendmail_result_error'] . "
"; } else { $tMessage .= "
" . $PALANG['pSendmail_result_success'] . "
"; } } } include ("templates/header.php"); include ("templates/menu.php"); echo '

'.$PALANG['pBroadcast_success'].'

'; include ("templates/footer.php"); } } if ($_SERVER['REQUEST_METHOD'] == "GET" || $error == 1) { include ("templates/header.php"); include ("templates/menu.php"); include ("templates/broadcast-message.php"); include ("templates/footer.php"); } /* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/edit-alias.php0000664000175000017620000001331611703401073017004 0ustar davidpalepurple"; $tMessage .= $PALANG['pEdit_alias_goto_text_error2'] . htmlentities($address) . ""; } } $result = db_query ("SELECT * FROM $table_mailbox WHERE username='$fAddress' AND domain='$fDomain'"); if ($result['rows'] == 1) { if($CONF['alias_control_admin'] == 'NO' && !authentication_has_role('global-admin')) { // if original record had a mailbox alias, so ensure the updated one does too. if(in_array($fAddress, $orig_alias_list)) { $new_aliases[] = $fAddress; } } } // duplicates suck, mmkay.. $new_aliases = array_unique($new_aliases); $goto = implode(',', $new_aliases); if ($error != 1) { $goto = escape_string($goto); $result = db_query ("UPDATE $table_alias SET goto='$goto',modified=NOW() WHERE address='$fAddress' AND domain='$fDomain'"); if ($result['rows'] != 1) { $tMessage = $PALANG['pEdit_alias_result_error']; } else { db_log ($SESSID_USERNAME, $fDomain, 'edit_alias', "$fAddress -> $goto"); header ("Location: list-virtual.php?domain=$fDomain"); exit; } } else { # on error $tGoto = htmlentities($_POST['fGoto']); } } $fAddress = htmlentities($fAddress, ENT_QUOTES); $fDomain = htmlentities($fDomain, ENT_QUOTES); include ("templates/header.php"); include ("templates/menu.php"); include ("templates/edit-alias.php"); include ("templates/footer.php"); /* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/create-alias-domain.php0000664000175000017620000001041011172426302020561 0ustar davidpalepurple 0) { while ($row = db_array ($result['result'])) { $list_aliases[ $row['alias_domain'] ] = $row['target_domain']; } } # filter available alias domains $alias_domains = array(); foreach ($list_domains as $dom) { if (isset($list_aliases[$dom]) || in_array($dom,$list_aliases)) continue; $alias_domains[] = $dom; } if (count($alias_domains) == 0) { $error = 1; $tMessage = $PALANG['pCreate_alias_domain_error4']; } # filter available target domains foreach ($list_domains as $dom) { if (isset($list_aliases[$dom])) continue; $target_domains[] = $dom; } if (isset ($_REQUEST['alias_domain'])) { $fAliasDomain = escape_string ($_REQUEST['alias_domain']); $fAliasDomain = strtolower ($fAliasDomain); } if (isset ($_REQUEST['target_domain'])) { $fTargetDomain = escape_string ($_REQUEST['target_domain']); $fTargetDomain = strtolower ($fTargetDomain); } if (isset ($_REQUEST['active'])) { $fActive = (bool)$_REQUEST['active']; } else { $fActive = true; } if ($_SERVER['REQUEST_METHOD'] == "POST") { if(!authentication_has_role ('global-admin') && !(check_owner ($SESSID_USERNAME, $fAliasDomain) && check_owner ($SESSID_USERNAME, $fTargetDomain))) { $error = 1; $tMessage = $PALANG['pCreate_alias_domain_error1']; } if (isset($list_aliases[$fAliasDomain]) || // alias_domain is unique (primary key, a domain can't be an alias for multiple others) in_array($fAliasDomain,$list_aliases) || // an alias_domain can't be a target_domain for a third domain. isset($list_aliases[$fTargetDomain]) || // same as above, other way around ($fAliasDomain == $fTargetDomain) || // i really don't have to empty($fAliasDomain) || empty($fTargetDomain)) // explain this, do i? { $error = 1; $tMessage = $PALANG['pCreate_alias_domain_error2']; } $sqlActive = db_get_boolean($fActive); if ($error != 1) { $result = db_query ("INSERT INTO $table_alias_domain (alias_domain,target_domain,created,modified,active) VALUES ('$fAliasDomain','$fTargetDomain',NOW(),NOW(),'$sqlActive')"); if ($result['rows'] != 1) { $error = 1; $tMessage = $PALANG['pCreate_alias_domain_error3']; } else { db_log ($SESSID_USERNAME, $fAliasDomain, 'create_alias_domain', "$fAliasDomain -> $fTargetDomain"); flash_info($PALANG['pCreate_alias_domain_success']); # we would have to update the list of domains available for aliasing. Doing a redirect is easier. header("Location: " . $CONF['postfix_admin_url'] . "/create-alias-domain.php"); exit; } } $tMessage .= "
($fAliasDomain -> $fTargetDomain)
\n"; } include ("templates/header.php"); include ("templates/menu.php"); include ("templates/create-alias-domain.php"); include ("templates/footer.php"); /* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/LICENSE.TXT0000664000175000017620000000304111004713202015726 0ustar davidpalepurple Postfix Admin is a Web Based Management tool created for Postfix. It is a PHP based application that handles Postfix Style Virtual Domains and Users that are stored in MySQL. Copyright (c) 2005 High5! (Mischa Peters and others) This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Postfix Admin verion 2.1.1, Copyright (c) 2005 High5! (Mischa Peters & Contributors) Postfix Admin comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. High5!, hereby disclaims all copyright interest in the program `Postfix Admin' (which makes passes at Postfix, PHP and MySQL) written by Wietse Venema, PHP Group and MYSQL AB. Contributors: Mihau, Tarvin, SteveB, DJTremors, WhiteFox, David Osborn, David Goodwin (GingerDog), Christian Boltz (cboltz) and GregC and others. postfixadmin-2.3.7/motd.txt0000664000175000017620000000041010715711016015755 0ustar davidpalepurple

postfixadmin-2.3.7/delete.php0000664000175000017620000001406211425627625016247 0ustar davidpalepurple= 0)) { $error = 1; $tMessage = $PALANG['pAdminDelete_admin_error']; } else { $url = "list-admin.php"; header ("Location: $url"); } } # ($fTable == "admin") elseif ($fTable == "domain") { authentication_require_role('global-admin'); $fWhere = 'domain'; $result_domain_admins = db_delete ($table_domain_admins,$fWhere,$fDelete); $result_alias = db_delete ($table_alias,$fWhere,$fDelete); $result_mailbox = db_delete ($table_mailbox,$fWhere,$fDelete); $result_alias_domain = db_delete($table_alias_domain,'alias_domain',$fDelete); $result_log = db_delete ($table_log,$fWhere,$fDelete); if ($CONF['vacation'] == "YES") { $result_vacation = db_delete ($table_vacation,$fWhere,$fDelete); } $result_domain = db_delete ($table_domain,$fWhere,$fDelete); if (!$result_domain || !domain_postdeletion($fDelete)) { $error = 1; $tMessage = $PALANG['pAdminDelete_domain_error']; } else { $url = "list-domain.php"; header ("Location: $url"); } } # ($fTable == "domain") elseif ($fTable == "alias_domain") { authentication_require_role('global-admin'); $table_domain_alias = table_by_key('alias_domain'); $fWhere = 'alias_domain'; $fDelete = $fDomain; if(db_delete($table_domain_alias,$fWhere,$fDelete)) { $url = "list-domain.php"; header ("Location: $url"); } } # ($fTable == "alias_domain") elseif ($fTable == "alias" or $fTable == "mailbox") { if (!check_owner ($SESSID_USERNAME, $fDomain)) { $error = 1; $tMessage = $PALANG['pDelete_domain_error'] . "$fDomain!"; } elseif (!check_alias_owner ($SESSID_USERNAME, $fDelete)) { $error = 1; $tMessage = $PALANG['pDelete_alias_error'] . "$fDelete!"; } else { if ($CONF['database_type'] == "pgsql") db_query('BEGIN'); /* there may be no aliases to delete */ $result = db_query("SELECT * FROM $table_alias WHERE address = '$fDelete' AND domain = '$fDomain'"); if($result['rows'] == 1) { $result = db_query ("DELETE FROM $table_alias WHERE address='$fDelete' AND domain='$fDomain'"); db_log ($SESSID_USERNAME, $fDomain, 'delete_alias', $fDelete); } /* is there a mailbox? if do delete it from orbit; it's the only way to be sure */ $result = db_query ("SELECT * FROM $table_mailbox WHERE username='$fDelete' AND domain='$fDomain'"); if ($result['rows'] == 1) { $result = db_query ("DELETE FROM $table_mailbox WHERE username='$fDelete' AND domain='$fDomain'"); $postdel_res=mailbox_postdeletion($fDelete,$fDomain); if ($result['rows'] != 1 || !$postdel_res) { $error = 1; $tMessage = $PALANG['pDelete_delete_error'] . "$fDelete ("; if ($result['rows']!=1) { $tMessage.='mailbox'; if (!$postdel_res) $tMessage.=', '; } if (!$postdel_res) { $tMessage.='post-deletion'; } $tMessage.=')'; } db_log ($SESSID_USERNAME, $fDomain, 'delete_mailbox', $fDelete); $result = db_query("SELECT * FROM $table_quota WHERE username='$fDelete'"); if($result['rows'] >= 1) { db_query ("DELETE FROM $table_quota WHERE username='$fDelete'"); } $result = db_query("SELECT * FROM $table_quota2 WHERE username='$fDelete'"); if($result['rows'] == 1) { db_query ("DELETE FROM $table_quota2 WHERE username='$fDelete'"); } } $result = db_query("SELECT * FROM $table_vacation WHERE email = '$fDelete' AND domain = '$fDomain'"); if($result['rows'] == 1) { db_query ("DELETE FROM $table_vacation WHERE email='$fDelete' AND domain='$fDomain'"); db_query ("DELETE FROM $table_vacation_notification WHERE on_vacation ='$fDelete' "); /* should be caught by cascade, if PgSQL */ } } if ($error != 1) { if ($CONF['database_type'] == "pgsql") db_query('COMMIT'); header ("Location: list-virtual.php?domain=$fDomain"); exit; } else { $tMessage .= $PALANG['pDelete_delete_error'] . "$fDelete (physical mail)!"; if ($CONF['database_type'] == "pgsql") db_query('ROLLBACK'); } } else { flash_error($PALANG['invalid_parameter']); } include ("templates/header.php"); include ("templates/menu.php"); include ("templates/message.php"); include ("templates/footer.php"); /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ ?> postfixadmin-2.3.7/variables.inc.php0000664000175000017620000000440211225725773017523 0ustar davidpalepurple 0 AND NOT a.attisdropped AND a.attrelid = ( SELECT c.oid FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relname ~ ' . "'^($table)\$' AND pg_catalog.pg_table_is_visible(c.oid) ) AND a.attname = '$field' "; $r = db_query($sql); $row = db_row($r['result']); if($row) { return true; } return false; } function _mysql_field_exists($table, $field) { $sql = "SHOW COLUMNS FROM $table LIKE '$field'"; $r = db_query($sql); $row = db_row($r['result']); if($row) { return true; } return false; } $table = table_by_key('config'); if($CONF['database_type'] == 'pgsql') { // check if table already exists, if so, don't recreate it $r = db_query("SELECT relname FROM pg_class WHERE relname = '$table'"); if($r['rows'] == 0) { $pgsql = " CREATE TABLE $table ( id SERIAL, name VARCHAR(20) NOT NULL UNIQUE, value VARCHAR(20) NOT NULL, PRIMARY KEY(id) )"; db_query_parsed($pgsql); } } else { $mysql = " CREATE TABLE {IF_NOT_EXISTS} $table ( `id` {AUTOINCREMENT} {PRIMARY}, `name` VARCHAR(20) {LATIN1} NOT NULL DEFAULT '', `value` VARCHAR(20) {LATIN1} NOT NULL DEFAULT '', UNIQUE name ( `name` ) ) "; db_query_parsed($mysql, 0, " ENGINE = MYISAM COMMENT = 'PostfixAdmin settings'"); } $sql = "SELECT * FROM $table WHERE name = 'version'"; // insert into config('version', '01'); $r = db_query($sql); if($r['rows'] == 1) { $rs = $r['result']; $row = db_array($rs); $version = $row['value']; } else { db_query_parsed("INSERT INTO $table (name, value) VALUES ('version', '0')", 0, ''); $version = 0; } _do_upgrade($version); function _do_upgrade($current_version) { global $CONF; # $target_version = preg_replace('/[^0-9]/', '', '$Revision: 1521 $'); $target_version = 740; # hardcoded target version for 2.3 branch - increase (by one) if database changes in the branch are necessary if ($current_version >= $target_version) { # already up to date echo "

Database is up to date

"; return true; } echo "

Updating database:

- old version: $current_version; target version: $target_version

"; for ($i = $current_version +1; $i <= $target_version; $i++) { $function = "upgrade_$i"; $function_mysql = $function . "_mysql"; $function_pgsql = $function . "_pgsql"; if (function_exists($function)) { echo "

updating to version $i (all databases)..."; $function(); echo "   done"; } if ($CONF['database_type'] == 'mysql' || $CONF['database_type'] == 'mysqli' ) { if (function_exists($function_mysql)) { echo "

updating to version $i (MySQL)..."; $function_mysql(); echo "   done"; } } elseif($CONF['database_type'] == 'pgsql') { if (function_exists($function_pgsql)) { echo "

updating to version $i (PgSQL)..."; $function_pgsql(); echo "   done"; } } // Update config table so we don't run the same query twice in the future. $i = (int) $i; $table = table_by_key('config'); $sql = "UPDATE $table SET value = $i WHERE name = 'version'"; db_query($sql); }; } /** * Replaces database specific parts in a query * @param String sql query with placeholders * @param int (optional) whether errors should be ignored (0=false) * @param String (optional) MySQL specific code to attach, useful for COMMENT= on CREATE TABLE * @return String sql query */ function db_query_parsed($sql, $ignore_errors = 0, $attach_mysql = "") { global $CONF; if ($CONF['database_type'] == 'mysql' || $CONF['database_type'] == 'mysqli' ) { $replace = array( '{AUTOINCREMENT}' => 'int(11) not null auto_increment', '{PRIMARY}' => 'primary key', '{UNSIGNED}' => 'unsigned' , '{FULLTEXT}' => 'FULLTEXT', '{BOOLEAN}' => 'tinyint(1) NOT NULL', '{UTF-8}' => '/*!40100 CHARACTER SET utf8 */', '{LATIN1}' => '/*!40100 CHARACTER SET latin1 */', '{IF_NOT_EXISTS}' => 'IF NOT EXISTS', '{RENAME_COLUMN}' => 'CHANGE COLUMN', '{MYISAM}' => 'ENGINE=MyISAM', '{INNODB}' => 'ENGINE=InnoDB', '{BIGINT}' => 'bigint', ); $sql = "$sql $attach_mysql"; } elseif($CONF['database_type'] == 'pgsql') { $replace = array( '{AUTOINCREMENT}' => 'SERIAL', '{PRIMARY}' => 'primary key', '{UNSIGNED}' => '', '{FULLTEXT}' => '', '{BOOLEAN}' => 'BOOLEAN NOT NULL', '{UTF-8}' => '', # UTF-8 is simply ignored. '{LATIN1}' => '', # same for latin1 '{IF_NOT_EXISTS}' => '', # does not work with PgSQL '{RENAME_COLUMN}' => 'ALTER COLUMN', # PgSQL : ALTER TABLE x RENAME x TO y '{MYISAM}' => '', '{INNODB}' => '', '{BIGINT}' => 'bigint', 'int(1)' => 'int', 'int(10)' => 'int', 'int(11)' => 'int', 'int(4)' => 'int', ); } else { echo "Sorry, unsupported database type " . $conf['database_type']; exit; } $replace['{BOOL_TRUE}'] = db_get_boolean(True); $replace['{BOOL_FALSE}'] = db_get_boolean(False); $query = trim(str_replace(array_keys($replace), $replace, $sql)); if (safeget('debug') != "") { print "

$query"; } $result = db_query($query, $ignore_errors); if (safeget('debug') != "") { print "

" . $result['error'] . "
"; } return $result; } function _drop_index ($table, $index) { global $CONF; $table = table_by_key ($table); if ($CONF['database_type'] == 'mysql' || $CONF['database_type'] == 'mysqli' ) { return "ALTER TABLE $table DROP INDEX $index"; } elseif($CONF['database_type'] == 'pgsql') { return "DROP INDEX $index"; # Index names are unique with a DB for PostgreSQL } else { echo "Sorry, unsupported database type " . $conf['database_type']; exit; } } function _add_index($table, $indexname, $fieldlist) { global $CONF; $table = table_by_key ($table); if ($CONF['database_type'] == 'mysql' || $CONF['database_type'] == 'mysqli' ) { return "ALTER TABLE $table ADD INDEX `$indexname` ( `$fieldlist` )"; } elseif($CONF['database_type'] == 'pgsql') { $pgindexname = $table . "_" . $indexname . '_idx'; return "CREATE INDEX $pgindexname ON $table($fieldlist);"; # Index names are unique with a DB for PostgreSQL } else { echo "Sorry, unsupported database type " . $conf['database_type']; exit; } } function upgrade_1_mysql() { // CREATE MYSQL DATABASE TABLES. $admin = table_by_key('admin'); $alias = table_by_key('alias'); $domain = table_by_key('domain'); $domain_admins = table_by_key('domain_admins'); $log = table_by_key('log'); $mailbox = table_by_key('mailbox'); $vacation = table_by_key('vacation'); $sql = array(); $sql[] = " CREATE TABLE {IF_NOT_EXISTS} $admin ( `username` varchar(255) NOT NULL default '', `password` varchar(255) NOT NULL default '', `created` datetime NOT NULL default '0000-00-00 00:00:00', `modified` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`username`) ) {MYISAM} COMMENT='Postfix Admin - Virtual Admins';"; $sql[] = " CREATE TABLE {IF_NOT_EXISTS} $alias ( `address` varchar(255) NOT NULL default '', `goto` text NOT NULL, `domain` varchar(255) NOT NULL default '', `created` datetime NOT NULL default '0000-00-00 00:00:00', `modified` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`address`) ) {MYISAM} COMMENT='Postfix Admin - Virtual Aliases'; "; $sql[] = " CREATE TABLE {IF_NOT_EXISTS} $domain ( `domain` varchar(255) NOT NULL default '', `description` varchar(255) NOT NULL default '', `aliases` int(10) NOT NULL default '0', `mailboxes` int(10) NOT NULL default '0', `maxquota` bigint(20) NOT NULL default '0', `quota` bigint(20) NOT NULL default '0', `transport` varchar(255) default NULL, `backupmx` tinyint(1) NOT NULL default '0', `created` datetime NOT NULL default '0000-00-00 00:00:00', `modified` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`domain`) ) {MYISAM} COMMENT='Postfix Admin - Virtual Domains'; "; $sql[] = " CREATE TABLE {IF_NOT_EXISTS} $domain_admins ( `username` varchar(255) NOT NULL default '', `domain` varchar(255) NOT NULL default '', `created` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', KEY username (`username`) ) {MYISAM} COMMENT='Postfix Admin - Domain Admins';"; $sql[] = " CREATE TABLE {IF_NOT_EXISTS} $log ( `timestamp` datetime NOT NULL default '0000-00-00 00:00:00', `username` varchar(255) NOT NULL default '', `domain` varchar(255) NOT NULL default '', `action` varchar(255) NOT NULL default '', `data` varchar(255) NOT NULL default '', KEY timestamp (`timestamp`) ) {MYISAM} COMMENT='Postfix Admin - Log';"; $sql[] = " CREATE TABLE {IF_NOT_EXISTS} $mailbox ( `username` varchar(255) NOT NULL default '', `password` varchar(255) NOT NULL default '', `name` varchar(255) NOT NULL default '', `maildir` varchar(255) NOT NULL default '', `quota` bigint(20) NOT NULL default '0', `domain` varchar(255) NOT NULL default '', `created` datetime NOT NULL default '0000-00-00 00:00:00', `modified` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`username`) ) {MYISAM} COMMENT='Postfix Admin - Virtual Mailboxes';"; $sql[] = " CREATE TABLE {IF_NOT_EXISTS} $vacation ( email varchar(255) NOT NULL , subject varchar(255) NOT NULL, body text NOT NULL, cache text NOT NULL, domain varchar(255) NOT NULL , created datetime NOT NULL default '0000-00-00 00:00:00', active tinyint(4) NOT NULL default '1', PRIMARY KEY (email), KEY email (email) ) {INNODB} DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Vacation' ;"; foreach($sql as $query) { db_query_parsed($query); } } function upgrade_2_mysql() { # upgrade pre-2.1 database # from TABLE_BACKUP_MX.TXT $table_domain = table_by_key ('domain'); if(!_mysql_field_exists($table_domain, 'transport')) { $result = db_query_parsed("ALTER TABLE $table_domain ADD COLUMN transport VARCHAR(255) AFTER maxquota;", TRUE); } if(!_mysql_field_exists($table_domain, 'backupmx')) { $result = db_query_parsed("ALTER TABLE $table_domain ADD COLUMN backupmx {BOOLEAN} DEFAULT {BOOL_FALSE} AFTER transport;", TRUE); } } function upgrade_2_pgsql() { if(!_pgsql_object_exists(table_by_key('domain'))) { db_query_parsed(" CREATE TABLE " . table_by_key('domain') . " ( domain character varying(255) NOT NULL, description character varying(255) NOT NULL default '', aliases integer NOT NULL default 0, mailboxes integer NOT NULL default 0, maxquota integer NOT NULL default 0, quota integer NOT NULL default 0, transport character varying(255) default NULL, backupmx boolean NOT NULL default false, created timestamp with time zone default now(), modified timestamp with time zone default now(), active boolean NOT NULL default true, Constraint \"domain_key\" Primary Key (\"domain\") ); CREATE INDEX domain_domain_active ON " . table_by_key('domain') . "(domain,active); COMMENT ON TABLE " . table_by_key('domain') . " IS 'Postfix Admin - Virtual Domains'; "); } if(!_pgsql_object_exists(table_by_key('admin'))) { db_query_parsed(' CREATE TABLE ' . table_by_key("admin") . ' ( "username" character varying(255) NOT NULL, "password" character varying(255) NOT NULL default \'\', "created" timestamp with time zone default now(), "modified" timestamp with time zone default now(), "active" boolean NOT NULL default true, Constraint "admin_key" Primary Key ("username") );' . " COMMENT ON TABLE " . table_by_key('admin') . " IS 'Postfix Admin - Virtual Admins'; "); } if(!_pgsql_object_exists(table_by_key('alias'))) { db_query_parsed(' CREATE TABLE ' . table_by_key("alias") . ' ( address character varying(255) NOT NULL, goto text NOT NULL, domain character varying(255) NOT NULL REFERENCES "' . table_by_key("domain") . '", created timestamp with time zone default now(), modified timestamp with time zone default now(), active boolean NOT NULL default true, Constraint "alias_key" Primary Key ("address") ); CREATE INDEX alias_address_active ON ' . table_by_key("alias") . '(address,active); COMMENT ON TABLE ' . table_by_key("alias") . ' IS \'Postfix Admin - Virtual Aliases\'; '); } if(!_pgsql_object_exists(table_by_key('domain_admins'))) { db_query_parsed(' CREATE TABLE ' . table_by_key('domain_admins') . ' ( username character varying(255) NOT NULL, domain character varying(255) NOT NULL REFERENCES "' . table_by_key('domain') . '", created timestamp with time zone default now(), active boolean NOT NULL default true ); COMMENT ON TABLE ' . table_by_key('domain_admins') . ' IS \'Postfix Admin - Domain Admins\'; '); } if(!_pgsql_object_exists(table_by_key('log'))) { db_query_parsed(' CREATE TABLE ' . table_by_key('log') . ' ( timestamp timestamp with time zone default now(), username character varying(255) NOT NULL default \'\', domain character varying(255) NOT NULL default \'\', action character varying(255) NOT NULL default \'\', data text NOT NULL default \'\' ); COMMENT ON TABLE ' . table_by_key('log') . ' IS \'Postfix Admin - Log\'; '); } if(!_pgsql_object_exists(table_by_key('mailbox'))) { db_query_parsed(' CREATE TABLE ' . table_by_key('mailbox') . ' ( username character varying(255) NOT NULL, password character varying(255) NOT NULL default \'\', name character varying(255) NOT NULL default \'\', maildir character varying(255) NOT NULL default \'\', quota integer NOT NULL default 0, domain character varying(255) NOT NULL REFERENCES "' . table_by_key('domain') . '", created timestamp with time zone default now(), modified timestamp with time zone default now(), active boolean NOT NULL default true, Constraint "mailbox_key" Primary Key ("username") ); CREATE INDEX mailbox_username_active ON ' . table_by_key('mailbox') . '(username,active); COMMENT ON TABLE ' . table_by_key('mailbox') . ' IS \'Postfix Admin - Virtual Mailboxes\'; '); } if(!_pgsql_object_exists(table_by_key('vacation'))) { db_query_parsed(' CREATE TABLE ' . table_by_key('vacation') . ' ( email character varying(255) PRIMARY KEY, subject character varying(255) NOT NULL, body text NOT NULL , cache text NOT NULL , "domain" character varying(255) NOT NULL REFERENCES "' . table_by_key('domain') . '", created timestamp with time zone DEFAULT now(), active boolean DEFAULT true NOT NULL ); CREATE INDEX vacation_email_active ON ' . table_by_key('vacation') . '(email,active);'); } if(!_pgsql_object_exists(table_by_key('vacation_notification'))) { db_query_parsed(' CREATE TABLE ' . table_by_key('vacation_notification') . ' ( on_vacation character varying(255) NOT NULL REFERENCES ' . table_by_key('vacation') . '(email) ON DELETE CASCADE, notified character varying(255) NOT NULL, notified_at timestamp with time zone NOT NULL DEFAULT now(), CONSTRAINT vacation_notification_pkey primary key(on_vacation,notified) ); '); } // this handles anyone who is upgrading... (and should have no impact on new installees) $table_domain = table_by_key ('domain'); $result = db_query_parsed("ALTER TABLE $table_domain ADD COLUMN transport VARCHAR(255)", TRUE); $result = db_query_parsed("ALTER TABLE $table_domain ADD COLUMN backupmx BOOLEAN DEFAULT false", TRUE); } function upgrade_3_mysql() { # upgrade pre-2.1 database # from TABLE_CHANGES.TXT $table_admin = table_by_key ('admin'); $table_alias = table_by_key ('alias'); $table_domain = table_by_key ('domain'); $table_mailbox = table_by_key ('mailbox'); $table_vacation = table_by_key ('vacation'); if(!_mysql_field_exists($table_admin, 'created')) { db_query_parsed("ALTER TABLE $table_admin {RENAME_COLUMN} create_date created DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL;"); } if(!_mysql_field_exists($table_admin, 'modified')) { db_query_parsed("ALTER TABLE $table_admin {RENAME_COLUMN} change_date modified DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL;"); } if(!_mysql_field_exists($table_alias, 'created')) { db_query_parsed("ALTER TABLE $table_alias {RENAME_COLUMN} create_date created DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL;"); } if(!_mysql_field_exists($table_alias, 'modified')) { db_query_parsed("ALTER TABLE $table_alias {RENAME_COLUMN} change_date modified DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL;"); } if(!_mysql_field_exists($table_domain, 'created')) { db_query_parsed("ALTER TABLE $table_domain {RENAME_COLUMN} create_date created DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL;"); } if(!_mysql_field_exists($table_domain, 'modified')) { db_query_parsed("ALTER TABLE $table_domain {RENAME_COLUMN} change_date modified DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL;"); } if(!_mysql_field_exists($table_domain, 'aliases')) { db_query_parsed("ALTER TABLE $table_domain ADD COLUMN aliases INT(10) DEFAULT '-1' NOT NULL AFTER description;"); } if(!_mysql_field_exists($table_domain, 'mailboxes')) { db_query_parsed("ALTER TABLE $table_domain ADD COLUMN mailboxes INT(10) DEFAULT '-1' NOT NULL AFTER aliases;"); } if(!_mysql_field_exists($table_domain, 'maxquota')) { db_query_parsed("ALTER TABLE $table_domain ADD COLUMN maxquota INT(10) DEFAULT '-1' NOT NULL AFTER mailboxes;"); } if(!_mysql_field_exists($table_domain, 'transport')) { db_query_parsed("ALTER TABLE $table_domain ADD COLUMN transport VARCHAR(255) AFTER maxquota;"); } if(!_mysql_field_exists($table_domain, 'backupmx')) { db_query_parsed("ALTER TABLE $table_domain ADD COLUMN backupmx TINYINT(1) DEFAULT '0' NOT NULL AFTER transport;"); } if(!_mysql_field_exists($table_mailbox, 'created')) { db_query_parsed("ALTER TABLE $table_mailbox {RENAME_COLUMN} create_date created DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL;"); } if(!_mysql_field_exists($table_mailbox, 'modified')) { db_query_parsed("ALTER TABLE $table_mailbox {RENAME_COLUMN} change_date modified DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL;"); } if(!_mysql_field_exists($table_mailbox, 'quota')) { db_query_parsed("ALTER TABLE $table_mailbox ADD COLUMN quota INT(10) DEFAULT '-1' NOT NULL AFTER maildir;"); } if(!_mysql_field_exists($table_vacation, 'domain')) { db_query_parsed("ALTER TABLE $table_vacation ADD COLUMN domain VARCHAR(255) DEFAULT '' NOT NULL AFTER cache;"); } if(!_mysql_field_exists($table_vacation, 'created')) { db_query_parsed("ALTER TABLE $table_vacation ADD COLUMN created DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL AFTER domain;"); } if(!_mysql_field_exists($table_vacation, 'active')) { db_query_parsed("ALTER TABLE $table_vacation ADD COLUMN active TINYINT(1) DEFAULT '1' NOT NULL AFTER created;"); } db_query_parsed("ALTER TABLE $table_vacation DROP PRIMARY KEY"); db_query_parsed("ALTER TABLE $table_vacation ADD PRIMARY KEY(email)"); db_query_parsed("UPDATE $table_vacation SET domain=SUBSTRING_INDEX(email, '@', -1) WHERE email=email;"); } function upgrade_4_mysql() { # MySQL only # changes between 2.1 and moving to sourceforge $table_domain = table_by_key ('domain'); $result = db_query_parsed("ALTER TABLE $table_domain ADD COLUMN quota int(10) NOT NULL default '0' AFTER maxquota", TRUE); # Possible errors that can be ignored: # - Invalid query: Table 'postfix.domain' doesn't exist } /** * Changes between 2.1 and moving to sf.net */ function upgrade_4_pgsql() { $table_domain = table_by_key('domain'); $table_admin = table_by_key('admin'); $table_alias = table_by_key('alias'); $table_domain_admins = table_by_key('domain_admins'); $table_log = table_by_key('log'); $table_mailbox = table_by_key('mailbox'); $table_vacation = table_by_key('vacation'); $table_vacation_notification = table_by_key('vacation_notification'); if(!_pgsql_field_exists($table_domain, 'quota')) { $result = db_query_parsed("ALTER TABLE $table_domain ADD COLUMN quota int NOT NULL default '0'"); } $result = db_query_parsed("ALTER TABLE $table_domain ALTER COLUMN domain DROP DEFAULT"); if(!_pgsql_object_exists('domain_domain_active')) { $result = db_query_parsed("CREATE INDEX domain_domain_active ON $table_domain(domain,active)"); } $result = db_query_parsed("ALTER TABLE $table_domain_admins ALTER COLUMN domain DROP DEFAULT"); $result = db_query_parsed("ALTER TABLE $table_alias ALTER COLUMN address DROP DEFAULT"); $result = db_query_parsed("ALTER TABLE $table_alias ALTER COLUMN domain DROP DEFAULT"); if(!_pgsql_object_exists('alias_address_active')) { $result = db_query_parsed("CREATE INDEX alias_address_active ON $table_alias(address,active)"); } $result = db_query_parsed("ALTER TABLE $table_domain_admins ALTER COLUMN username DROP DEFAULT"); $result = db_query_parsed("ALTER TABLE $table_domain_admins ALTER COLUMN domain DROP DEFAULT"); $result = db_query_parsed(" BEGIN; ALTER TABLE $table_log RENAME COLUMN data TO data_old; ALTER TABLE $table_log ADD COLUMN data text NOT NULL default ''; UPDATE $table_log SET data = CAST(data_old AS text); ALTER TABLE $table_log DROP COLUMN data_old; COMMIT;"); $result = db_query_parsed("ALTER TABLE $table_mailbox ALTER COLUMN username DROP DEFAULT"); $result = db_query_parsed("ALTER TABLE $table_mailbox ALTER COLUMN domain DROP DEFAULT"); $result = db_query_parsed(" BEGIN; ALTER TABLE $table_mailbox RENAME COLUMN domain TO domain_old; ALTER TABLE $table_mailbox ADD COLUMN domain varchar(255) REFERENCES $table_domain (domain); UPDATE $table_mailbox SET domain = domain_old; ALTER TABLE $table_mailbox DROP COLUMN domain_old; COMMIT;" ); if(!_pgsql_object_exists('mailbox_username_active')) { db_query_parsed("CREATE INDEX mailbox_username_active ON $table_mailbox(username,active)"); } $result = db_query_parsed("ALTER TABLE $table_vacation ALTER COLUMN body SET DEFAULT ''"); if(_pgsql_field_exists($table_vacation, 'cache')) { $result = db_query_parsed("ALTER TABLE $table_vacation DROP COLUMN cache"); } $result = db_query_parsed(" BEGIN; ALTER TABLE $table_vacation RENAME COLUMN domain to domain_old; ALTER TABLE $table_vacation ADD COLUMN domain varchar(255) REFERENCES $table_domain; UPDATE $table_vacation SET domain = domain_old; ALTER TABLE $table_vacation DROP COLUMN domain_old; COMMIT; "); if(!_pgsql_object_exists('vacation_email_active')) { $result = db_query_parsed("CREATE INDEX vacation_email_active ON $table_vacation(email,active)"); } if(!_pgsql_object_exists($table_vacation_notification)) { $result = db_query_parsed(" CREATE TABLE $table_vacation_notification ( on_vacation character varying(255) NOT NULL REFERENCES $table_vacation(email) ON DELETE CASCADE, notified character varying(255) NOT NULL, notified_at timestamp with time zone NOT NULL DEFAULT now(), CONSTRAINT vacation_notification_pkey primary key(on_vacation,notified));"); } } # Possible errors that can be ignored: # # NO MySQL errors should be ignored below this line! /** * create tables * version: Sourceforge SVN r1 of DATABASE_MYSQL.txt * changes compared to DATABASE_MYSQL.txt: * - removed MySQL user and database creation * - removed creation of default superadmin */ function upgrade_5_mysql() { $result = db_query_parsed(" CREATE TABLE {IF_NOT_EXISTS} `" . table_by_key('admin') . "` ( `username` varchar(255) NOT NULL default '', `password` varchar(255) NOT NULL default '', `created` datetime NOT NULL default '0000-00-00 00:00:00', `modified` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`username`), KEY username (`username`) ) {MYISAM} DEFAULT {LATIN1} COMMENT='Postfix Admin - Virtual Admins'; "); $result = db_query_parsed(" CREATE TABLE {IF_NOT_EXISTS} `" . table_by_key('alias') . "` ( `address` varchar(255) NOT NULL default '', `goto` text NOT NULL, `domain` varchar(255) NOT NULL default '', `created` datetime NOT NULL default '0000-00-00 00:00:00', `modified` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`address`), KEY address (`address`) ) {MYISAM} DEFAULT {LATIN1} COMMENT='Postfix Admin - Virtual Aliases'; "); $result = db_query_parsed(" CREATE TABLE {IF_NOT_EXISTS} `" . table_by_key('domain') . "` ( `domain` varchar(255) NOT NULL default '', `description` varchar(255) NOT NULL default '', `aliases` int(10) NOT NULL default '0', `mailboxes` int(10) NOT NULL default '0', `maxquota` int(10) NOT NULL default '0', `quota` int(10) NOT NULL default '0', `transport` varchar(255) default NULL, `backupmx` tinyint(1) NOT NULL default '0', `created` datetime NOT NULL default '0000-00-00 00:00:00', `modified` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`domain`), KEY domain (`domain`) ) {MYISAM} DEFAULT {LATIN1} COMMENT='Postfix Admin - Virtual Domains'; "); $result = db_query_parsed(" CREATE TABLE {IF_NOT_EXISTS} `" . table_by_key('domain_admins') . "` ( `username` varchar(255) NOT NULL default '', `domain` varchar(255) NOT NULL default '', `created` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', KEY username (`username`) ) {MYISAM} DEFAULT {LATIN1} COMMENT='Postfix Admin - Domain Admins'; "); $result = db_query_parsed(" CREATE TABLE {IF_NOT_EXISTS} `" . table_by_key('log') . "` ( `timestamp` datetime NOT NULL default '0000-00-00 00:00:00', `username` varchar(255) NOT NULL default '', `domain` varchar(255) NOT NULL default '', `action` varchar(255) NOT NULL default '', `data` varchar(255) NOT NULL default '', KEY timestamp (`timestamp`) ) {MYISAM} DEFAULT {LATIN1} COMMENT='Postfix Admin - Log'; "); $result = db_query_parsed(" CREATE TABLE {IF_NOT_EXISTS} `" . table_by_key('mailbox') . "` ( `username` varchar(255) NOT NULL default '', `password` varchar(255) NOT NULL default '', `name` varchar(255) NOT NULL default '', `maildir` varchar(255) NOT NULL default '', `quota` int(10) NOT NULL default '0', `domain` varchar(255) NOT NULL default '', `created` datetime NOT NULL default '0000-00-00 00:00:00', `modified` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`username`), KEY username (`username`) ) {MYISAM} DEFAULT {LATIN1} COMMENT='Postfix Admin - Virtual Mailboxes'; "); $result = db_query_parsed(" CREATE TABLE {IF_NOT_EXISTS} `" . table_by_key('vacation') . "` ( `email` varchar(255) NOT NULL , `subject` varchar(255) NOT NULL, `body` text NOT NULL, `cache` text NOT NULL, `domain` varchar(255) NOT NULL, `created` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`email`), KEY email (`email`) ) {MYISAM} DEFAULT {LATIN1} COMMENT='Postfix Admin - Virtual Vacation'; "); } /** * drop useless indicies (already available as primary key) */ function upgrade_79_mysql() { # MySQL only $result = db_query_parsed(_drop_index('admin', 'username'), True); $result = db_query_parsed(_drop_index('alias', 'address'), True); $result = db_query_parsed(_drop_index('domain', 'domain'), True); $result = db_query_parsed(_drop_index('mailbox', 'username'), True); } function upgrade_81_mysql() { # MySQL only $table_vacation = table_by_key ('vacation'); $table_vacation_notification = table_by_key('vacation_notification'); $all_sql = explode("\n", trim(" ALTER TABLE `$table_vacation` CHANGE `email` `email` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_vacation` CHANGE `subject` `subject` VARCHAR( 255 ) {UTF-8} NOT NULL ALTER TABLE `$table_vacation` CHANGE `body` `body` TEXT {UTF-8} NOT NULL ALTER TABLE `$table_vacation` CHANGE `cache` `cache` TEXT {LATIN1} NOT NULL ALTER TABLE `$table_vacation` CHANGE `domain` `domain` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_vacation` CHANGE `active` `active` TINYINT( 1 ) NOT NULL DEFAULT '1' ALTER TABLE `$table_vacation` DEFAULT {LATIN1} ALTER TABLE `$table_vacation` {INNODB} ")); foreach ($all_sql as $sql) { $result = db_query_parsed($sql, TRUE); } } /** * Make logging translatable - i.e. create alias => create_alias */ function upgrade_90() { $result = db_query_parsed("UPDATE " . table_by_key ('log') . " SET action = REPLACE(action,' ','_')", TRUE); # change edit_alias_state to edit_alias_active $result = db_query_parsed("UPDATE " . table_by_key ('log') . " SET action = 'edit_alias_state' WHERE action = 'edit_alias_active'", TRUE); } /** * MySQL only allow quota > 2 GB */ function upgrade_169_mysql() { $table_domain = table_by_key ('domain'); $table_mailbox = table_by_key ('mailbox'); $result = db_query_parsed("ALTER TABLE $table_domain MODIFY COLUMN `quota` bigint(20) NOT NULL default '0'", TRUE); $result = db_query_parsed("ALTER TABLE $table_domain MODIFY COLUMN `maxquota` bigint(20) NOT NULL default '0'", TRUE); $result = db_query_parsed("ALTER TABLE $table_mailbox MODIFY COLUMN `quota` bigint(20) NOT NULL default '0'", TRUE); } /** * Create / modify vacation_notification table. * Note: This might not work if users used workarounds to create the table before. * In this case, dropping the table is the easiest solution. */ function upgrade_318_mysql() { $table_vacation_notification = table_by_key('vacation_notification'); $table_vacation = table_by_key('vacation'); db_query_parsed( " CREATE TABLE {IF_NOT_EXISTS} $table_vacation_notification ( on_vacation varchar(255) {LATIN1} NOT NULL, notified varchar(255) {LATIN1} NOT NULL, notified_at timestamp NOT NULL default CURRENT_TIMESTAMP, PRIMARY KEY on_vacation (`on_vacation`, `notified`), CONSTRAINT `vacation_notification_pkey` FOREIGN KEY (`on_vacation`) REFERENCES $table_vacation(`email`) ON DELETE CASCADE ) {INNODB} COMMENT='Postfix Admin - Virtual Vacation Notifications' "); # in case someone has manually created the table with utf8 fields before: $all_sql = explode("\n", trim(" ALTER TABLE `$table_vacation_notification` CHANGE `notified` `notified` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_vacation_notification` DEFAULT CHARACTER SET utf8 ")); # Possible errors that can be ignored: # None. # If something goes wrong, the user should drop the vacation_notification table # (not a great loss) and re-create it using this function. foreach ($all_sql as $sql) { $result = db_query_parsed($sql); } } /** * Create fetchmail table */ function upgrade_344_mysql() { $table_fetchmail = table_by_key('fetchmail'); db_query_parsed( " CREATE TABLE IF NOT EXISTS $table_fetchmail( id int(11) unsigned not null auto_increment, mailbox varchar(255) not null default '', src_server varchar(255) not null default '', src_auth enum('password','kerberos_v5','kerberos','kerberos_v4','gssapi','cram-md5','otp','ntlm','msn','ssh','any'), src_user varchar(255) not null default '', src_password varchar(255) not null default '', src_folder varchar(255) not null default '', poll_time int(11) unsigned not null default 10, fetchall tinyint(1) unsigned not null default 0, keep tinyint(1) unsigned not null default 0, protocol enum('POP3','IMAP','POP2','ETRN','AUTO'), extra_options text, returned_text text, mda varchar(255) not null default '', date timestamp, primary key(id) ); "); } function upgrade_344_pgsql() { $fetchmail = table_by_key('fetchmail'); // a field name called 'date' is probably a bad idea. if(!_pgsql_object_exists('fetchmail')) { db_query_parsed( " create table $fetchmail( id serial, mailbox varchar(255) not null default '', src_server varchar(255) not null default '', src_auth varchar(15) NOT NULL, src_user varchar(255) not null default '', src_password varchar(255) not null default '', src_folder varchar(255) not null default '', poll_time integer not null default 10, fetchall boolean not null default false, keep boolean not null default false, protocol varchar(15) NOT NULL, extra_options text, returned_text text, mda varchar(255) not null default '', date timestamp with time zone default now(), primary key(id), CHECK (src_auth IN ('password','kerberos_v5','kerberos','kerberos_v4','gssapi','cram-md5','otp','ntlm','msn','ssh','any')), CHECK (protocol IN ('POP3', 'IMAP', 'POP2', 'ETRN', 'AUTO')) ); "); } // MySQL expects sequences to start at 1. Stupid database. // fetchmail.php requires id parameters to be > 0, as it does if($id) like logic... hence if we don't // fudge the sequence starting point, you cannot delete/edit the first entry if using PostgreSQL. // I'm sure there's a more elegant way of fixing it properly.... but this should work for now. if(_pgsql_object_exists('fetchmail_id_seq')) { db_query_parsed("SELECT nextval('{$fetchmail}_id_seq')"); // I don't care about number waste. } } /** * Create alias_domain table - MySQL */ # function upgrade_362_mysql() { # renamed to _438 to make sure it runs after an upgrade from 2.2.x function upgrade_438_mysql() { # Table structure for table alias_domain # $table_alias_domain = table_by_key('alias_domain'); db_query_parsed(" CREATE TABLE IF NOT EXISTS $table_alias_domain ( `alias_domain` varchar(255) NOT NULL default '', `target_domain` varchar(255) NOT NULL default '', `created` datetime NOT NULL default '0000-00-00 00:00:00', `modified` datetime NOT NULL default '0000-00-00 00:00:00', `active` tinyint(1) NOT NULL default '1', PRIMARY KEY (`alias_domain`), KEY `active` (`active`), KEY `target_domain` (`target_domain`) ) {MYISAM} COMMENT='Postfix Admin - Domain Aliases' "); } /** * Create alias_domain table - PgSQL */ # function upgrade_362_pgsql() { # renamed to _438 to make sure it runs after an upgrade from 2.2.x function upgrade_438_pgsql() { # Table structure for table alias_domain $table_alias_domain = table_by_key('alias_domain'); $table_domain = table_by_key('domain'); if(_pgsql_object_exists($table_alias_domain)) { return; } db_query_parsed(" CREATE TABLE $table_alias_domain ( alias_domain character varying(255) NOT NULL REFERENCES $table_domain(domain) ON DELETE CASCADE, target_domain character varying(255) NOT NULL REFERENCES $table_domain(domain) ON DELETE CASCADE, created timestamp with time zone default now(), modified timestamp with time zone default now(), active boolean NOT NULL default true, PRIMARY KEY(alias_domain))"); db_query_parsed("CREATE INDEX alias_domain_active ON $table_alias_domain(alias_domain,active)"); db_query_parsed("COMMENT ON TABLE $table_alias_domain IS 'Postfix Admin - Domain Aliases'"); } /** * Change description fields to UTF-8 */ function upgrade_373_mysql() { # MySQL only $table_domain = table_by_key ('domain'); $table_mailbox = table_by_key('mailbox'); $all_sql = explode("\n", trim(" ALTER TABLE `$table_domain` CHANGE `description` `description` VARCHAR( 255 ) {UTF-8} NOT NULL ALTER TABLE `$table_mailbox` CHANGE `name` `name` VARCHAR( 255 ) {UTF-8} NOT NULL ")); foreach ($all_sql as $sql) { $result = db_query_parsed($sql); } } /** * add ssl option for fetchmail */ function upgrade_439_mysql() { $table_fetchmail = table_by_key('fetchmail'); if(!_mysql_field_exists($table_fetchmail, 'ssl')) { db_query_parsed("ALTER TABLE `$table_fetchmail` ADD `ssl` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `protocol` ; "); } } function upgrade_439_pgsql() { $table_fetchmail = table_by_key('fetchmail'); if(!_pgsql_field_exists($table_fetchmail, 'ssl')) { db_query_parsed("ALTER TABLE $table_fetchmail ADD COLUMN ssl BOOLEAN NOT NULL DEFAULT false"); } } function upgrade_473_mysql() { $table_admin = table_by_key('admin'); $table_alias = table_by_key('alias'); $table_al_dom = table_by_key('alias_domain'); $table_domain = table_by_key('domain'); $table_dom_adm = table_by_key('domain_admins'); $table_fmail = table_by_key('fetchmail'); $table_mailbox = table_by_key('mailbox'); $table_log = table_by_key('log'); # tables were created without explicit charset before :-( $all_sql = explode("\n", trim(" ALTER TABLE `$table_admin` CHANGE `username` `username` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_admin` CHANGE `password` `password` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_admin` DEFAULT {LATIN1} ALTER TABLE `$table_alias` CHANGE `address` `address` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_alias` CHANGE `goto` `goto` TEXT {LATIN1} NOT NULL ALTER TABLE `$table_alias` CHANGE `domain` `domain` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_alias` DEFAULT {LATIN1} ALTER TABLE `$table_al_dom` CHANGE `alias_domain` `alias_domain` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_al_dom` CHANGE `target_domain` `target_domain` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_al_dom` DEFAULT {LATIN1} ALTER TABLE `$table_domain` CHANGE `domain` `domain` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_domain` CHANGE `transport` `transport` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_domain` DEFAULT {LATIN1} ALTER TABLE `$table_dom_adm` CHANGE `username` `username` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_dom_adm` CHANGE `domain` `domain` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_dom_adm` DEFAULT {LATIN1} ALTER TABLE `$table_log` CHANGE `username` `username` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_log` CHANGE `domain` `domain` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_log` CHANGE `action` `action` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_log` CHANGE `data` `data` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_log` DEFAULT {LATIN1} ALTER TABLE `$table_mailbox` CHANGE `username` `username` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_mailbox` CHANGE `password` `password` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_mailbox` CHANGE `maildir` `maildir` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_mailbox` CHANGE `domain` `domain` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_mailbox` DEFAULT {LATIN1} ALTER TABLE `$table_fmail` CHANGE `mailbox` `mailbox` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_fmail` CHANGE `src_server` `src_server` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_fmail` CHANGE `src_user` `src_user` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_fmail` CHANGE `src_password` `src_password` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_fmail` CHANGE `src_folder` `src_folder` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_fmail` CHANGE `mda` `mda` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_fmail` CHANGE `mailbox` `mailbox` VARCHAR( 255 ) {LATIN1} NOT NULL ALTER TABLE `$table_fmail` CHANGE `extra_options` `extra_options` TEXT {LATIN1} NULL DEFAULT NULL ALTER TABLE `$table_fmail` CHANGE `returned_text` `returned_text` TEXT {LATIN1} NULL DEFAULT NULL ALTER TABLE `$table_fmail` DEFAULT {LATIN1} ")); foreach ($all_sql as $sql) { $result = db_query_parsed($sql); } } function upgrade_479_mysql () { # ssl is a reserved word in MySQL and causes several problems. Renaming the field... $table_fmail = table_by_key('fetchmail'); if(!_mysql_field_exists($table_fmail, 'usessl')) { db_query_parsed("ALTER TABLE `$table_fmail` CHANGE `ssl` `usessl` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0'"); } } function upgrade_479_pgsql () { $table_fmail = table_by_key('fetchmail'); if(!_pgsql_field_exists($table_fmail, 'usessl')) { db_query_parsed("alter table $table_fmail rename column ssl to usessl"); } } function upgrade_483_mysql () { $table_log = table_by_key('log'); db_query_parsed("ALTER TABLE $table_log CHANGE `data` `data` TEXT {LATIN1} NOT NULL"); } # Add a local_part field to the mailbox table, and populate it with the local part of the user's address. # This is to make it easier (hopefully) to change the filesystem location of a mailbox in the future # See https://sourceforge.net/forum/message.php?msg_id=5394663 function upgrade_495_pgsql() { $table_mailbox = table_by_key('mailbox'); if(!_pgsql_field_exists($table_mailbox, 'local_part')) { db_query_parsed("ALTER TABLE $table_mailbox add column local_part varchar(255) "); db_query_parsed("UPDATE $table_mailbox SET local_part = substring(username from '^(.*)@')"); db_query_parsed("ALTER TABLE $table_mailbox alter column local_part SET NOT NULL"); } } # See https://sourceforge.net/forum/message.php?msg_id=5394663 function upgrade_495_mysql() { $table_mailbox = table_by_key('mailbox'); if(!_mysql_field_exists($table_mailbox, 'local_part')) { db_query_parsed("ALTER TABLE $table_mailbox add local_part varchar(255) AFTER quota"); // allow to be null db_query_parsed("UPDATE $table_mailbox SET local_part = substring_index(username, '@', 1)"); db_query_parsed("ALTER TABLE $table_mailbox change local_part local_part varchar(255) NOT NULL"); // remove null-ness... } } function upgrade_504_mysql() { $table_mailbox = table_by_key('mailbox'); db_query_parsed("ALTER TABLE `$table_mailbox` CHANGE `local_part` `local_part` VARCHAR( 255 ) {LATIN1} NOT NULL"); } function upgrade_655() { db_query_parsed(_add_index('mailbox', 'domain', 'domain')); db_query_parsed(_add_index('alias', 'domain', 'domain')); } function upgrade_729() { $table_quota = table_by_key('quota'); $table_quota2 = table_by_key('quota2'); # table for dovecot v1.0 & 1.1 db_query_parsed(" CREATE TABLE {IF_NOT_EXISTS} $table_quota ( username VARCHAR(255) {LATIN1} NOT NULL, path VARCHAR(100) {LATIN1} NOT NULL, current {BIGINT}, PRIMARY KEY (username, path) ) {MYISAM} ; "); # table for dovecot >= 1.2 db_query_parsed(" CREATE TABLE {IF_NOT_EXISTS} $table_quota2 ( username VARCHAR(100) {LATIN1} NOT NULL, bytes {BIGINT} NOT NULL DEFAULT 0, messages integer NOT NULL DEFAULT 0, PRIMARY KEY (username) ) {MYISAM} ; "); } function upgrade_730_pgsql() { $table_quota = table_by_key('quota'); $table_quota2 = table_by_key('quota2'); db_query_parsed('CREATE LANGUAGE plpgsql', 1); /* will error if plpgsql is already installed */ # trigger for dovecot v1.0 & 1.1 quota table # taken from http://wiki.dovecot.org/Quota/Dict db_query_parsed(" CREATE OR REPLACE FUNCTION merge_quota() RETURNS TRIGGER AS \$merge_quota\$ BEGIN UPDATE $table_quota SET current = NEW.current + current WHERE username = NEW.username AND path = NEW.path; IF found THEN RETURN NULL; ELSE RETURN NEW; END IF; END; \$merge_quota\$ LANGUAGE plpgsql; "); db_query_parsed(" CREATE TRIGGER mergequota BEFORE INSERT ON $table_quota FOR EACH ROW EXECUTE PROCEDURE merge_quota(); "); # trigger for dovecot >= 1.2 quota table # taken from http://wiki.dovecot.org/Quota/Dict, table/trigger name changed to quota2 naming db_query_parsed(" CREATE OR REPLACE FUNCTION merge_quota2() RETURNS TRIGGER AS \$\$ BEGIN IF NEW.messages < 0 OR NEW.messages IS NULL THEN -- ugly kludge: we came here from this function, really do try to insert IF NEW.messages IS NULL THEN NEW.messages = 0; ELSE NEW.messages = -NEW.messages; END IF; return NEW; END IF; LOOP UPDATE $table_quota2 SET bytes = bytes + NEW.bytes, messages = messages + NEW.messages WHERE username = NEW.username; IF found THEN RETURN NULL; END IF; BEGIN IF NEW.messages = 0 THEN INSERT INTO $table_quota2 (bytes, messages, username) VALUES (NEW.bytes, NULL, NEW.username); ELSE INSERT INTO $table_quota2 (bytes, messages, username) VALUES (NEW.bytes, -NEW.messages, NEW.username); END IF; return NULL; EXCEPTION WHEN unique_violation THEN -- someone just inserted the record, update it END; END LOOP; END; \$\$ LANGUAGE plpgsql; "); db_query_parsed(" CREATE TRIGGER mergequota2 BEFORE INSERT ON $table_quota2 FOR EACH ROW EXECUTE PROCEDURE merge_quota2(); "); } function upgrade_740_pgsql() { # upgrade_968_pgsql() in SVN trunk # pgsql counterpart for upgrade_169_mysql() - allow really big quota $table_domain = table_by_key ('domain'); $table_mailbox = table_by_key('mailbox'); db_query_parsed("ALTER TABLE $table_domain ALTER COLUMN quota type bigint"); db_query_parsed("ALTER TABLE $table_domain ALTER COLUMN maxquota type bigint"); db_query_parsed("ALTER TABLE $table_mailbox ALTER COLUMN quota type bigint"); } postfixadmin-2.3.7/xmlrpc.php0000664000175000017620000001141611245325561016304 0ustar davidpalepurplegetHttpClient(); * $http_client->setCookieJar(); * * $login_object = $xmlrpc->getProxy('login'); * $success = $login_object->login($email_address, $password); * * if($success) { * echo "We're logged in"; * } * else { * die("Auth failed"); * } * $user = $xmlrpc->getProxy('user'); * $alias = $xmlrpc->getProxy('alias'); * $vacation = $xmlrpc->getProxy('vacation'); * * if($vacation->checkVacation()) { * echo "Vacation turned on for user"; * } * * Note, the requirement that your XmlRpc client provides cookies with each request. * If it does not do this, then your authentication details will not persist across requests, and * this XMLRPC interface will not work. */ require_once(dirname(__FILE__) . '/common.php'); if($CONF['xmlrpc_enabled'] == false) { die("xmlrpc support disabled"); } require_once('Zend/XmlRpc/Server.php'); $server = new Zend_XmlRpc_Server(); /** * @param string $username * @param string $password * @return boolean true on success, else false. */ function login($username, $password) { if(UserHandler::login($username, $password)) { session_regenerate_id(); $_SESSION['authenticated'] = true; $_SESSION['username'] = $username; return true; } return false; } if(!isset($_SESSION['authenticated'])) { $server->addFunction('login', 'login'); } else { $server->setClass('UserProxy', 'user'); $server->setClass('VacationProxy', 'vacation'); $server->setClass('AliasProxy', 'alias'); } echo $server->handle(); class UserProxy { /** * @param string $old_password * @param string $new_password * @return boolean true on success */ public function changePassword($old_password, $new_password) { $uh = new UserHandler($_SESSION['username']); return $uh->change_pass($old_password, $new_password); } /** * @param string $username * @param string $password * @return boolean true if successful. */ public function login($username, $password) { $uh = new UserHandler($_SESSION['username']); return $uh->login($username, $password); } } class VacationProxy { /** * @return boolean true if the vacation is removed successfully. Else false. */ public function remove() { $vh = new VacationHandler($_SESSION['username']); return $vh->remove(); } /** * @return boolean true if vacation stuff is enabled in this instance of postfixadmin * and the user has the ability to make changes to it. */ public function isVacationSupported() { $vh = new VacationHandler($_SESSION['username']); return $vh->vacation_supported(); } /** * @return boolean true if the user has an active vacation record etc. */ public function checkVacation() { $vh = new VacationHandler($_SESSION['username']); return $vh->check_vacation(); } /** * @return struct|boolean - either array of vacation details or boolean false if the user has none. */ public function getDetails() { $vh = new VacationHandler($_SESSION['username']); return $vh->get_details(); } /** * @param string $subject * @param string $body * @return boolean true on success. */ public function setAway($subject, $body) { $vh = new VacationHandler($_SESSION['username']); return $vh->set_away($subject, $body); } } class AliasProxy { /** * @return array - array of aliases this user has. Array may be empty. */ public function get() { $ah = new AliasHandler($_SESSION['username']); /* I see no point in returning special addresses to the user. */ return $ah->get(false); } /** * @param array of email addresses (Strings) * @param string flag to set ('forward_and_store' or 'remote_only') * @return boolean true */ public function update($addresses, $flags) { $ah = new AliasHandler($_SESSION['username']); /** * if the user is on vacation, they should use VacationProxy stuff to remove it * and we'll never return the vacation address from here anyway */ return $ah->update($addresses, $flags, true); } /** * @return boolean true if the user has 'store_and_forward' set. * (i.e. their email address is also in the alias table). IF it returns false, then it's 'remote_only' */ public function hasStoreAndForward() { $ah = new AliasHandler($_SESSION['username']); return $ah->hasStoreAndForward(); } } postfixadmin-2.3.7/list-admin.php0000664000175000017620000000206711146027202017031 0ustar davidpalepurple 0)) { for ($i = 0; $i < sizeof ($list_admins); $i++) { $admin_properties[$i] = get_admin_properties ($list_admins[$i]); } } include ("templates/header.php"); include ("templates/menu.php"); include ("templates/admin_list-admin.php"); include ("templates/footer.php"); /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ ?> postfixadmin-2.3.7/edit-vacation.php0000664000175000017620000001537611703114423017527 0ustar davidpalepurple $goto"); } } } //Set the vacation data for $fUsername if (!empty ($fChange)) { $goto = ''; $result = db_query ("SELECT * FROM $table_alias WHERE address='$fUsername'"); if ($result['rows'] == 1) { $row = db_array ($result['result']); $goto = $row['goto']; } $Active = db_get_boolean(True); $notActive = db_get_boolean(False); // I don't think we need to care if the vacation entry is inactive or active.. as long as we don't try and // insert a duplicate $result = db_query("SELECT * FROM $table_vacation WHERE email = '$fUsername'"); if($result['rows'] == 1) { $result = db_query("UPDATE $table_vacation SET active = '$Active', subject = '$fSubject', body = '$fBody', created = NOW() WHERE email = '$fUsername'"); } else { $result = db_query ("INSERT INTO $table_vacation (email,subject,body,domain,created,active) VALUES ('$fUsername','$fSubject','$fBody','$fDomain',NOW(),'$Active')"); } if ($result['rows'] != 1) { $error = 1; } if($goto == '') { $goto = $vacation_goto; $sql = "INSERT INTO $table_alias (goto, address, domain, modified) VALUES ('$goto', '$fUsername', '$fDomain', NOW())"; } else { $goto = $goto . "," . $vacation_goto; $sql = "UPDATE $table_alias SET goto='$goto',modified=NOW() WHERE address='$fUsername'"; } $result = db_query ($sql); if ($result['rows'] != 1) { $error = 1; } db_log($SESSID_USERNAME, $domain, 'edit_alias', "$fUsername -> $goto"); } } if($error == 0) { if(!empty ($fBack)) { $tMessage = $PALANG['pVacation_result_removed']; } if(!empty($fChange)) { $tMessage= $PALANG['pVacation_result_added']; } } else { $tMessage = $PALANG['pVacation_result_error']; } include ("templates/header.php"); include ("templates/menu.php"); include ("templates/edit-vacation.php"); include ("templates/footer.php"); /* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/backup.php0000664000175000017620000001016411703056521016237 0ustar davidpalepurpleSorry: Backup is currently not supported for your DBMS.

'; } /* SELECT attnum,attname,typname,atttypmod-4,attnotnull,atthasdef,adsrc AS def FROM pg_attribute,pg_class,pg_type,pg_attrdef WHERE pg_class.oid=attrelid AND pg_type.oid=atttypid AND attnum>0 AND pg_class.oid=adrelid AND adnum=attnum AND atthasdef='t' AND lower(relname)='admin' UNION SELECT attnum,attname,typname,atttypmod-4,attnotnull,atthasdef,'' AS def FROM pg_attribute,pg_class,pg_type WHERE pg_class.oid=attrelid AND pg_type.oid=atttypid AND attnum>0 AND atthasdef='f' AND lower(relname)='admin' $db = $_GET['db']; $cmd = "pg_dump -c -D -f /tix/miner/miner.sql -F p -N -U postgres $db"; $res = `$cmd`; // Alternate: $res = shell_exec($cmd); echo $res; */ if ($_SERVER['REQUEST_METHOD'] == "GET") { umask (077); $path = (ini_get('upload_tmp_dir') != '') ? ini_get('upload_tmp_dir') : '/tmp'; $filename = "postfixadmin-" . date ("Ymd") . "-" . getmypid() . ".sql"; $backup = $path . DIRECTORY_SEPARATOR . $filename; $header = "#\n# Postfix Admin $version\n# Date: " . date ("D M j G:i:s T Y") . "\n#\n"; if (!$fh = fopen ($backup, 'w')) { $tMessage = "
Cannot open file ($backup)
"; include ("templates/header.php"); include ("templates/menu.php"); include ("templates/message.php"); include ("templates/footer.php"); } else { fwrite ($fh, $header); $tables = array( 'admin', 'alias', 'alias_domain', 'config', 'domain', 'domain_admins', 'fetchmail', 'log', 'mailbox', 'quota', 'quota2', 'vacation', 'vacation_notification' ); for ($i = 0 ; $i < sizeof ($tables) ; ++$i) { $result = db_query ("SHOW CREATE TABLE " . table_by_key($tables[$i])); if ($result['rows'] > 0) { while ($row = db_array ($result['result'])) { fwrite ($fh, "$row[1];\n\n"); } } } for ($i = 0 ; $i < sizeof ($tables) ; ++$i) { $result = db_query ("SELECT * FROM " . table_by_key($tables[$i])); if ($result['rows'] > 0) { while ($row = db_assoc ($result['result'])) { $fields = array_keys($row); $values = array_values($row); $values = array_map('escape_string', $values); fwrite ($fh, "INSERT INTO ". $tables[$i] . " (". implode (',',$fields) . ") VALUES ('" . implode ('\',\'',$values) . "');\n"); $fields = ""; $values = ""; } } } } header ("Content-Type: text/plain"); header ("Content-Disposition: attachment; filename=\"$filename\""); header ("Content-Transfer-Encoding: binary"); header ("Content-Length: " . filesize("$backup")); header ("Content-Description: Postfix Admin"); $download_backup = fopen ("$backup", "r"); unlink ("$backup"); fpassthru ($download_backup); } /* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/0000775000175000017620000000000012301477472016234 5ustar davidpalepurplepostfixadmin-2.3.7/languages/ru.lang0000664000175000017620000010142411636730120017517 0ustar davidpalepurpleНевозможно удалить запись '; $PALANG['pDelete_delete_success'] = '%s удален.'; $PALANG['pDelete_postdelete_error'] = 'Невозможно удалить ящик '; $PALANG['pDelete_domain_error'] = 'Этот домен не принадлежит вам '; $PALANG['pDelete_domain_alias_error'] = 'Этот домен не принадлежит вам '; $PALANG['pDelete_alias_error'] = 'Невозможно удалить алиас '; $PALANG['pCreate_alias_domain_welcome'] = 'Отображать адреса одного вашего домена на другой.'; $PALANG['pCreate_alias_domain_alias'] = 'Домен-алиас'; $PALANG['pCreate_alias_domain_alias_text'] = 'Домен, в который приходит почта.'; $PALANG['pCreate_alias_domain_target'] = 'Целевой домен'; $PALANG['pCreate_alias_domain_target_text'] = 'Домен, куда должна направляться почта.'; $PALANG['pCreate_alias_domain_active'] = 'Активен'; $PALANG['pCreate_alias_domain_button'] = 'Создать домен-алиас'; $PALANG['pCreate_alias_domain_error1'] = 'Вам не разрешено создавать выбранную конфигурацию.'; $PALANG['pCreate_alias_domain_error2'] = 'Выбранная конфигурация некорректна, пожалуйста, выберите другую!'; $PALANG['pCreate_alias_domain_error3'] = 'Не удалось добавить запись в базу данных.'; $PALANG['pCreate_alias_domain_error4'] = 'Все домены уже задействованы в доменах-алиасах.'; $PALANG['pCreate_alias_domain_success'] = 'Домен-алиас добавлен в таблицу доменов-алиасов!'; $PALANG['pCreate_alias_welcome'] = 'Создание нового алиаса в вашем домене.'; $PALANG['pCreate_alias_address'] = 'Алиас'; $PALANG['pCreate_alias_address_text_error1'] = '
Неверное имя алиаса!'; $PALANG['pCreate_alias_address_text_error2'] = '
Этот почтовый адрес уже существует, пожалуйста, выберите другой.'; $PALANG['pCreate_alias_address_text_error3'] = '
Вы достигли лимита по созданным алиасам!'; $PALANG['pCreate_alias_goto'] = 'Кому'; $PALANG['pCreate_alias_active'] = 'Активен'; $PALANG['pCreate_alias_button'] = 'Создать алиас'; $PALANG['pCreate_alias_goto_text'] = 'Куда должна доставляться почта.'; $PALANG['pCreate_alias_goto_text_error'] = 'Куда должна идти почта.
Неверное поле Кому!'; $PALANG['pCreate_alias_result_error'] = 'Невозможно добавить алиас в список!'; $PALANG['pCreate_alias_result_success'] = 'Алиас был успешно создан!'; $PALANG['pCreate_alias_catchall_text'] = 'Для создания catch-all почтового ящика используйте "*" в качестве имени алиаса.'; # XXX don't propagate usage of *@target-domain.com for domain-aliasing any longer $PALANG['pEdit_alias_welcome'] = 'Редактирование алиаса в вашем домене.
Одна запись на строку.'; $PALANG['pEdit_alias_address'] = 'Алиас'; $PALANG['pEdit_alias_address_error'] = 'Невозможно определить алиас!'; $PALANG['pEdit_alias_goto'] = 'Кому'; $PALANG['pEdit_alias_active'] = 'Активен'; $PALANG['pEdit_alias_goto_text_error1'] = 'Вы ничего не ввели в поле Кому'; $PALANG['pEdit_alias_goto_text_error2'] = 'Вы ввели неверный адрес: '; $PALANG['pEdit_alias_domain_error'] = 'Этот домен не принадлежит вам: '; $PALANG['pEdit_alias_domain_result_error'] = 'Невозможно изменить домен-алиас!'; $PALANG['pEdit_alias_forward_and_store'] = 'Доставлять в локальный почтовый ящик.'; $PALANG['pEdit_alias_forward_only'] = 'Только пересылать на указанные адреса.'; $PALANG['pEdit_alias_button'] = 'Редактировать алиас'; $PALANG['pEdit_alias_result_error'] = 'Невозможно изменить алиас!'; $PALANG['pCreate_mailbox_welcome'] = 'Создание нового почтового ящика для вашего домена.'; $PALANG['pCreate_mailbox_username'] = 'Название'; $PALANG['pCreate_mailbox_username_text_error1'] = '
Неверное имя!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Это имя уже существует, пожалуйста, выберите другое!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Вы достигли лимита по созданию почтовых ящиков!'; $PALANG['pCreate_mailbox_password'] = 'Пароль'; $PALANG['pCreate_mailbox_password2'] = 'Пароль (еще раз)'; $PALANG['pCreate_mailbox_password_text'] = 'Пароль для POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Пароль для POP3/IMAP
Введенные вами пароли не совпадают!
Либо пусты!
'; $PALANG['pCreate_mailbox_name'] = 'Имя'; $PALANG['pCreate_mailbox_name_text'] = 'Полное имя'; $PALANG['pCreate_mailbox_quota'] = 'Квота'; $PALANG['pCreate_mailbox_quota_text'] = 'МБ'; $PALANG['pCreate_mailbox_quota_text_error'] = 'МБ
Квота, выставленная вами, слишком велика!'; $PALANG['pCreate_mailbox_active'] = 'Активен'; $PALANG['pCreate_mailbox_mail'] = 'Отправить приветственное письмо'; $PALANG['pCreate_mailbox_button'] = 'Создать ящик'; $PALANG['pCreate_mailbox_result_error'] = 'Невозможно добавить ящик в список существующих ящиков!'; $PALANG['pCreate_mailbox_result_success'] = 'Почтовый ящик был успешно создан!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'Почтовый ящик был успешно создан, но в нем не удалось создать (некоторые) стандартные папки'; $PALANG['pEdit_mailbox_welcome'] = 'Редактирование ящика для вашего домена.'; $PALANG['pEdit_mailbox_username'] = 'Название'; $PALANG['pEdit_mailbox_username_error'] = 'Невозможно определить ящик!'; $PALANG['pEdit_mailbox_password'] = 'Новый пароль'; $PALANG['pEdit_mailbox_password2'] = 'Новый пароль (еще раз)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Введенные вами пароли не совпадают!'; $PALANG['pEdit_mailbox_name'] = 'Имя'; $PALANG['pEdit_mailbox_name_text'] = 'Полное имя'; $PALANG['pEdit_mailbox_quota'] = 'Квота'; $PALANG['pEdit_mailbox_quota_text'] = 'МБ'; $PALANG['pEdit_mailbox_quota_text_error'] = 'МБ
Квота, выставленная вами, слишком велика!'; $PALANG['pEdit_mailbox_domain_error'] = 'Этот домен не принадлежит вам: '; $PALANG['pEdit_mailbox_button'] = 'Редактировать ящик'; $PALANG['pEdit_mailbox_result_error'] = 'Невозможно изменить пароль!'; $PALANG['pPassword_welcome'] = 'Изменение вашего пароля.'; $PALANG['pPassword_admin'] = 'Имя для входа'; $PALANG['pPassword_admin_text_error'] = 'Имя, введенное вами, не соответствует почтовому ящику!'; $PALANG['pPassword_password_current'] = 'Текущий пароль'; $PALANG['pPassword_password_current_text_error'] = 'Вы не указали ваш текущий пароль!'; $PALANG['pPassword_password'] = 'Новый пароль'; $PALANG['pPassword_password2'] = 'Новый пароль (еще раз)'; $PALANG['pPassword_password_text_error'] = 'Введенные вами пароли не совпадают!
Либо пусты!
'; $PALANG['pPassword_button'] = 'Изменить пароль'; $PALANG['pPassword_result_error'] = 'Невозможно изменить ваш пароль!'; $PALANG['pPassword_result_success'] = 'Ваш пароль был изменен!'; $PALANG['pEdit_vacation_set'] = 'Поменять / задать сообщение об отсутствии'; $PALANG['pEdit_vacation_remove'] = 'Убрать сообщение об отсутствии'; $PALANG['pVacation_result_error'] = 'Невозможно обновить настройки автоответчика!'; $PALANG['pVacation_result_removed'] = 'Автоответчик отключен!'; $PALANG['pVacation_result_added'] = 'Автоответчик включен!'; $PALANG['pViewlog_welcome'] = 'Просмотреть последних 10 действий для '; $PALANG['pViewlog_timestamp'] = 'Время создания/модификации'; $PALANG['pViewlog_username'] = 'Админ'; $PALANG['pViewlog_domain'] = 'Домен'; $PALANG['pViewlog_action'] = 'Действие'; $PALANG['pViewlog_data'] = 'Данные'; $PALANG['pViewlog_action_create_mailbox'] = 'создание ящика'; $PALANG['pViewlog_action_delete_mailbox'] = 'удаление ящика'; $PALANG['pViewlog_action_edit_mailbox'] = 'редактирование ящика'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'изменение активности ящика'; $PALANG['pViewlog_action_create_alias'] = 'создание алиаса'; $PALANG['pViewlog_action_create_alias_domain'] = 'создание домена-алиаса'; $PALANG['pViewlog_action_delete_alias'] = 'удаление алиаса'; $PALANG['pViewlog_action_delete_alias_domain'] = 'удаление домена-алиаса'; $PALANG['pViewlog_action_edit_alias'] = 'редактирование алиаса'; $PALANG['pViewlog_action_edit_alias_state'] = 'изменение активности алиаса'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'изменение активности домена-алиаса'; $PALANG['pViewlog_action_edit_password'] = 'изменение пароля'; $PALANG['pViewlog_button'] = 'Выбрать'; $PALANG['pViewlog_result_error'] = 'Невозможно найти журнал!'; $PALANG['pSendmail_welcome'] = 'Послать письмо.'; $PALANG['pSendmail_admin'] = 'От'; $PALANG['pSendmail_to'] = 'Кому'; $PALANG['pSendmail_to_text_error'] = 'Поле Кому пустое либо содержит неверный адрес!'; $PALANG['pSendmail_subject'] = 'Тема'; $PALANG['pSendmail_subject_text'] = 'Добро пожаловать!'; $PALANG['pSendmail_body'] = 'Текст'; $PALANG['pSendmail_button'] = 'Послать сообщение'; $PALANG['pSendmail_result_error'] = 'Невозможно отправить сообщение!'; $PALANG['pSendmail_result_success'] = 'Сообщение отправлено!'; $PALANG['pAdminMenu_list_admin'] = 'Список админов'; $PALANG['pAdminMenu_list_domain'] = 'Список доменов'; $PALANG['pAdminMenu_list_virtual'] = 'Обзор'; $PALANG['pAdminMenu_viewlog'] = 'Журнал'; $PALANG['pAdminMenu_backup'] = 'Бэкап'; $PALANG['pAdminMenu_create_domain_admins'] = 'Админы доменов'; $PALANG['pAdminMenu_create_admin'] = 'Новый админ'; $PALANG['pAdminMenu_create_domain'] = 'Новый домен'; $PALANG['pAdminMenu_create_alias'] = 'Создать алиас'; $PALANG['pAdminMenu_create_mailbox'] = 'Создать ящик'; $PALANG['pAdminList_admin_domain'] = 'Домен'; $PALANG['pAdminList_admin_username'] = 'Админ'; $PALANG['pAdminList_admin_count'] = 'Домены'; $PALANG['pAdminList_admin_modified'] = 'Последнее изменение'; $PALANG['pAdminList_admin_active'] = 'Активен'; $PALANG['pAdminList_domain_domain'] = 'Домен'; $PALANG['pAdminList_domain_description'] = 'Описание'; $PALANG['pAdminList_domain_aliases'] = 'Алиасы'; $PALANG['pAdminList_domain_mailboxes'] = 'Ящики'; $PALANG['pAdminList_domain_maxquota'] = 'Квота (МБ)'; $PALANG['pAdminList_domain_transport'] = 'Транспорт'; $PALANG['pAdminList_domain_backupmx'] = 'Резервный MX'; $PALANG['pAdminList_domain_modified'] = 'Последнее изменение'; $PALANG['pAdminList_domain_active'] = 'Активен'; $PALANG['pAdminList_virtual_button'] = 'Выбрать'; $PALANG['pAdminList_virtual_welcome'] = 'Обзор для '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Алиасы'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Ящики'; $PALANG['pAdminList_virtual_alias_address'] = 'От'; $PALANG['pAdminList_virtual_alias_goto'] = 'Кому'; $PALANG['pAdminList_virtual_alias_modified'] = 'Последнее изменение'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Ящик'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Имя'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Квота (МБ)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Последнее изменение'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Активный'; $PALANG['pAdminCreate_domain_welcome'] = 'Добавление нового домена'; $PALANG['pAdminCreate_domain_domain'] = 'Домен'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Домен уже существует!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'Некорректный домен!'; $PALANG['pAdminCreate_domain_description'] = 'Описание'; $PALANG['pAdminCreate_domain_aliases'] = 'Алиасы'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = отключить | 0 = неограниченное'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Ящики'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = отключить | 0 = неограниченное'; $PALANG['pAdminCreate_domain_maxquota'] = 'Макс. квота'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'МБ
-1 = отключить | 0 = неограниченное'; $PALANG['pAdminCreate_domain_transport'] = 'Транспорт'; $PALANG['pAdminCreate_domain_transport_text'] = 'Укажите транспорт'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Добавить стандартные алиасы для домена'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'Почтовый сервер является резервным MX'; $PALANG['pAdminCreate_domain_button'] = 'Добавить домен'; $PALANG['pAdminCreate_domain_result_error'] = 'Невозможно добавить домен!'; $PALANG['pAdminCreate_domain_result_success'] = 'Домен был добавлен!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Невозможно удалить домен!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Невозможно удалить домен-алиас!'; $PALANG['pAdminEdit_domain_welcome'] = 'Редактирование домена'; $PALANG['pAdminEdit_domain_domain'] = 'Домен'; $PALANG['pAdminEdit_domain_description'] = 'Описание'; $PALANG['pAdminEdit_domain_aliases'] = 'Алиасы'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = отключить | 0 = неограниченное'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Ящики'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = отключить | 0 = неограниченное'; $PALANG['pAdminEdit_domain_maxquota'] = 'Макс. квота'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'МБ
-1 = отключить | 0 = неограниченное'; $PALANG['pAdminEdit_domain_transport'] = 'Транспорт'; $PALANG['pAdminEdit_domain_transport_text'] = 'Укажите транспорт'; $PALANG['pAdminEdit_domain_backupmx'] = 'Почтовый сервер является резервным MX'; $PALANG['pAdminEdit_domain_active'] = 'Активен'; $PALANG['pAdminEdit_domain_button'] = 'Редактировать домен'; $PALANG['pAdminEdit_domain_result_error'] = 'Невозможно изменить домен!'; $PALANG['pAdminCreate_admin_welcome'] = 'Добавление нового администратора домена'; $PALANG['pAdminCreate_admin_username'] = 'Администратор'; $PALANG['pAdminCreate_admin_username_text'] = 'Почтовый адрес'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Почтовый адрес
Некорректный адрес администратора!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Почтовый адрес
Администратор уже существует либо некорректное имя'; $PALANG['pAdminCreate_admin_password'] = 'Пароль'; $PALANG['pAdminCreate_admin_password2'] = 'Пароль (еще раз)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Введенные вами пароли не совпадают!
Либо пустые!
'; $PALANG['pAdminCreate_admin_button'] = 'Добавить администратора'; $PALANG['pAdminCreate_admin_result_error'] = 'Невозможно добавить администратора!'; $PALANG['pAdminCreate_admin_result_success'] = 'Администратор был добавлен!'; $PALANG['pAdminCreate_admin_address'] = 'Домен'; $PALANG['pAdminEdit_admin_welcome'] = 'Редактирование администратора домена'; $PALANG['pAdminEdit_admin_username'] = 'Администратор'; $PALANG['pAdminEdit_admin_password'] = 'Пароль'; $PALANG['pAdminEdit_admin_password2'] = 'Пароль (еще раз)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Введенные вами пароли не совпадают!
Либо пустые!
'; $PALANG['pAdminEdit_admin_active'] = 'Активен'; $PALANG['pAdminEdit_admin_super_admin'] = 'Супер админ'; $PALANG['pAdminEdit_admin_button'] = 'Редактировать администратора'; $PALANG['pAdminEdit_admin_result_error'] = 'Невозможно изменить администратора!'; $PALANG['pAdminEdit_admin_result_success'] = 'Администратор был изменен!'; $PALANG['pUsersLogin_welcome'] = 'Вход пользователей для изменения паролей и алиасов.'; $PALANG['pUsersLogin_username'] = 'Имя (адрес)'; $PALANG['pUsersLogin_password'] = 'Пароль'; $PALANG['pUsersLogin_button'] = 'Войти'; $PALANG['pUsersLogin_username_incorrect'] = 'Введено неправильное имя. Проверьте, что вы ввели свой адрес электронной почты!'; $PALANG['pUsersLogin_password_incorrect'] = 'Введен неверный пароль!'; $PALANG['pUsersMenu_vacation'] = 'Автоответчик'; $PALANG['pUsersMenu_edit_alias'] = 'Изменить пересылку почты'; $PALANG['pUsersMenu_password'] = 'Изменить пароль'; $PALANG['pUsersMain_vacation'] = 'Настроить сообщение "вне офиса" либо автоответчик для вашей почты.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' ВКЛЮЧЕН, щелкните \'' . $PALANG['pUsersMenu_vacation'] . '\', чтобы ' . $PALANG['edit'] . '/убрать'; $PALANG['pUsersMain_edit_alias'] = 'Изменить перенаправление почты.'; $PALANG['pUsersMain_password'] = 'Изменить текущий пароль.'; $PALANG['pUsersVacation_welcome'] = 'Автоответчик.'; $PALANG['pUsersVacation_welcome_text'] = 'У вас уже есть настроенный автоответчик!'; $PALANG['pUsersVacation_subject'] = 'Тема'; $PALANG['pUsersVacation_subject_text'] = 'Вне офиса'; $PALANG['pUsersVacation_body'] = 'Сообщение'; $PALANG['pUsersVacation_body_text'] = << по <дату>. По срочным вопросам вы можете обратиться к <контактному лицу>. EOM; $PALANG['pUsersVacation_button_away'] = 'Ухожу'; $PALANG['pUsersVacation_button_back'] = 'Возвращаюсь'; $PALANG['pUsersVacation_result_error'] = 'Невозможно изменить настройки автоответчика!'; $PALANG['pUsersVacation_result_success'] = 'Ваш автоответчик был убран!'; $PALANG['pUsersVacation_activefrom'] = 'Активен с'; $PALANG['pUsersVacation_activeuntil'] = 'Активен по'; $PALANG['pCreate_dbLog_createmailbox'] = 'создание ящика'; $PALANG['pCreate_dbLog_createalias'] = 'создание алиаса'; $PALANG['pDelete_dbLog_deletealias'] = 'удаление алиаса'; $PALANG['pDelete_dbLog_deletemailbox'] = 'удаление ящика'; $PALANG['pEdit_dbLog_editactive'] = 'изменение статуса активности'; $PALANG['pEdit_dbLog_editalias'] = 'редактирование алиаса'; $PALANG['pEdit_dbLog_editmailbox'] = 'редактирование ящика'; $PALANG['pSearch'] = 'поиск'; $PALANG['pSearch_welcome'] = 'Искать: '; $PALANG['pReturn_to'] = 'Вернуться к'; $PALANG['pBroadcast_title'] = 'Отправка широковещательного сообщения'; $PALANG['pBroadcast_from'] = 'От'; $PALANG['pBroadcast_name'] = 'Ваше имя'; $PALANG['pBroadcast_subject'] = 'Тема'; $PALANG['pBroadcast_message'] = 'Сообщение'; $PALANG['pBroadcast_send'] = 'Отправить сообщение'; $PALANG['pBroadcast_success'] = 'Ваше широковещательное сообщение было отправлено.'; $PALANG['pAdminMenu_broadcast_message'] = 'Широковещательное сообщение'; $PALANG['pBroadcast_error_empty'] = 'Поля Имя, Тема и Сообщение не должны быть пустыми!'; $PALANG['pStatus_undeliverable'] = 'возможно НЕ ДОСТАВЛЕНО '; $PALANG['pStatus_custom'] = 'Доставляется для '; $PALANG['pStatus_popimap'] = 'POP/IMAP '; $PALANG['pPasswordTooShort'] = "Пароль слишком короткий - требуется %s символов"; $PALANG['pInvalidDomainRegex'] = "Некорректное имя домена %s, не соответствует регулярному выражению"; $PALANG['pInvalidDomainDNS'] = "Некорректный домен %s, и/или не обнаруживается в DNS"; $PALANG['pInvalidMailRegex'] = "Некорректный адрес e-mail, не соответствует регулярному выражению"; $PALANG['pFetchmail_welcome'] = 'Собирать почту для:'; $PALANG['pFetchmail_new_entry'] = 'Новая запись'; $PALANG['pFetchmail_database_save_error'] = 'Не удалось сохранить эту запись в базе данных!'; $PALANG['pFetchmail_database_save_success'] = 'Запись сохранена в базе данных.'; $PALANG['pFetchmail_error_invalid_id'] = 'Не найдена запись с номером %s!'; $PALANG['pFetchmail_invalid_mailbox'] = 'Некорректный почтовый ящик!'; $PALANG['pFetchmail_server_missing'] = 'Пожалуйста введите имя удаленного сервера!'; $PALANG['pFetchmail_user_missing'] = 'Пожалуйста введите имя удаленного пользователя!'; $PALANG['pFetchmail_password_missing'] = 'Пожалуйста введите пароль удаленного пользователя!'; $PALANG['pFetchmail_field_id'] = 'Номер'; $PALANG['pFetchmail_field_mailbox'] = 'Ящик'; $PALANG['pFetchmail_field_src_server'] = 'Сервер'; $PALANG['pFetchmail_field_src_auth'] = 'Тип аутентификации'; $PALANG['pFetchmail_field_src_user'] = 'Пользователь'; $PALANG['pFetchmail_field_src_password'] = 'Пароль'; $PALANG['pFetchmail_field_src_folder'] = 'Папка'; $PALANG['pFetchmail_field_poll_time'] = 'Опрашивать'; $PALANG['pFetchmail_field_fetchall'] = 'Скачивать все'; $PALANG['pFetchmail_field_keep'] = 'Не удалять'; $PALANG['pFetchmail_field_protocol'] = 'Протокол'; $PALANG['pFetchmail_field_usessl'] = 'Включить SSL'; $PALANG['pFetchmail_field_extra_options'] = 'Дополнительные параметры'; $PALANG['pFetchmail_field_mda'] = 'MDA'; $PALANG['pFetchmail_field_date'] = 'Дата'; $PALANG['pFetchmail_field_returned_text'] = 'Текст отчета'; $PALANG['pFetchmail_desc_id'] = 'Номер записи'; $PALANG['pFetchmail_desc_mailbox'] = 'Локальный ящик'; $PALANG['pFetchmail_desc_src_server'] = 'Удаленный сервер'; $PALANG['pFetchmail_desc_src_auth'] = 'Обычно \'password\''; # Translators: Please do NOT translate 'password' here $PALANG['pFetchmail_desc_src_user'] = 'Удаленный пользователь'; $PALANG['pFetchmail_desc_src_password'] = 'Удаленный пароль'; $PALANG['pFetchmail_desc_src_folder'] = 'Удаленная папка'; $PALANG['pFetchmail_desc_poll_time'] = 'Опрашивать каждые ... минут'; $PALANG['pFetchmail_desc_fetchall'] = 'Скачивать и старые (виденные), и новые сообщения'; $PALANG['pFetchmail_desc_keep'] = 'Не удалять скачанные сообщения с удаленного сервера'; $PALANG['pFetchmail_desc_protocol'] = 'Какой протокол использовать'; $PALANG['pFetchmail_desc_usessl'] = 'Шифрование SSL'; $PALANG['pFetchmail_desc_extra_options'] = 'Дополнительные параметры fetchmail'; $PALANG['pFetchmail_desc_mda'] = 'Агент доставки почты (Mail Delivery Agent)'; $PALANG['pFetchmail_desc_date'] = 'Дата последнего опроса/изменения конфигурации'; $PALANG['pFetchmail_desc_returned_text'] = 'Текст отчета о последнем опросе'; $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/fo.lang0000664000175000017620000006505311636730120017504 0ustar davidpalepurpleFái ikki strikað '; $PALANG['pDelete_delete_success'] = '%s deleted.'; # XXX $PALANG['pDelete_postdelete_error'] = 'Unable to remove mailbox '; # XXX $PALANG['pDelete_domain_error'] = 'Hetta er ikki títt navnaøki '; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = 'Unable to delete alias '; # XXX $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = 'Stovna eitt nýtt dulnevni á tínum navnaøki.'; $PALANG['pCreate_alias_address'] = 'Dulnevni'; $PALANG['pCreate_alias_address_text_error1'] = '
DULNEVNI er ógyldugt!'; $PALANG['pCreate_alias_address_text_error2'] = '
Hendan e-post adressa finst longu, vinarliga vel eina aðra!'; $PALANG['pCreate_alias_address_text_error3'] = '
Tú hevur nátt tínum marki at stovna dulnevni!'; $PALANG['pCreate_alias_goto'] = 'Til'; $PALANG['pCreate_alias_active'] = 'Active'; # XXX $PALANG['pCreate_alias_button'] = 'Stovna Dulnevni'; $PALANG['pCreate_alias_goto_text'] = 'Har posturin skal sendast til.'; $PALANG['pCreate_alias_goto_text_error'] = 'Har posturin verður sendur til.
TIL er ógyldugt!'; $PALANG['pCreate_alias_result_error'] = 'Fái ikki stovnað dulnevni!'; $PALANG['pCreate_alias_result_success'] = 'Dulnevni er stovnað!'; $PALANG['pCreate_alias_catchall_text'] = 'Fyri at stovna eitt ið fangar alt, brúka eina "*" sum dulnevni.
Fyri navnaøki til navnaøki víðarisending brúka "*@navnaøki.fo" til hetta.'; $PALANG['pEdit_alias_welcome'] = 'Broyt eitt dulnevni á tínum navnaøki.
Eina adressu pr. linju.'; $PALANG['pEdit_alias_address'] = 'Dulnevni'; $PALANG['pEdit_alias_address_error'] = 'Finni ikki dulnevni!'; $PALANG['pEdit_alias_goto'] = 'Til'; $PALANG['pEdit_alias_active'] = 'Active'; # XXX $PALANG['pEdit_alias_goto_text_error1'] = 'Tú skrivaði onki í Til teigin'; $PALANG['pEdit_alias_goto_text_error2'] = 'E-post adressan tú skrivaði er ógyldug: '; $PALANG['pEdit_alias_domain_error'] = 'Hetta navnaøki er ikki títt: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Deliver to the local mailbox.'; # XXX $PALANG['pEdit_alias_forward_only'] = 'Forward to given email addresses only.'; # XXX $PALANG['pEdit_alias_button'] = 'Broyt Dulnevni'; $PALANG['pEdit_alias_result_error'] = 'Fái ikki broytt dulnevni!'; $PALANG['pCreate_mailbox_welcome'] = 'Stovna ein nýggjan postkassa á tínum navnaøki.'; $PALANG['pCreate_mailbox_username'] = 'Brúkaranavn'; $PALANG['pCreate_mailbox_username_text_error1'] = '
E-post adressan er ógyldug!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Hendan e-post adressan finst longu, vinarliga vel eina aðra!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Tú hevur nýtt tínum marki at stovna postkassar!'; $PALANG['pCreate_mailbox_password'] = 'Loyniorð'; $PALANG['pCreate_mailbox_password2'] = 'Loyniorð (umaftur)'; $PALANG['pCreate_mailbox_password_text'] = 'Loyniorð til POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Loyniorð til POP3/IMAP
Loyniorðini tú skrivaði samsvara ikki!
Ella eru tóm!
'; $PALANG['pCreate_mailbox_name'] = 'Navn'; $PALANG['pCreate_mailbox_name_text'] = 'Fult navn'; $PALANG['pCreate_mailbox_quota'] = 'Kvota'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Kvotan tú skrivaði er ov høg!'; $PALANG['pCreate_mailbox_active'] = 'Virkin'; $PALANG['pCreate_mailbox_mail'] = 'Stovna postkassa'; $PALANG['pCreate_mailbox_button'] = 'Stovna postkassa'; $PALANG['pCreate_mailbox_result_error'] = 'Fái ikki stovnað postkassa!'; $PALANG['pCreate_mailbox_result_success'] = 'Postkassin er stovnaður!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'The mailbox has been added to the mailbox table, but none (or only some) of the predefined sub-folders could be created'; # XXX $PALANG['pEdit_mailbox_welcome'] = 'Broyt postkassa á tínum navnaøki.'; $PALANG['pEdit_mailbox_username'] = 'Brúkaranavn'; $PALANG['pEdit_mailbox_username_error'] = 'Finni ikki postkassa!'; $PALANG['pEdit_mailbox_password'] = 'Nýtt loyniorð'; $PALANG['pEdit_mailbox_password2'] = 'Nýtt loyniorð (umaftur)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Loyniorðini tú skrivaði samsvara ikki!'; $PALANG['pEdit_mailbox_name'] = 'Navn'; $PALANG['pEdit_mailbox_name_text'] = 'Full name'; # XXX $PALANG['pEdit_mailbox_quota'] = 'Kvota'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Kvotan tú skrivaði er ov høg!'; $PALANG['pEdit_mailbox_domain_error'] = 'Hetta navnaøki er ikki títt: '; $PALANG['pEdit_mailbox_button'] = 'Broyt postkassa'; $PALANG['pEdit_mailbox_result_error'] = 'Fái ikki broytt loyniorðið!'; $PALANG['pPassword_welcome'] = 'Broyt títt login loyniorð.'; $PALANG['pPassword_admin'] = 'Logga inn'; $PALANG['pPassword_admin_text_error'] = 'Navnið tú skrivaði samsvarar ikki við nakran postkassa!'; $PALANG['pPassword_password_current'] = 'Núverandi loyniorð'; $PALANG['pPassword_password_current_text_error'] = 'Tú skrivaði ikki títt núverandi loyniorð!'; $PALANG['pPassword_password'] = 'Nýtt loyniorð'; $PALANG['pPassword_password2'] = 'Nýtt loyniorð (umaftur)'; $PALANG['pPassword_password_text_error'] = 'Loyniorðini tú skrivaði samsvara ikki!
Ella eru tóm!
'; $PALANG['pPassword_button'] = 'Broyt loyniorð'; $PALANG['pPassword_result_error'] = 'Fái ikki broytt títt loyniorð!'; $PALANG['pPassword_result_success'] = 'Títt loyniorð er broytt!'; $PALANG['pEdit_vacation_set'] = 'Change / Set away message'; # XXX $PALANG['pEdit_vacation_remove'] = 'Remove away message'; # XXX $PALANG['pVacation_result_error'] = 'Unable to update auto response settings!'; # XXX $PALANG['pVacation_result_removed'] = 'Auto response has been removed!'; # XXX $PALANG['pVacation_result_added'] = 'Auto response has been enabled!'; # XXX $PALANG['pViewlog_welcome'] = 'Vís seinastu 10 hendingarnar fyri '; $PALANG['pViewlog_timestamp'] = 'Tíðarstempul'; $PALANG['pViewlog_username'] = 'Umsitari'; $PALANG['pViewlog_domain'] = 'Navnaøki'; $PALANG['pViewlog_action'] = 'Hending'; $PALANG['pViewlog_data'] = 'Dáta'; $PALANG['pViewlog_action_create_mailbox'] = 'create mailbox'; # XXX $PALANG['pViewlog_action_delete_mailbox'] = 'delete mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox'] = 'edit mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox_state'] = 'edit mailbox active'; # XXX $PALANG['pViewlog_action_create_alias'] = 'create alias'; # XXX $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'delete alias'; # XXX $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'edit alias'; # XXX $PALANG['pViewlog_action_edit_alias_state'] = 'edit alias active'; # XXX $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'change password'; # XXX $PALANG['pViewlog_button'] = 'Vel'; $PALANG['pViewlog_result_error'] = 'Finni ikki loggarnar!'; $PALANG['pSendmail_welcome'] = 'Send ein e-post.'; $PALANG['pSendmail_admin'] = 'Frá'; $PALANG['pSendmail_to'] = 'Til'; $PALANG['pSendmail_to_text_error'] = 'Til er tómt ella ógyldug e-post adressa!'; $PALANG['pSendmail_subject'] = 'Evni'; $PALANG['pSendmail_subject_text'] = 'Vælkomin'; $PALANG['pSendmail_body'] = 'Boð'; $PALANG['pSendmail_button'] = 'Send boð'; $PALANG['pSendmail_result_error'] = 'Fái ikki stovnað postkassa!'; # XXX text change - new: Unable to send email! $PALANG['pSendmail_result_success'] = 'Postkassin er stovnaður!'; # XXX text change - new: Email sent! $PALANG['pAdminMenu_list_admin'] = 'Umsitara listi'; $PALANG['pAdminMenu_list_domain'] = 'Navnaøkja listi'; $PALANG['pAdminMenu_list_virtual'] = 'Virtual listi'; $PALANG['pAdminMenu_viewlog'] = 'Vís logg'; $PALANG['pAdminMenu_backup'] = 'Trygdaravrit'; $PALANG['pAdminMenu_create_domain_admins'] = 'Umsitarar fyri Navnaøki'; $PALANG['pAdminMenu_create_admin'] = 'Nýggjan Umsitara'; $PALANG['pAdminMenu_create_domain'] = 'Nýtt Navnaøki'; $PALANG['pAdminMenu_create_alias'] = 'Stovna Dulnevni'; $PALANG['pAdminMenu_create_mailbox'] = 'Stovna Postkassa'; $PALANG['pAdminList_admin_domain'] = 'Navnaøki'; $PALANG['pAdminList_admin_username'] = 'Umsitari'; $PALANG['pAdminList_admin_count'] = 'Navnaøki'; $PALANG['pAdminList_admin_modified'] = 'Síst broytt'; $PALANG['pAdminList_admin_active'] = 'Virkin'; $PALANG['pAdminList_domain_domain'] = 'Navnaøki'; $PALANG['pAdminList_domain_description'] = 'Frágreiðing'; $PALANG['pAdminList_domain_aliases'] = 'Dulnevni'; $PALANG['pAdminList_domain_mailboxes'] = 'Postkassar'; $PALANG['pAdminList_domain_maxquota'] = 'Hægsta Kvota (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; # XXX $PALANG['pAdminList_domain_modified'] = 'Síðst broytt'; $PALANG['pAdminList_domain_active'] = 'Virki'; $PALANG['pAdminList_virtual_button'] = 'Vel'; $PALANG['pAdminList_virtual_welcome'] = 'Yvirlit yvir '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Dulnevni'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Postkassar'; $PALANG['pAdminList_virtual_alias_address'] = 'Frá'; $PALANG['pAdminList_virtual_alias_goto'] = 'Til'; $PALANG['pAdminList_virtual_alias_modified'] = 'Síðst broytt'; $PALANG['pAdminList_virtual_mailbox_username'] = 'E-post'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Navn'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Kvota (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Síðst broytt'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Virkin'; $PALANG['pAdminCreate_domain_welcome'] = 'Stova nýtt navnaøki'; $PALANG['pAdminCreate_domain_domain'] = 'Navnaøki'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Navnaøki finst longu!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'The domain is invalid!'; # XXX $PALANG['pAdminCreate_domain_description'] = 'Frágreiðing'; $PALANG['pAdminCreate_domain_aliases'] = 'Dulnevni'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = óvirkja | 0 = óavmarkað'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Postkassar'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = óvirkja | 0 = óavmarkað'; $PALANG['pAdminCreate_domain_maxquota'] = 'Hægsta kvota'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = óvirkja | 0 = óavmarkað'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminCreate_domain_transport_text'] = 'Define transport'; # XXX $PALANG['pAdminCreate_domain_defaultaliases'] = 'Stovna sjálvvirkin e-post dulnevni'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; # XXX $PALANG['pAdminCreate_domain_backupmx'] = 'Post servari er "backup MX"'; $PALANG['pAdminCreate_domain_button'] = 'Stovna navnaøki'; $PALANG['pAdminCreate_domain_result_error'] = 'Fái ikki stovnað navnaøki!'; $PALANG['pAdminCreate_domain_result_success'] = 'Navnaøki er stovnað!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Unable to remove domain!'; # XXX $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = 'Broyt navnaøki'; $PALANG['pAdminEdit_domain_domain'] = 'Navnaøki'; $PALANG['pAdminEdit_domain_description'] = 'Frágreiðing'; $PALANG['pAdminEdit_domain_aliases'] = 'Dulnevni'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = óvirkja | 0 = óavmarkað'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Postkassar'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = óvirkja | 0 = óavmarkað'; $PALANG['pAdminEdit_domain_maxquota'] = 'Hægsta kvota'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = óvirkja | 0 = óavmarkað'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminEdit_domain_transport_text'] = 'Define transport'; # XXX $PALANG['pAdminEdit_domain_backupmx'] = 'Post servari er "backup MX"'; $PALANG['pAdminEdit_domain_active'] = 'Virki'; $PALANG['pAdminEdit_domain_button'] = 'Broyt navnaøki'; $PALANG['pAdminEdit_domain_result_error'] = 'Fái ikki broytt navnaøki!'; $PALANG['pAdminCreate_admin_welcome'] = 'Stovna navnaøki umsitara'; $PALANG['pAdminCreate_admin_username'] = 'Umsitari'; $PALANG['pAdminCreate_admin_username_text'] = 'E-post adressa'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'E-post adressa
Umsitari er ógyldug e-post adressa!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'E-post adressa
Umsitari finst longu ella er ógyldugur'; $PALANG['pAdminCreate_admin_password'] = 'Loyniorð'; $PALANG['pAdminCreate_admin_password2'] = 'Loyniorð (umaftur)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Loyniorðini tú skrivaði samsvara ikki!
Ella eru tóm!
'; $PALANG['pAdminCreate_admin_button'] = 'Stovna umsitara'; $PALANG['pAdminCreate_admin_result_error'] = 'Fái ikki stovnað umsitara!'; $PALANG['pAdminCreate_admin_result_success'] = 'Umsitari er stovnaður!'; $PALANG['pAdminCreate_admin_address'] = 'Navnaøki'; $PALANG['pAdminEdit_admin_welcome'] = 'Broyt navnaøki umsitara'; $PALANG['pAdminEdit_admin_username'] = 'Umsitari'; $PALANG['pAdminEdit_admin_password'] = 'Loyniorð'; $PALANG['pAdminEdit_admin_password2'] = 'Loyniorð (umaftur)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Loyniorðini tú skrivaði samsvara ikki!
Ella eru tóm!
'; $PALANG['pAdminEdit_admin_active'] = 'Virkin'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super admin'; # XXX $PALANG['pAdminEdit_admin_button'] = 'Broyt umsitara'; $PALANG['pAdminEdit_admin_result_error'] = 'Fái ikki broytt umsitara!'; $PALANG['pAdminEdit_admin_result_success'] = 'Umsitari er broyttur!'; $PALANG['pUsersLogin_welcome'] = 'Postkassa brúkarar loggi inn fyri at broyta loyniorð, víðarisending ella frítíðarboð.'; $PALANG['pUsersLogin_username'] = 'Login (e-post)'; $PALANG['pUsersLogin_password'] = 'Loyniorð'; $PALANG['pUsersLogin_button'] = 'Logga inn'; $PALANG['pUsersLogin_username_incorrect'] = 'Títt login er skeivt. Minst til at logga inn við tíni e-post adressu!'; $PALANG['pUsersLogin_password_incorrect'] = 'Títt loyniorð er skeivt!'; $PALANG['pUsersMenu_vacation'] = 'Frítíðarboð'; $PALANG['pUsersMenu_edit_alias'] = 'Broyt víðarisending'; $PALANG['pUsersMenu_password'] = 'Broyt loyniorð'; $PALANG['pUsersMain_vacation'] = 'Set eini frítíðarboð ella svarboð fyri tín post.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' is ON, click \'' . $PALANG['pUsersMenu_vacation'] . '\' to ' . $PALANG['edit'] . '/remove'; # XXX $PALANG['pUsersMain_edit_alias'] = 'Send tín post víðari til aðra adressu.'; $PALANG['pUsersMain_password'] = 'Broyt títt núverandi loyniorð.'; $PALANG['pUsersVacation_welcome'] = 'Sjálvvirkið svar.'; $PALANG['pUsersVacation_welcome_text'] = 'Tú hevur longu eini frítíðarboð uppsett!'; $PALANG['pUsersVacation_subject'] = 'Evni'; $PALANG['pUsersVacation_subject_text'] = 'Out of Office'; $PALANG['pUsersVacation_body'] = 'Boð'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << until . For urgent matters you can contact . --- Títt navn EOM; $PALANG['pUsersVacation_button_away'] = 'Burtur'; $PALANG['pUsersVacation_button_back'] = 'Heima'; $PALANG['pUsersVacation_result_error'] = 'Fái ikki broytt tínar frítíðarboð uppsetingar!'; $PALANG['pUsersVacation_result_success'] = 'Títt frítíðarboð er strikað!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'create mailbox'; # XXX $PALANG['pCreate_dbLog_createalias'] = 'create alias'; # XXX $PALANG['pDelete_dbLog_deletealias'] = 'delete alias'; # XXX $PALANG['pDelete_dbLog_deletemailbox'] = 'delete mailbox'; # XXX $PALANG['pEdit_dbLog_editactive'] = 'change active state'; # XXX $PALANG['pEdit_dbLog_editalias'] = 'edit alias'; # XXX $PALANG['pEdit_dbLog_editmailbox'] = 'edit mailbox'; # XXX $PALANG['pSearch'] = 'search'; # XXX $PALANG['pSearch_welcome'] = 'Searching for: '; # XXX $PALANG['pReturn_to'] = 'Return to'; # XXX $PALANG['pBroadcast_title'] = 'Send broadcast message'; # XXX $PALANG['pBroadcast_from'] = 'From'; # XXX $PALANG['pBroadcast_name'] = 'Your name'; # XXX $PALANG['pBroadcast_subject'] = 'Subject'; # XXX $PALANG['pBroadcast_message'] = 'Message'; # XXX $PALANG['pBroadcast_send'] = 'Send message'; # XXX $PALANG['pBroadcast_success'] = 'Your broadcast message was sent.'; # XXX $PALANG['pAdminMenu_broadcast_message'] = 'Broadcast message'; # XXX $PALANG['pBroadcast_error_empty'] = 'The fields Name, Subject and Message should\'t be empty !'; # XXX $PALANG['pStatus_undeliverable'] = 'maybe UNDELIVERABLE '; # XXX $PALANG['pStatus_custom'] = 'Delivers to '; # XXX $PALANG['pStatus_popimap'] = 'POP/IMAP '; # XXX $PALANG['pPasswordTooShort'] = "Password is too short - requires %s characters"; # XXX $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Fetch mail for:'; # XXX $PALANG['pFetchmail_new_entry'] = 'New entry'; # XXX $PALANG['pFetchmail_database_save_error'] = 'Could not save this entry in the database!'; # XXX $PALANG['pFetchmail_database_save_success'] = 'Entry saved in database.'; # XXX $PALANG['pFetchmail_error_invalid_id'] = 'No entry with ID %s found!'; # XXX $PALANG['pFetchmail_invalid_mailbox'] = 'Invalid mailbox!'; # XXX $PALANG['pFetchmail_server_missing'] = 'Please enter the remote server name!'; # XXX $PALANG['pFetchmail_user_missing'] = 'Please enter the remote username!'; # XXX $PALANG['pFetchmail_password_missing'] = 'Please enter the remote password!'; # XXX $PALANG['pFetchmail_field_id'] = 'ID'; # XXX $PALANG['pFetchmail_field_mailbox'] = 'Mailbox'; # XXX $PALANG['pFetchmail_field_src_server'] = 'Server'; # XXX $PALANG['pFetchmail_field_src_auth'] = 'Auth Type'; # XXX $PALANG['pFetchmail_field_src_user'] = 'User'; # XXX $PALANG['pFetchmail_field_src_password'] = 'Password'; # XXX $PALANG['pFetchmail_field_src_folder'] = 'Folder'; # XXX $PALANG['pFetchmail_field_poll_time'] = 'Poll'; # XXX $PALANG['pFetchmail_field_fetchall'] = 'Fetch All'; # XXX $PALANG['pFetchmail_field_keep'] = 'Keep'; # XXX $PALANG['pFetchmail_field_protocol'] = 'Protocol'; # XXX $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra Options'; # XXX $PALANG['pFetchmail_field_mda'] = 'MDA'; # XXX $PALANG['pFetchmail_field_date'] = 'Date'; # XXX $PALANG['pFetchmail_field_returned_text'] = 'Returned Text'; # XXX $PALANG['pFetchmail_desc_id'] = 'Record ID'; # XXX $PALANG['pFetchmail_desc_mailbox'] = 'Local mailbox'; # XXX $PALANG['pFetchmail_desc_src_server'] = 'Remote Server'; # XXX $PALANG['pFetchmail_desc_src_auth'] = 'Mostly \'password\''; # Translators: Please do NOT translate 'password' here # XXX $PALANG['pFetchmail_desc_src_user'] = 'Remote User'; # XXX $PALANG['pFetchmail_desc_src_password'] = 'Remote Password'; # XXX $PALANG['pFetchmail_desc_src_folder'] = 'Remote Folder'; # XXX $PALANG['pFetchmail_desc_poll_time'] = 'Poll every ... minutes'; # XXX $PALANG['pFetchmail_desc_fetchall'] = 'Retrieve both old (seen) and new messages'; # XXX $PALANG['pFetchmail_desc_keep'] = 'Keep retrieved messages on the remote mailserver'; # XXX $PALANG['pFetchmail_desc_protocol'] = 'Protocol to use'; # XXX $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Extra fetchmail Options'; # XXX $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; # XXX $PALANG['pFetchmail_desc_date'] = 'Date of last polling/configuration change'; # XXX $PALANG['pFetchmail_desc_returned_text'] = 'Text message from last polling'; # XXX $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/mk.lang0000664000175000017620000007514111636730120017506 0ustar davidpalepurple // $PALANG['YES'] = 'Да'; $PALANG['NO'] = 'Не'; $PALANG['edit'] = 'Измени'; $PALANG['del'] = 'Бриши'; $PALANG['exit'] = 'Exit'; # XXX $PALANG['cancel'] = 'Cancel'; # XXX $PALANG['save'] = 'Save'; # XXX $PALANG['confirm'] = 'Дали сте сигурни дека сакате да го избришете ова?\n'; $PALANG['confirm_domain'] = 'Дали сакате да ги избришете сите записи од овој домен? Ова не може да се поправи покасно!\n'; $PALANG['check_update'] = 'Check for update'; # XXX $PALANG['invalid_parameter'] = 'Invalid parameter!'; # XXX $PALANG['pFooter_logged_as'] = 'Logged as %s'; # XXX $PALANG['pLogin_welcome'] = 'Логин за администрирање на домени (Само за администратори!)'; $PALANG['pLogin_username'] = 'Корисничко име (email)'; $PALANG['pLogin_password'] = 'Лозинка'; $PALANG['pLogin_button'] = 'Пријава'; $PALANG['pLogin_failed'] = 'Your email address or password are not correct.'; # XXX $PALANG['pLogin_login_users'] = 'Логин за обични корисници.'; $PALANG['pMenu_main'] = 'Main'; # XXX $PALANG['pMenu_overview'] = 'Преглед'; $PALANG['pMenu_create_alias'] = 'Додавање на алијас'; $PALANG['pMenu_create_alias_domain'] = 'Add Alias Domain'; # XXX $PALANG['pMenu_create_mailbox'] = 'Додавање на поштенско сандаче'; $PALANG['pMenu_fetchmail'] = 'Fetch Email'; # XXX $PALANG['pMenu_sendmail'] = 'Праќање порака'; $PALANG['pMenu_password'] = 'Промена на лозинка'; $PALANG['pMenu_viewlog'] = 'Преглед на записи'; $PALANG['pMenu_logout'] = 'Одјава'; $PALANG['pMain_welcome'] = 'Добредојдовте на администраторот за Postfix!'; $PALANG['pMain_overview'] = 'Преглед на алијаси и поштенски сандачиња. Од овде може да се променат или избришат податоците.'; $PALANG['pMain_create_alias'] = 'Креирање на нов алијас за вашиот домен.'; $PALANG['pMain_create_mailbox'] = 'Креирање на ново поштенско сандаче.'; $PALANG['pMain_sendmail'] = 'Праќање на порака на новокреирано сандаче.'; $PALANG['pMain_password'] = 'Промена на вашата администраторска лозинка за доменот.'; $PALANG['pMain_viewlog'] = 'Преглед на записи.'; $PALANG['pMain_logout'] = 'Одјава од системот'; $PALANG['pOverview_disabled'] = 'Disabled'; # XXX $PALANG['pOverview_unlimited'] = 'Unlimited'; # XXX $PALANG['pOverview_title'] = ':: Defined Domains'; # XXX $PALANG['pOverview_up_arrow'] = 'Go Top'; # XXX $PALANG['pOverview_right_arrow'] = 'Next Page'; # XXX $PALANG['pOverview_left_arrow'] = 'Previous Page'; # XXX $PALANG['pOverview_alias_domain_title'] = ':: Domain Aliases'; # XXX $PALANG['pOverview_alias_title'] = ':: Alias'; # XXX $PALANG['pOverview_mailbox_title'] = ':: Mailboxes'; # XXX $PALANG['pOverview_button'] = 'Оди'; $PALANG['pOverview_welcome'] = 'Преглед за '; $PALANG['pOverview_alias_domain_aliases'] = 'Alias Domains'; # XXX $PALANG['pOverview_alias_domain_target'] = '%s is an Alias Domain for:'; # XXX $PALANG['pOverview_alias_alias_count'] = 'Алијаси'; $PALANG['pOverview_alias_mailbox_count'] = 'Поштенски сандачиња'; $PALANG['pOverview_alias_address'] = 'Од'; $PALANG['pOverview_alias_goto'] = 'До'; $PALANG['pOverview_alias_modified'] = 'Последна промена'; $PALANG['pOverview_alias_domain_modified'] = 'Last Modified'; # XXX $PALANG['pOverview_alias_active'] = 'Active'; # XXX $PALANG['pOverview_alias_domain_active'] = 'Active'; # XXX $PALANG['pOverview_alias_edit'] = 'Alias'; # XXX $PALANG['and_x_more'] = '[and %s more...]'; # XXX $PALANG['pOverview_mailbox_username'] = 'Адреса'; $PALANG['pOverview_mailbox_name'] = 'Име'; $PALANG['pOverview_mailbox_quota'] = 'Квота (MB)'; $PALANG['pOverview_mailbox_modified'] = 'Последна промена'; $PALANG['pOverview_mailbox_active'] = 'Активен'; $PALANG['pOverview_vacation_edit'] = 'VACATION IS ON'; # XXX $PALANG['pOverview_vacation_option'] = 'Set Vacation'; # XXX $PALANG['pOverview_get_domain'] = 'Домен'; $PALANG['pOverview_get_aliases'] = 'Алијаси'; $PALANG['pOverview_get_alias_domains'] = 'Domain Aliases'; # XXX $PALANG['pOverview_get_mailboxes'] = 'Поштенски сандачиња'; $PALANG['pOverview_get_quota'] = 'Квота на сандаче (MB)'; $PALANG['pOverview_get_modified'] = 'Последна промена'; $PALANG['pDelete_delete_error'] = 'Не можам да го избришам записот '; $PALANG['pDelete_delete_success'] = '%s deleted.'; # XXX $PALANG['pDelete_postdelete_error'] = 'Unable to remove mailbox '; # XXX $PALANG['pDelete_domain_error'] = 'Овој домен не е ваш '; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = 'Unable to delete alias '; # XXX $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = 'Креирање на нов алијас за вашиот домен.'; $PALANG['pCreate_alias_address'] = 'Алијас'; $PALANG['pCreate_alias_address_text_error1'] = '
Алијасот не е валиден!'; $PALANG['pCreate_alias_address_text_error2'] = '
Оваа адреса веќе постои. Ве молам одберете друга!'; $PALANG['pCreate_alias_address_text_error3'] = '
Го достигнавте вашиот лимит за креирање алијаси!'; $PALANG['pCreate_alias_goto'] = 'До'; $PALANG['pCreate_alias_active'] = 'Active'; # XXX $PALANG['pCreate_alias_button'] = 'Додавање алијас'; $PALANG['pCreate_alias_goto_text'] = 'Каде треба да се испрати поштата.'; $PALANG['pCreate_alias_goto_text_error'] = 'Каде треба да се испрати пораката.
Полето ДО не е валидно!'; $PALANG['pCreate_alias_result_error'] = 'Не можам да го додадам алијасот на табелата со алијаси!'; $PALANG['pCreate_alias_result_success'] = 'Алијасот е додаден на табелата со алијаси!'; $PALANG['pCreate_alias_catchall_text'] = 'За да креираш catch-all користи "*" како алијас.
За препраќање од домен на домен користи "*@domain.tld" како ДО.'; $PALANG['pEdit_alias_welcome'] = 'Едитирање на алијас за вашиот домен.
Еден запис по линија.'; $PALANG['pEdit_alias_address'] = 'Алијас'; $PALANG['pEdit_alias_address_error'] = 'Не можам да го најдам алијасот!'; $PALANG['pEdit_alias_goto'] = 'До'; $PALANG['pEdit_alias_active'] = 'Active'; # XXX $PALANG['pEdit_alias_goto_text_error1'] = 'Немате ништо внесено во полето ДО'; $PALANG['pEdit_alias_goto_text_error2'] = 'Адресата која ја имате внесено не е валидна: '; $PALANG['pEdit_alias_domain_error'] = 'Овој домен не е ваш: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Deliver to the local mailbox.'; # XXX $PALANG['pEdit_alias_forward_only'] = 'Forward to given email addresses only.'; # XXX $PALANG['pEdit_alias_button'] = 'Едитирање на алијас'; $PALANG['pEdit_alias_result_error'] = 'Не можам да го променам алијасот!'; $PALANG['pCreate_mailbox_welcome'] = 'Креирање на ново поштенско сандаче.'; $PALANG['pCreate_mailbox_username'] = 'Корисничко име'; $PALANG['pCreate_mailbox_username_text_error1'] = '
EMAIL не е валиден!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Оваа адреса веќе постои, одберете друга!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Достигнат е лимитот на поштенски сандачиња!'; $PALANG['pCreate_mailbox_password'] = 'Лозинка'; $PALANG['pCreate_mailbox_password2'] = 'Лозинка (лозинка)'; $PALANG['pCreate_mailbox_password_text'] = 'Лозинка за POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Лозинка за POP3/IMAP
Внесените лозинки не се поклопуваат!
Или се празни!
'; $PALANG['pCreate_mailbox_name'] = 'Име'; $PALANG['pCreate_mailbox_name_text'] = 'Цело име'; $PALANG['pCreate_mailbox_quota'] = 'квота'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Внесената квота е превисока!'; $PALANG['pCreate_mailbox_active'] = 'Активен'; $PALANG['pCreate_mailbox_mail'] = 'Креирање на поштенско сандаче'; $PALANG['pCreate_mailbox_button'] = 'Додавање на сандаче'; $PALANG['pCreate_mailbox_result_error'] = 'Не можам да додадам ново сандаче на табелата!'; $PALANG['pCreate_mailbox_result_success'] = 'Поштенското сандаче е додадено на табелата!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'The mailbox has been added to the mailbox table, but none (or only some) of the predefined sub-folders could be created'; # XXX $PALANG['pEdit_mailbox_welcome'] = 'Измена на поштенско сандаче на доменот.'; $PALANG['pEdit_mailbox_username'] = 'Корисничко име'; $PALANG['pEdit_mailbox_username_error'] = 'Не можам да го најдам сандачето!'; $PALANG['pEdit_mailbox_password'] = 'Нова лозинка'; $PALANG['pEdit_mailbox_password2'] = 'Нова лозинка (повторно)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Внесените лозинки не одговараат!'; $PALANG['pEdit_mailbox_name'] = 'Име'; $PALANG['pEdit_mailbox_name_text'] = 'Full name'; # XXX $PALANG['pEdit_mailbox_quota'] = 'Квота'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Внесената квота е превисока!'; $PALANG['pEdit_mailbox_domain_error'] = 'Овој домен не е ваш: '; $PALANG['pEdit_mailbox_button'] = 'Измена на сандаче'; $PALANG['pEdit_mailbox_result_error'] = 'Не можам да го променан сандачето!'; $PALANG['pPassword_welcome'] = 'Промена на лозинка за најавување.'; $PALANG['pPassword_admin'] = 'Пријава'; $PALANG['pPassword_admin_text_error'] = 'Внесениот LOGIN не одговара на сандачето!'; $PALANG['pPassword_password_current'] = 'Стара лозинка'; $PALANG['pPassword_password_current_text_error'] = 'Ја немате венесено вашата стара лозинка!'; $PALANG['pPassword_password'] = 'Нова лозинка'; $PALANG['pPassword_password2'] = 'Нова лозинка (повторно)'; $PALANG['pPassword_password_text_error'] = 'Внесените лозинки не одговараат!
Или се празни!
'; $PALANG['pPassword_button'] = 'Промена на лозинка'; $PALANG['pPassword_result_error'] = 'Не можам да ја променам вашата лозинка!'; $PALANG['pPassword_result_success'] = 'Вашата лозинка е сменета!'; $PALANG['pEdit_vacation_set'] = 'Change / Set away message'; # XXX $PALANG['pEdit_vacation_remove'] = 'Remove away message'; # XXX $PALANG['pVacation_result_error'] = 'Unable to update auto response settings!'; # XXX $PALANG['pVacation_result_removed'] = 'Auto response has been removed!'; # XXX $PALANG['pVacation_result_added'] = 'Auto response has been enabled!'; # XXX $PALANG['pViewlog_welcome'] = 'Преглед на последните 10 операции за: '; $PALANG['pViewlog_timestamp'] = 'Маркер (Timestamp)'; $PALANG['pViewlog_username'] = 'Админ'; $PALANG['pViewlog_domain'] = 'Домен'; $PALANG['pViewlog_action'] = 'Операција'; $PALANG['pViewlog_data'] = 'Датум'; $PALANG['pViewlog_action_create_mailbox'] = 'create mailbox'; # XXX $PALANG['pViewlog_action_delete_mailbox'] = 'delete mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox'] = 'edit mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox_state'] = 'edit mailbox active'; # XXX $PALANG['pViewlog_action_create_alias'] = 'create alias'; # XXX $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'delete alias'; # XXX $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'edit alias'; # XXX $PALANG['pViewlog_action_edit_alias_state'] = 'edit alias active'; # XXX $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'change password'; # XXX $PALANG['pViewlog_button'] = 'Оди'; $PALANG['pViewlog_result_error'] = 'Не можам да ги пронајдам записите!'; $PALANG['pSendmail_welcome'] = 'Прати порака.'; $PALANG['pSendmail_admin'] = 'Од'; $PALANG['pSendmail_to'] = 'До'; $PALANG['pSendmail_to_text_error'] = 'ДО полето е празно или адресата не е валидна!'; $PALANG['pSendmail_subject'] = 'Тема'; $PALANG['pSendmail_subject_text'] = 'Добро дојдовте'; $PALANG['pSendmail_body'] = 'Содржина'; $PALANG['pSendmail_button'] = 'Прати порака'; $PALANG['pSendmail_result_error'] = 'Не можам да го креирам сандачето!'; # XXX text change - new: Unable to send email! $PALANG['pSendmail_result_success'] = 'Сандачето е креирано!'; # XXX text change - new: Email sent! $PALANG['pAdminMenu_list_admin'] = 'Листа на администратори'; $PALANG['pAdminMenu_list_domain'] = 'Листа на домени'; $PALANG['pAdminMenu_list_virtual'] = 'Листа на виртуелни домени'; $PALANG['pAdminMenu_viewlog'] = 'Преглед на записи'; $PALANG['pAdminMenu_backup'] = 'Backup'; $PALANG['pAdminMenu_create_domain_admins'] = 'Администратори на домен'; $PALANG['pAdminMenu_create_admin'] = 'Нов администратор'; $PALANG['pAdminMenu_create_domain'] = 'Нов домен'; $PALANG['pAdminMenu_create_alias'] = 'Нов алијас'; $PALANG['pAdminMenu_create_mailbox'] = 'Ново сандаче'; $PALANG['pAdminList_admin_domain'] = 'Домен'; $PALANG['pAdminList_admin_username'] = 'Корисничко име'; $PALANG['pAdminList_admin_count'] = 'Домени'; $PALANG['pAdminList_admin_modified'] = 'Последна промена'; $PALANG['pAdminList_admin_active'] = 'Активен'; $PALANG['pAdminList_domain_domain'] = 'Домен'; $PALANG['pAdminList_domain_description'] = 'Опис'; $PALANG['pAdminList_domain_aliases'] = 'Алијаси'; $PALANG['pAdminList_domain_mailboxes'] = 'Поштенски сандачиња'; $PALANG['pAdminList_domain_maxquota'] = 'Максимална квота (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; $PALANG['pAdminList_domain_modified'] = 'Последна промена'; $PALANG['pAdminList_domain_active'] = 'Активен'; $PALANG['pAdminList_virtual_button'] = 'Оди'; $PALANG['pAdminList_virtual_welcome'] = 'Преглед за '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Алијаси'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Поштенски сандачиња'; $PALANG['pAdminList_virtual_alias_address'] = 'Од'; $PALANG['pAdminList_virtual_alias_goto'] = 'До'; $PALANG['pAdminList_virtual_alias_modified'] = 'Последна промена'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Емејл'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Име'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Квота (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Последна промена'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Активно'; $PALANG['pAdminCreate_domain_welcome'] = 'Додади нов домен'; $PALANG['pAdminCreate_domain_domain'] = 'Домен'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Доменот веќе постои!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'The domain is invalid!'; # XXX $PALANG['pAdminCreate_domain_description'] = 'Опис'; $PALANG['pAdminCreate_domain_aliases'] = 'Алијаси'; $PALANG['pAdminCreate_domain_aliases_text'] = '0 = забрането | -1 = неограничено'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Поштенски сандачиња'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '0 = забрането | -1 = неограничено'; $PALANG['pAdminCreate_domain_maxquota'] = 'Максимална квота'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
0 = исклучено | -1 = неограничено'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Define transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Додади на имплицитни алијаси'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'Mail серверот е backup MX'; $PALANG['pAdminCreate_domain_button'] = 'Додади домен'; $PALANG['pAdminCreate_domain_result_error'] = 'Не можам да го додадам доменот!'; $PALANG['pAdminCreate_domain_result_success'] = 'Доменот е додаден!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Unable to remove domain!'; # XXX $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = 'Измена на домен'; $PALANG['pAdminEdit_domain_domain'] = 'Домен'; $PALANG['pAdminEdit_domain_description'] = 'Опис'; $PALANG['pAdminEdit_domain_aliases'] = 'Алијаси'; $PALANG['pAdminEdit_domain_aliases_text'] = '0 = забрането | -1 = неограничено'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Поштенски сандачиња'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '0 = забрането | -1 = неограничено'; $PALANG['pAdminEdit_domain_maxquota'] = 'Максимална квота'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
0 = исклучена | -1 = неограничена'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminEdit_domain_transport_text'] = 'Define transport'; # XXX $PALANG['pAdminEdit_domain_backupmx'] = 'Mail серверот е backup MX'; $PALANG['pAdminEdit_domain_active'] = 'Активен'; $PALANG['pAdminEdit_domain_button'] = 'Едитирај домен'; $PALANG['pAdminEdit_domain_result_error'] = 'Не можам да го модифицирам доменот!'; $PALANG['pAdminCreate_admin_welcome'] = 'Додади нов администратор на домен'; $PALANG['pAdminCreate_admin_username'] = 'Администратор'; $PALANG['pAdminCreate_admin_username_text'] = 'Email адреса'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Email адресата
Администратор не е валидна адреса!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Email адресата
Администраторот веќе постои или не е валидна'; $PALANG['pAdminCreate_admin_password'] = 'Лозинка'; $PALANG['pAdminCreate_admin_password2'] = 'Лозинка (повторно)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Внесените лозинки не одговараат!
Или се празни!
'; $PALANG['pAdminCreate_admin_button'] = 'Додади Администратор'; $PALANG['pAdminCreate_admin_result_error'] = 'Не можам да додадам администратор!'; $PALANG['pAdminCreate_admin_result_success'] = 'Администраторот е додаден!'; $PALANG['pAdminCreate_admin_address'] = 'Домен'; $PALANG['pAdminEdit_admin_welcome'] = 'Измена на администратор на домен'; $PALANG['pAdminEdit_admin_username'] = 'Администратор'; $PALANG['pAdminEdit_admin_password'] = 'Лозинка'; $PALANG['pAdminEdit_admin_password2'] = 'Лозинка (повторно)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Внесените лозинки не одговараат!
Или се празни!
'; $PALANG['pAdminEdit_admin_active'] = 'Активен'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super admin'; # XXX $PALANG['pAdminEdit_admin_button'] = 'Едитирај Администратор'; $PALANG['pAdminEdit_admin_result_error'] = 'Не можам да го модифицирам администраторот!'; $PALANG['pAdminEdit_admin_result_success'] = 'Администраторот е модифициран!'; $PALANG['pUsersLogin_welcome'] = 'Логин за корисници на поштенски сандачиња.Промена на логин и лозинка'; $PALANG['pUsersLogin_username'] = 'Корисничко име (email)'; $PALANG['pUsersLogin_password'] = 'Лозинка'; $PALANG['pUsersLogin_button'] = 'Пријава'; $PALANG['pUsersLogin_username_incorrect'] = 'Погрешно корисничко име. Логирајте се со вашата email адреса!'; $PALANG['pUsersLogin_password_incorrect'] = 'Погрешна лозинка!'; $PALANG['pUsersMenu_vacation'] = 'Автоматски одговор'; $PALANG['pUsersMenu_edit_alias'] = 'Промена на препраќање (forward)'; $PALANG['pUsersMenu_password'] = 'Промена на лозинка'; $PALANG['pUsersMain_vacation'] = 'Подесување на автоматски одговор за почтенското сандаче.'; $PALANG['pUsersMain_vacationSet'] = 'Auto Response is ON, click \'Auto Response\' to edit/remove'; # XXX $PALANG['pUsersMain_edit_alias'] = 'Промена на препраќање на пораки (email forwarding).'; $PALANG['pUsersMain_password'] = 'Промена на лозинка.'; $PALANG['pUsersVacation_welcome'] = 'Автоматски одговор.'; $PALANG['pUsersVacation_welcome_text'] = 'Веќе имате конфигуриран автоматски одговор!'; $PALANG['pUsersVacation_subject'] = 'Тема'; $PALANG['pUsersVacation_subject_text'] = 'Отсутен'; $PALANG['pUsersVacation_body'] = 'Содржина'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << до . За итни случаи контактирајте со . EOM; $PALANG['pUsersVacation_button_away'] = 'Заминување'; $PALANG['pUsersVacation_button_back'] = 'Враќање :)'; $PALANG['pUsersVacation_result_error'] = 'Не можам да ги променам сетирањата за автоматскиот одговор!'; $PALANG['pUsersVacation_result_success'] = 'Вашиот автоматски одговор е отстранет!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'create mailbox'; # XXX $PALANG['pCreate_dbLog_createalias'] = 'create alias'; # XXX $PALANG['pDelete_dbLog_deletealias'] = 'delete alias'; # XXX $PALANG['pDelete_dbLog_deletemailbox'] = 'delete mailbox'; # XXX $PALANG['pEdit_dbLog_editactive'] = 'change active state'; # XXX $PALANG['pEdit_dbLog_editalias'] = 'edit alias'; # XXX $PALANG['pEdit_dbLog_editmailbox'] = 'edit mailbox'; # XXX $PALANG['pSearch'] = 'search'; # XXX $PALANG['pSearch_welcome'] = 'Searching for: '; # XXX $PALANG['pReturn_to'] = 'Return to'; # XXX $PALANG['pBroadcast_title'] = 'Send broadcast message'; # XXX $PALANG['pBroadcast_from'] = 'From'; # XXX $PALANG['pBroadcast_name'] = 'Your name'; # XXX $PALANG['pBroadcast_subject'] = 'Subject'; # XXX $PALANG['pBroadcast_message'] = 'Message'; # XXX $PALANG['pBroadcast_send'] = 'Send message'; # XXX $PALANG['pBroadcast_success'] = 'Your broadcast message was sent.'; # XXX $PALANG['pAdminMenu_broadcast_message'] = 'Broadcast message'; # XXX $PALANG['pBroadcast_error_empty'] = 'The fields Name, Subject and Message should\'t be empty !'; # XXX $PALANG['pStatus_undeliverable'] = 'maybe UNDELIVERABLE '; # XXX $PALANG['pStatus_custom'] = 'Delivers to '; # XXX $PALANG['pStatus_popimap'] = 'POP/IMAP '; # XXX $PALANG['pPasswordTooShort'] = "Password is too short - requires %s characters"; # XXX $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Fetch mail for:'; # XXX $PALANG['pFetchmail_new_entry'] = 'New entry'; # XXX $PALANG['pFetchmail_database_save_error'] = 'Could not save this entry in the database!'; # XXX $PALANG['pFetchmail_database_save_success'] = 'Entry saved in database.'; # XXX $PALANG['pFetchmail_error_invalid_id'] = 'No entry with ID %s found!'; # XXX $PALANG['pFetchmail_invalid_mailbox'] = 'Invalid mailbox!'; # XXX $PALANG['pFetchmail_server_missing'] = 'Please enter the remote server name!'; # XXX $PALANG['pFetchmail_user_missing'] = 'Please enter the remote username!'; # XXX $PALANG['pFetchmail_password_missing'] = 'Please enter the remote password!'; # XXX $PALANG['pFetchmail_field_id'] = 'ID'; # XXX $PALANG['pFetchmail_field_mailbox'] = 'Mailbox'; # XXX $PALANG['pFetchmail_field_src_server'] = 'Server'; # XXX $PALANG['pFetchmail_field_src_auth'] = 'Auth Type'; # XXX $PALANG['pFetchmail_field_src_user'] = 'User'; # XXX $PALANG['pFetchmail_field_src_password'] = 'Password'; # XXX $PALANG['pFetchmail_field_src_folder'] = 'Folder'; # XXX $PALANG['pFetchmail_field_poll_time'] = 'Poll'; # XXX $PALANG['pFetchmail_field_fetchall'] = 'Fetch All'; # XXX $PALANG['pFetchmail_field_keep'] = 'Keep'; # XXX $PALANG['pFetchmail_field_protocol'] = 'Protocol'; # XXX $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra Options'; # XXX $PALANG['pFetchmail_field_mda'] = 'MDA'; # XXX $PALANG['pFetchmail_field_date'] = 'Date'; # XXX $PALANG['pFetchmail_field_returned_text'] = 'Returned Text'; # XXX $PALANG['pFetchmail_desc_id'] = 'Record ID'; # XXX $PALANG['pFetchmail_desc_mailbox'] = 'Local mailbox'; # XXX $PALANG['pFetchmail_desc_src_server'] = 'Remote Server'; # XXX $PALANG['pFetchmail_desc_src_auth'] = 'Mostly \'password\''; # Translators: Please do NOT translate 'password' here # XXX $PALANG['pFetchmail_desc_src_user'] = 'Remote User'; # XXX $PALANG['pFetchmail_desc_src_password'] = 'Remote Password'; # XXX $PALANG['pFetchmail_desc_src_folder'] = 'Remote Folder'; # XXX $PALANG['pFetchmail_desc_poll_time'] = 'Poll every ... minutes'; # XXX $PALANG['pFetchmail_desc_fetchall'] = 'Retrieve both old (seen) and new messages'; # XXX $PALANG['pFetchmail_desc_keep'] = 'Keep retrieved messages on the remote mailserver'; # XXX $PALANG['pFetchmail_desc_protocol'] = 'Protocol to use'; # XXX $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Extra fetchmail Options'; # XXX $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; # XXX $PALANG['pFetchmail_desc_date'] = 'Date of last polling/configuration change'; # XXX $PALANG['pFetchmail_desc_returned_text'] = 'Text message from last polling'; # XXX $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/nl.lang0000664000175000017620000006373311636730120017514 0ustar davidpalepurpleMislukt te verwijderen '; $PALANG['pDelete_delete_success'] = '%s verwijderd.'; $PALANG['pDelete_postdelete_error'] = 'Niet in staat mailbox te verwijderen '; $PALANG['pDelete_domain_error'] = 'Dit is niet uw domein '; $PALANG['pDelete_domain_alias_error'] = 'Dit is niet uw domein '; $PALANG['pDelete_alias_error'] = 'Niet in staat alias te verwijderen '; $PALANG['pCreate_alias_domain_welcome'] = 'Spiegel een van uw domeinen naar een ander domein.'; $PALANG['pCreate_alias_domain_alias'] = 'Alias domein'; $PALANG['pCreate_alias_domain_alias_text'] = 'Het domein waar mail voor binnen komt.'; $PALANG['pCreate_alias_domain_target'] = 'Doel domein'; $PALANG['pCreate_alias_domain_target_text'] = 'Domein waar de mail naar toe moet.'; $PALANG['pCreate_alias_domain_active'] = 'Actief'; $PALANG['pCreate_alias_domain_button'] = 'Voeg alias domein toe'; $PALANG['pCreate_alias_domain_error1'] = 'U heeft niet genoeg rechten om de huidige configuratie te maken.'; $PALANG['pCreate_alias_domain_error2'] = 'De huidige configuratie is ongeldig, slecteer een andere!'; $PALANG['pCreate_alias_domain_error3'] = 'Fout bij vullen database.'; $PALANG['pCreate_alias_domain_error4'] = 'Alle domeinen hebben al een alias!'; $PALANG['pCreate_alias_domain_success'] = 'De domein alias is toegevoegd aan de alias domein tabel!'; $PALANG['pCreate_alias_welcome'] = 'Maak een nieuw alias aan voor uw domein.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
De Alias is niet geldig!'; $PALANG['pCreate_alias_address_text_error2'] = '
Dit e-mail aders bestaat al, kies aub een andere.'; $PALANG['pCreate_alias_address_text_error3'] = '
U bezit het maximum aantal aliassen.'; $PALANG['pCreate_alias_goto'] = 'Naar'; $PALANG['pCreate_alias_active'] = 'Actief'; $PALANG['pCreate_alias_button'] = 'Voeg alias toe'; $PALANG['pCreate_alias_goto_text'] = 'Waar de e-mails heen gestuurd worden.'; $PALANG['pCreate_alias_goto_text_error'] = 'Waar de e-mail naar toe moet.
De NAAR is niet geldig.'; $PALANG['pCreate_alias_result_error'] = 'Mislukt om de alias toe te voegen.'; $PALANG['pCreate_alias_result_success'] = 'De alias is toegevoegd.'; $PALANG['pCreate_alias_catchall_text'] = 'Om een catch-all te gebruiken, dient u een "*" (asteric) in te vullen als alias.
Voor domein naar domein forwarding gebruik "*@domein.tld" als naar.'; $PALANG['pEdit_alias_welcome'] = 'Bewerk een alias voor uw domein.
Een alias per regel.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Mislukt om alias te vinden!'; $PALANG['pEdit_alias_goto'] = 'Naar'; $PALANG['pEdit_alias_active'] = 'Actief'; $PALANG['pEdit_alias_goto_text_error1'] = 'U heeft geen Naar opgegeven.'; $PALANG['pEdit_alias_goto_text_error2'] = 'Het e-mail adres wat u opgaf is niet geldig: '; $PALANG['pEdit_alias_domain_error'] = 'Dit domein is niet van u: '; $PALANG['pEdit_alias_domain_result_error'] = 'Niet in staat de domein alias te bewerken!'; $PALANG['pEdit_alias_forward_and_store'] = 'Lever af op de lokale mailbox.'; $PALANG['pEdit_alias_forward_only'] = 'Alleen op opgegeven email adres afleveren.'; $PALANG['pEdit_alias_button'] = 'Bewerk Alias'; $PALANG['pEdit_alias_result_error'] = 'Mislukt om de alias te bewerken!'; $PALANG['pCreate_mailbox_welcome'] = 'Maak een nieuw lokale mailbox voor uw domein.'; $PALANG['pCreate_mailbox_username'] = 'Gebruikersnaam'; $PALANG['pCreate_mailbox_username_text_error1'] = '
Het e-mail adres is niet geldig.'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Dit e-mail adres is al ingebruik. Kies aub een andere.'; $PALANG['pCreate_mailbox_username_text_error3'] = '
U bezit het maximum aantal mailboxen.'; $PALANG['pCreate_mailbox_password'] = 'Wachtwoord'; $PALANG['pCreate_mailbox_password2'] = 'Wachtwoord nogmaals'; $PALANG['pCreate_mailbox_password_text'] = 'Wachtwoord voor POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Wachtwoord voor POP3/IMAP
De wachtwoorden die u opgaf komen niet overeen.
Of zijn leeg.
'; $PALANG['pCreate_mailbox_name'] = 'Naam'; $PALANG['pCreate_mailbox_name_text'] = 'Volledige naam'; $PALANG['pCreate_mailbox_quota'] = 'Quota'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
De quota die opgaf is te hoog.'; $PALANG['pCreate_mailbox_active'] = 'Actief'; $PALANG['pCreate_mailbox_mail'] = 'Mailbox toevoegen'; $PALANG['pCreate_mailbox_button'] = 'Mailbox toevoegen'; $PALANG['pCreate_mailbox_result_error'] = 'Mislukt om de mailbox toe te voegen.'; $PALANG['pCreate_mailbox_result_success'] = 'De mailbox is toegevoegd.'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'De mailbox is aan de mailbox tabel toegevoegd, maar geen (of sommige) van de vooraf gedefinieerde sub-folders kon aangemaakt worden'; $PALANG['pEdit_mailbox_welcome'] = 'Bewerk een mailbox voor uw domein.'; $PALANG['pEdit_mailbox_username'] = 'Gebruikersnaam'; $PALANG['pEdit_mailbox_username_error'] = 'Mislukt om mailbox te vinden!'; $PALANG['pEdit_mailbox_password'] = 'Nieuw wachtwoord'; $PALANG['pEdit_mailbox_password2'] = 'Nieuw wachtwoord (nogmaals)'; $PALANG['pEdit_mailbox_password_text_error'] = 'De wachtwoorden die u opgaf komen niet overeen.'; $PALANG['pEdit_mailbox_name'] = 'Naam'; $PALANG['pEdit_mailbox_name_text'] = 'Volledige naam'; $PALANG['pEdit_mailbox_quota'] = 'Quota'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
De quota die opgaf is te hoog.'; $PALANG['pEdit_mailbox_domain_error'] = 'Dit domein is niet van nu: '; $PALANG['pEdit_mailbox_button'] = 'Bewerk Mailbox'; $PALANG['pEdit_mailbox_result_error'] = 'Mislukt om het wachtwoord te wijzigen.'; $PALANG['pPassword_welcome'] = 'Bewerk u login wachtwoord.'; $PALANG['pPassword_admin'] = 'Login'; $PALANG['pPassword_admin_text_error'] = 'De login die u opgaf komt niet overeen met een mailbox.'; $PALANG['pPassword_password_current'] = 'Huidig wachtwoord'; $PALANG['pPassword_password_current_text_error'] = 'U heeft uw huidige wachtwoord niet opgegeven.'; $PALANG['pPassword_password'] = 'Nieuw wachtwoord'; $PALANG['pPassword_password2'] = 'Nieuw wachtwoord (nogmaals)'; $PALANG['pPassword_password_text_error'] = 'De wachtwoorden komen niet overeen.
Of zijn leeg.
'; $PALANG['pPassword_button'] = 'Wijzig wachtwoord'; $PALANG['pPassword_result_error'] = 'Mislukt om uw wachtwoord te veranderen.'; $PALANG['pPassword_result_success'] = 'Uw wachtwoord is veranderd.'; $PALANG['pEdit_vacation_set'] = 'Verander / Activeer beantwoorden tekst'; $PALANG['pEdit_vacation_remove'] = 'Verwijder beantwoorden tekst'; $PALANG['pVacation_result_error'] = 'Niet in staat automatisch beantwoorden te wijzigen!'; $PALANG['pVacation_result_removed'] = 'Automatisch beantwoorden is gedeactiveerd!'; $PALANG['pVacation_result_added'] = 'Automatisch beatwoorden is geactiveerd!'; $PALANG['pViewlog_welcome'] = 'Laat de laatste 10 actie\'s zien van '; $PALANG['pViewlog_timestamp'] = 'Tijd'; $PALANG['pViewlog_username'] = 'Beheerder'; $PALANG['pViewlog_domain'] = 'Domein'; $PALANG['pViewlog_action'] = 'Actie'; $PALANG['pViewlog_data'] = 'Aanpassing'; $PALANG['pViewlog_action_create_mailbox'] = 'Mailbox toegevoegd'; $PALANG['pViewlog_action_delete_mailbox'] = 'Mailbox verwijderd'; $PALANG['pViewlog_action_edit_mailbox'] = 'Mailbox bewerkt'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'status actieve mailbox bewerkt'; $PALANG['pViewlog_action_create_alias'] = 'alias toegevoegd'; $PALANG['pViewlog_action_create_alias_domain'] = 'maak domein alias'; $PALANG['pViewlog_action_delete_alias'] = 'alias verwijderd'; $PALANG['pViewlog_action_delete_alias_domain'] = 'verwijder alias domein'; $PALANG['pViewlog_action_edit_alias'] = 'alias bewerkt'; $PALANG['pViewlog_action_edit_alias_state'] = 'status actieve alias bewerkt'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'status actieve domein alias bewerkt'; $PALANG['pViewlog_action_edit_password'] = 'wachtwoord aangepast'; $PALANG['pViewlog_button'] = 'Ga'; $PALANG['pViewlog_result_error'] = 'Mislukt om de logs te vinden!'; $PALANG['pSendmail_welcome'] = 'Verstuur een e-mail.'; $PALANG['pSendmail_admin'] = 'Van'; $PALANG['pSendmail_to'] = 'Naar'; $PALANG['pSendmail_to_text_error'] = 'Naar is leeg of een ongeldig adres.'; $PALANG['pSendmail_subject'] = 'Onderwerp'; $PALANG['pSendmail_subject_text'] = 'Welkom'; $PALANG['pSendmail_body'] = 'Inhoud'; $PALANG['pSendmail_button'] = 'Verstuur bericht'; $PALANG['pSendmail_result_error'] = 'Mislukt om mail te versturen!'; $PALANG['pSendmail_result_success'] = 'E-mail verstuurd!'; $PALANG['pAdminMenu_list_admin'] = 'Beheerders overzicht'; $PALANG['pAdminMenu_list_domain'] = 'Domein overzicht'; $PALANG['pAdminMenu_list_virtual'] = 'Virtueel overzicht'; $PALANG['pAdminMenu_viewlog'] = 'Laat Log zien'; $PALANG['pAdminMenu_backup'] = 'Backup'; $PALANG['pAdminMenu_create_domain_admins'] = 'Domein Beheerders'; $PALANG['pAdminMenu_create_admin'] = 'Nieuwe beheerder'; $PALANG['pAdminMenu_create_domain'] = 'Voeg Domein toe'; $PALANG['pAdminMenu_create_alias'] = 'Voeg Alias toe'; $PALANG['pAdminMenu_create_mailbox'] = 'Voeg Mailbox toe'; $PALANG['pAdminList_admin_domain'] = 'Domein'; $PALANG['pAdminList_admin_username'] = 'Beheerder'; $PALANG['pAdminList_admin_count'] = 'Domeinen'; $PALANG['pAdminList_admin_modified'] = 'Laatst bewerkt'; $PALANG['pAdminList_admin_active'] = 'Actief'; $PALANG['pAdminList_domain_domain'] = 'Domein'; $PALANG['pAdminList_domain_description'] = 'Omschrijving'; $PALANG['pAdminList_domain_aliases'] = 'Aliassen'; $PALANG['pAdminList_domain_mailboxes'] = 'Mailboxen'; $PALANG['pAdminList_domain_maxquota'] = 'Quota (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; $PALANG['pAdminList_domain_backupmx'] = 'Back-up MX'; $PALANG['pAdminList_domain_modified'] = 'Laatst bewerkt'; $PALANG['pAdminList_domain_active'] = 'Actief'; $PALANG['pAdminList_virtual_button'] = 'Ga'; $PALANG['pAdminList_virtual_welcome'] = 'Overzicht voor '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Aliassen'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Mailboxen'; $PALANG['pAdminList_virtual_alias_address'] = 'Van'; $PALANG['pAdminList_virtual_alias_goto'] = 'Naar'; $PALANG['pAdminList_virtual_alias_modified'] = 'Laatst bewerkt'; $PALANG['pAdminList_virtual_mailbox_username'] = 'e-mail'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Naam'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Quota (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Laatst bewerkt'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Actief'; $PALANG['pAdminCreate_domain_welcome'] = 'Voeg een nieuw domein toe'; $PALANG['pAdminCreate_domain_domain'] = 'Domein'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Het domein bestaat al.'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'Het domein is niet geldig!'; $PALANG['pAdminCreate_domain_description'] = 'Omschrijving'; $PALANG['pAdminCreate_domain_aliases'] = 'Aliassen'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = uit | 0 = onbeperkt'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Mailboxen'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = uit | 0 = onbeperkt'; $PALANG['pAdminCreate_domain_maxquota'] = 'Max Quota'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = uit | 0 = onbeperkt'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Definieer transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Gebruik standaard aliassen'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'Mail server is back-up MX'; $PALANG['pAdminCreate_domain_button'] = 'Voeg Domein toe'; $PALANG['pAdminCreate_domain_result_error'] = 'Mislukt om het domein toe te voegen.'; $PALANG['pAdminCreate_domain_result_success'] = 'Domein is toegevoegd!'; $PALANG['pAdminDelete_admin_error'] = 'Niet in staat beheerder te verwijderen!'; $PALANG['pAdminDelete_domain_error'] = 'Niet in staat domein te verwijderen!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Niet in staat domein alias te verwijderen!'; $PALANG['pAdminEdit_domain_welcome'] = 'Bewerk een domein'; $PALANG['pAdminEdit_domain_domain'] = 'Domein'; $PALANG['pAdminEdit_domain_description'] = 'Omschrijving'; $PALANG['pAdminEdit_domain_aliases'] = 'Aliassen'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = uit | 0 = onbeperkt'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Mailboxen'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = uit | 0 = onbeperkt'; $PALANG['pAdminEdit_domain_maxquota'] = 'Max Quota'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = uit | 0 = onbeperkt'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Defineer transport'; $PALANG['pAdminEdit_domain_backupmx'] = 'Mail server is back-up MX'; $PALANG['pAdminEdit_domain_active'] = 'Actief'; $PALANG['pAdminEdit_domain_button'] = 'Bewerk domein'; $PALANG['pAdminEdit_domain_result_error'] = 'Mislukt het domein te bewerken.'; $PALANG['pAdminCreate_admin_welcome'] = 'Voeg een nieuw domein beheerder toe'; $PALANG['pAdminCreate_admin_username'] = 'Beheerder'; $PALANG['pAdminCreate_admin_username_text'] = 'E-mail adres'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'e-mail adres
Beheerder is geen geldig e-mail adres!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'e-mail adres
De beheerder bestaat al of is niet geldig'; $PALANG['pAdminCreate_admin_password'] = 'Wachtwoord'; $PALANG['pAdminCreate_admin_password2'] = 'Wachtwoord (nogmaals)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'De wachtwoorden die u opgaf komen niet overeen.
Of zijn leeg.
'; $PALANG['pAdminCreate_admin_button'] = 'Voeg beheerder toe'; $PALANG['pAdminCreate_admin_result_error'] = 'Mislukt om beheerder toe te voegen!'; $PALANG['pAdminCreate_admin_result_success'] = 'Beheerder is toegevoegd.'; $PALANG['pAdminCreate_admin_address'] = 'Domein'; $PALANG['pAdminEdit_admin_welcome'] = 'Bewerk een domein beheerder'; $PALANG['pAdminEdit_admin_username'] = 'Beheerder'; $PALANG['pAdminEdit_admin_password'] = 'Wachtwoord'; $PALANG['pAdminEdit_admin_password2'] = 'Wachtwoord (nogmaals)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'De wachtwoorden die u opgaf komen niet overeen.
Of zijn leeg.
'; $PALANG['pAdminEdit_admin_active'] = 'Actief'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super administrator'; $PALANG['pAdminEdit_admin_button'] = 'Bewerk beheerder'; $PALANG['pAdminEdit_admin_result_error'] = 'Mislukt om beheerder te bewerken'; $PALANG['pAdminEdit_admin_result_success'] = 'Beheerder is bewerkt!'; $PALANG['pUsersLogin_welcome'] = 'Mailbox gebruikers login om uw wachtwoord en aliassen te bewerken.'; $PALANG['pUsersLogin_username'] = 'Login (email)'; $PALANG['pUsersLogin_password'] = 'Wachtwoord'; $PALANG['pUsersLogin_button'] = 'Login'; $PALANG['pUsersLogin_username_incorrect'] = 'Uw login is niet correct. U dient in te loggen met uw e-mail adres.'; $PALANG['pUsersLogin_password_incorrect'] = 'Uw wachtwoord is niet correct.'; $PALANG['pUsersMenu_vacation'] = 'Automatisch beantwoorden'; $PALANG['pUsersMenu_edit_alias'] = 'Wijzig uw forward'; $PALANG['pUsersMenu_password'] = 'Wijzig wachtwoord'; $PALANG['pUsersMain_vacation'] = 'Stel een "out of office" bericht of automatisch beantwoorden voor uw e-mail in.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' is actief, click \'' . $PALANG['pUsersMenu_vacation'] . '\' to ' . $PALANG['edit'] . '/verwijderen'; $PALANG['pUsersMain_edit_alias'] = 'Wijzig uw e-mail forwarding.'; $PALANG['pUsersMain_password'] = 'Wijzig uw huidige wachtwoord.'; $PALANG['pUsersVacation_welcome'] = 'Automatisch beantwoorden.'; $PALANG['pUsersVacation_welcome_text'] = 'U heeft uw automatisch beantwoorden ingesteld.'; $PALANG['pUsersVacation_subject'] = 'Onderwerp'; $PALANG['pUsersVacation_subject_text'] = 'Out of Office'; $PALANG['pUsersVacation_body'] = 'Bericht'; $PALANG['pUsersVacation_body_text'] = << tot . Voor belangrijke punten kunt u contact opnemen met . EOM; $PALANG['pUsersVacation_button_away'] = 'Afwezig'; $PALANG['pUsersVacation_button_back'] = 'Kom terug'; $PALANG['pUsersVacation_result_error'] = 'Mislukt om uw automatisch beantwoorden instellingen te wijzigen.'; $PALANG['pUsersVacation_result_success'] = 'Uw automatisch beantwoorden is verwijderd.'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'mailbox aangemaakt'; $PALANG['pCreate_dbLog_createalias'] = 'alias aangemaakt'; $PALANG['pDelete_dbLog_deletealias'] = 'alias verwijderd'; $PALANG['pDelete_dbLog_deletemailbox'] = 'mailbox verwijderd'; $PALANG['pEdit_dbLog_editactive'] = 'status verandert'; $PALANG['pEdit_dbLog_editalias'] = 'bewerk alias'; $PALANG['pEdit_dbLog_editmailbox'] = 'bewerk mailbox'; $PALANG['pSearch'] = 'zoek'; $PALANG['pSearch_welcome'] = 'zoeken naar: '; $PALANG['pReturn_to'] = 'Ga terug naar'; $PALANG['pBroadcast_title'] = 'Verzend broadcast bericht'; $PALANG['pBroadcast_from'] = 'Van'; $PALANG['pBroadcast_name'] = 'Uw naam'; $PALANG['pBroadcast_subject'] = 'Onderwerp'; $PALANG['pBroadcast_message'] = 'Bericht'; $PALANG['pBroadcast_send'] = 'Verzend bericht'; $PALANG['pBroadcast_success'] = 'Uw algemene bericht is verzonden.'; $PALANG['pAdminMenu_broadcast_message'] = 'Algemeen bericht'; $PALANG['pBroadcast_error_empty'] = 'De velden Naam, Onderwerp en Bericht mogen niet leeg zijn !'; $PALANG['pStatus_undeliverable'] = 'Misschien niet af te leveren '; $PALANG['pStatus_custom'] = 'Bezorgen op '; $PALANG['pStatus_popimap'] = 'POP/IMAP '; $PALANG['pPasswordTooShort'] = "Wachtwoord is te kort - moet minimaal %s karakters bevatten"; $PALANG['pInvalidDomainRegex'] = "Ongeldig domein naam %s"; $PALANG['pInvalidDomainDNS'] = "Ongeldig domein %s"; $PALANG['pInvalidMailRegex'] = "Ongeldig email adres"; $PALANG['pFetchmail_welcome'] = 'Haal mail op voor:'; $PALANG['pFetchmail_new_entry'] = 'Nieuw item'; $PALANG['pFetchmail_database_save_error'] = 'Niet in staat dit item toe te voegen aan database!'; $PALANG['pFetchmail_database_save_success'] = 'Item opgeslagen in database.'; $PALANG['pFetchmail_error_invalid_id'] = 'Geen item met ID %s gevonden!'; $PALANG['pFetchmail_invalid_mailbox'] = 'Ongeldige mailbox!'; $PALANG['pFetchmail_server_missing'] = 'Naam van server!'; $PALANG['pFetchmail_user_missing'] = 'Naam van de gebruiker!'; $PALANG['pFetchmail_password_missing'] = 'Wachtwoord!'; $PALANG['pFetchmail_field_id'] = 'ID'; $PALANG['pFetchmail_field_mailbox'] = 'mailbox'; $PALANG['pFetchmail_field_src_server'] = 'server'; $PALANG['pFetchmail_field_src_auth'] = 'authenticatietype'; $PALANG['pFetchmail_field_src_user'] = 'gebruiker'; $PALANG['pFetchmail_field_src_password'] = 'wachtwoord'; $PALANG['pFetchmail_field_src_folder'] = 'map'; $PALANG['pFetchmail_field_poll_time'] = 'controle'; $PALANG['pFetchmail_field_fetchall'] = 'alle berichten ophalen'; $PALANG['pFetchmail_field_keep'] = 'behouden'; $PALANG['pFetchmail_field_protocol'] = 'protocol'; $PALANG['pFetchmail_field_usessl'] = 'SSL actief'; $PALANG['pFetchmail_field_extra_options'] = 'extra opties'; $PALANG['pFetchmail_field_mda'] = 'MD'; $PALANG['pFetchmail_field_date'] = 'datum'; $PALANG['pFetchmail_field_returned_text'] = 'teruggegeven tekst'; $PALANG['pFetchmail_desc_id'] = 'record ID'; $PALANG['pFetchmail_desc_mailbox'] = 'Naar welke mailbox sturen we de opgehaalde mail.'; $PALANG['pFetchmail_desc_src_server'] = 'andere server.'; $PALANG['pFetchmail_desc_src_auth'] = 'In de meeste gevallen \'password\''; # Translators: Please do NOT translate 'password' here $PALANG['pFetchmail_desc_src_user'] = 'Gebruiker op andere server.'; $PALANG['pFetchmail_desc_src_password'] = 'Wachtwoord op andere server.'; $PALANG['pFetchmail_desc_src_folder'] = 'folder op andere server.'; $PALANG['pFetchmail_desc_poll_time'] = 'Check iedere ... minuten.'; $PALANG['pFetchmail_desc_fetchall'] = 'Haal zowel oude (gelezen) als nieuwe berichten op.'; $PALANG['pFetchmail_desc_keep'] = 'Opgehaalde berichten op de server achterlaten.'; $PALANG['pFetchmail_desc_protocol'] = 'het te gebruiken protocol.'; $PALANG['pFetchmail_desc_usessl'] = 'SSL encryptie'; $PALANG['pFetchmail_desc_extra_options'] = 'extra opties voor fetchmail.'; $PALANG['pFetchmail_desc_mda'] = 'mail delivery agent.'; $PALANG['pFetchmail_desc_date'] = 'datum van de laatste berichtencontrole/configuratie verandering.'; $PALANG['pFetchmail_desc_returned_text'] = 'text bericht van de laatste berichtencontrole.'; $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/tr.lang0000664000175000017620000006474211636730120017531 0ustar davidpalepurpleKayýt silinemiyor '; $PALANG['pDelete_delete_success'] = '%s deleted.'; # XXX $PALANG['pDelete_postdelete_error'] = 'Unable to remove mailbox '; # XXX $PALANG['pDelete_domain_error'] = 'Bu domain size ait deðil '; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = 'Unable to delete alias '; # XXX $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = 'Domaininiz için yeni bir alias yaratýn.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
ALIAS uygun deðil!'; $PALANG['pCreate_alias_address_text_error2'] = '
Bu e-posta zaten kullanýlýyor, lütfen baþka bir tane seçin!'; $PALANG['pCreate_alias_address_text_error3'] = '
Alias limitine ulaþtýnýz!'; $PALANG['pCreate_alias_goto'] = 'kime'; $PALANG['pCreate_alias_active'] = 'Active'; # XXX $PALANG['pCreate_alias_button'] = 'Alias Ekle'; $PALANG['pCreate_alias_goto_text'] = 'E-postanýn gitmesi gereken yer.'; $PALANG['pCreate_alias_goto_text_error'] = 'E-postanýn gitmesi gereken bir yer.
Kime alaný uygun deðil!'; $PALANG['pCreate_alias_result_error'] = 'Alias\'ý alias tabþlosuna eklenemedi!'; $PALANG['pCreate_alias_result_success'] = 'Alias tabloya eklendi!'; $PALANG['pCreate_alias_catchall_text'] = 'Hepsini-yakala yaratmak için alias olarak "*" kullanýn.
Domain yönlendirme domaini için kime kýsmýnda "*@domain.tld" kullanýn.'; $PALANG['pEdit_alias_welcome'] = 'domaniniz için bir domain\'i düzenleyin.
Satýr baþýna bir giriþ.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'alias bulunamýyor!'; $PALANG['pEdit_alias_goto'] = 'Kime'; $PALANG['pEdit_alias_active'] = 'Active'; # XXX $PALANG['pEdit_alias_goto_text_error1'] = 'Kime kýsmýna hiçbirþey girmediniz.'; $PALANG['pEdit_alias_goto_text_error2'] = 'Girdiðiniz e-posta uygun deðil: '; $PALANG['pEdit_alias_domain_error'] = 'Bu domain sizin deðil: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Deliver to the local mailbox.'; # XXX $PALANG['pEdit_alias_forward_only'] = 'Forward to given email addresses only.'; # XXX $PALANG['pEdit_alias_button'] = 'Alias Düzenle'; $PALANG['pEdit_alias_result_error'] = 'Alias düzenlenemiyor!'; $PALANG['pCreate_mailbox_welcome'] = 'Domaininiz için yeni bir lokal e-posta yaratýn.'; $PALANG['pCreate_mailbox_username'] = 'Kullanýcý adý'; $PALANG['pCreate_mailbox_username_text_error1'] = '
E-POSTA uygun deðil!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Bu elektronik posta kullanýlmakta, lütfen farklý bir tane seçin!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Posta kutusu yaratma limitinize eriþtiniz!'; $PALANG['pCreate_mailbox_password'] = 'þifre'; $PALANG['pCreate_mailbox_password2'] = 'þifre (tekrar)'; $PALANG['pCreate_mailbox_password_text'] = 'POP3/IMAP için þifre'; $PALANG['pCreate_mailbox_password_text_error'] = 'POP3/IMAP için þifre
Verdiðiniz þifreler birbirini tutmuyor!
Ya da boþ!
'; $PALANG['pCreate_mailbox_name'] = 'Ýsim'; $PALANG['pCreate_mailbox_name_text'] = 'Tam isim'; $PALANG['pCreate_mailbox_quota'] = 'kota'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Veridðiniz kota çok yüksek!'; $PALANG['pCreate_mailbox_active'] = 'Aktif'; $PALANG['pCreate_mailbox_mail'] = 'Posta kutusu yarat'; $PALANG['pCreate_mailbox_button'] = 'Posta kutusu ekle'; $PALANG['pCreate_mailbox_result_error'] = 'Posta kutusu posta kutusu tablosuna eklenemiyor!'; $PALANG['pCreate_mailbox_result_success'] = 'Posta kutusu tabloya eklendi!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'The mailbox has been added to the mailbox table, but none (or only some) of the predefined sub-folders could be created'; # XXX $PALANG['pEdit_mailbox_welcome'] = 'Domaninizdeki bir posta kutusunu düzenleyin.'; $PALANG['pEdit_mailbox_username'] = 'kullanýcý adý'; $PALANG['pEdit_mailbox_username_error'] = 'Posta kutusu bulunamadý!'; $PALANG['pEdit_mailbox_password'] = 'Yeni þifre'; $PALANG['pEdit_mailbox_password2'] = 'Yeni þifre (tekrar)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Verdiðiniz þifreler birbirini tutmuyor!'; $PALANG['pEdit_mailbox_name'] = 'Ýsim'; $PALANG['pEdit_mailbox_name_text'] = 'Full name'; # XXX $PALANG['pEdit_mailbox_quota'] = 'kota'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Verdiðiniz kota çok yüksek!'; $PALANG['pEdit_mailbox_domain_error'] = 'Bu domain dizin deðil: '; $PALANG['pEdit_mailbox_button'] = 'Posta kutusunu düzenle'; $PALANG['pEdit_mailbox_result_error'] = 'Þifre deðiþtirilemedi!'; $PALANG['pPassword_welcome'] = 'Giriþ þifrenizi deðiþtirin.'; $PALANG['pPassword_admin'] = 'Giriþ'; $PALANG['pPassword_admin_text_error'] = 'Verdiðiniz e-posta kutusu hiçbir posta kutusuna uymuyor!'; $PALANG['pPassword_password_current'] = 'þuanki þifre'; $PALANG['pPassword_password_current_text_error'] = 'Þuanki þifrenizi vermediniz!'; $PALANG['pPassword_password'] = 'Yeni Þifre'; $PALANG['pPassword_password2'] = 'Yeni þifre (tekrar)'; $PALANG['pPassword_password_text_error'] = 'Verdiðiniz þifreler birbirini tutmuyor!
Ya da boþ!
'; $PALANG['pPassword_button'] = 'Þifreyi deðiþtir'; $PALANG['pPassword_result_error'] = 'Þifreniz deðiþtirilemedi!'; $PALANG['pPassword_result_success'] = 'þifreniz deðiþtirildi!'; $PALANG['pEdit_vacation_set'] = 'Change / Set away message'; # XXX $PALANG['pEdit_vacation_remove'] = 'Remove away message'; # XXX $PALANG['pVacation_result_error'] = 'Unable to update auto response settings!'; # XXX $PALANG['pVacation_result_removed'] = 'Auto response has been removed!'; # XXX $PALANG['pVacation_result_added'] = 'Auto response has been enabled!'; # XXX $PALANG['pViewlog_welcome'] = 'Son 10 hareket:'; $PALANG['pViewlog_timestamp'] = 'Timestamp'; $PALANG['pViewlog_username'] = 'Yönetici'; $PALANG['pViewlog_domain'] = 'Domain'; $PALANG['pViewlog_action'] = 'Aksiyon'; $PALANG['pViewlog_data'] = 'Veri'; $PALANG['pViewlog_action_create_mailbox'] = 'create mailbox'; # XXX $PALANG['pViewlog_action_delete_mailbox'] = 'delete mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox'] = 'edit mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox_state'] = 'edit mailbox active'; # XXX $PALANG['pViewlog_action_create_alias'] = 'create alias'; # XXX $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'delete alias'; # XXX $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'edit alias'; # XXX $PALANG['pViewlog_action_edit_alias_state'] = 'edit alias active'; # XXX $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'change password'; # XXX $PALANG['pViewlog_button'] = 'Git'; $PALANG['pViewlog_result_error'] = 'Loglar bulunamýyor!'; $PALANG['pSendmail_welcome'] = 'Eposta gönder.'; $PALANG['pSendmail_admin'] = 'kimden'; $PALANG['pSendmail_to'] = 'Kime'; $PALANG['pSendmail_to_text_error'] = 'Kime doðru bir e-posta deðil!'; $PALANG['pSendmail_subject'] = 'konu'; $PALANG['pSendmail_subject_text'] = 'Hoþ geldiniz'; $PALANG['pSendmail_body'] = 'Metin'; $PALANG['pSendmail_button'] = 'Mesaj Gönder'; $PALANG['pSendmail_result_error'] = 'Posta kutusu yaratýlamadý!'; # XXX text change - new: Unable to send email! $PALANG['pSendmail_result_success'] = 'Posta kutusu yaratýldý!'; # XXX text change - new: Email sent! $PALANG['pAdminMenu_list_admin'] = 'Yönetici Listesi'; $PALANG['pAdminMenu_list_domain'] = 'Domain Listesi'; $PALANG['pAdminMenu_list_virtual'] = 'Sanal Liste'; $PALANG['pAdminMenu_viewlog'] = 'Log Ýzle'; $PALANG['pAdminMenu_backup'] = 'Yedek'; $PALANG['pAdminMenu_create_domain_admins'] = 'Domain Yöneticileri'; $PALANG['pAdminMenu_create_admin'] = 'Yeni Yönetici'; $PALANG['pAdminMenu_create_domain'] = 'Yeni Domain'; $PALANG['pAdminMenu_create_alias'] = 'Alias ekle'; $PALANG['pAdminMenu_create_mailbox'] = 'Postakutusu ekle'; $PALANG['pAdminList_admin_domain'] = 'Domain'; $PALANG['pAdminList_admin_username'] = 'Yönetici'; $PALANG['pAdminList_admin_count'] = 'Domainler'; $PALANG['pAdminList_admin_modified'] = 'Son Düzenleme'; $PALANG['pAdminList_admin_active'] = 'Aktif'; $PALANG['pAdminList_domain_domain'] = 'Domain'; $PALANG['pAdminList_domain_description'] = 'Açýklama'; $PALANG['pAdminList_domain_aliases'] = 'Aliaslar'; $PALANG['pAdminList_domain_mailboxes'] = 'Posta kutularý'; $PALANG['pAdminList_domain_maxquota'] = 'Max kota (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; $PALANG['pAdminList_domain_modified'] = 'Son Düzenleme'; $PALANG['pAdminList_domain_active'] = 'Aktif'; $PALANG['pAdminList_virtual_button'] = 'Git'; $PALANG['pAdminList_virtual_welcome'] = 'Genel Bilgiler:'; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Aliaslar'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Postakutularý'; $PALANG['pAdminList_virtual_alias_address'] = 'Kimden'; $PALANG['pAdminList_virtual_alias_goto'] = 'Kime'; $PALANG['pAdminList_virtual_alias_modified'] = 'Son Düzenleme'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Eposta'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Ýsim'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'kota (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Son Düzenleme'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Aktif'; $PALANG['pAdminCreate_domain_welcome'] = 'Yeni domain ekle'; $PALANG['pAdminCreate_domain_domain'] = 'Domain'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Bu Domain halen bulunmakta!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'The domain is invalid!'; # XXX $PALANG['pAdminCreate_domain_description'] = 'Açýklama'; $PALANG['pAdminCreate_domain_aliases'] = 'Aliaslar'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = iptal | 0 = limisiz'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Postakutularý'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = iptal | 0 = limitsiz'; $PALANG['pAdminCreate_domain_maxquota'] = 'Max Kota'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = iptal | 0 = limitsiz'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminCreate_domain_transport_text'] = 'Define transport'; # XXX $PALANG['pAdminCreate_domain_defaultaliases'] = 'Öntanýmlý posta aliasý ekle'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; # XXX $PALANG['pAdminCreate_domain_backupmx'] = 'Mail server is backup MX'; # XXX $PALANG['pAdminCreate_domain_button'] = 'Domain ekle'; $PALANG['pAdminCreate_domain_result_error'] = 'Domain eklenemedi!'; $PALANG['pAdminCreate_domain_result_success'] = 'Domain eklendi!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Unable to remove domain!'; # XXX $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = 'Domain düzenle'; $PALANG['pAdminEdit_domain_domain'] = 'Domain'; $PALANG['pAdminEdit_domain_description'] = 'Açýklama'; $PALANG['pAdminEdit_domain_aliases'] = 'Aliaslar'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = iptal | 0 = limitsiz'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Posta kutularý'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = iptal | 0 = limitsiz'; $PALANG['pAdminEdit_domain_maxquota'] = 'Max Kota'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = iptal | 0 = limitsiz'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminEdit_domain_transport_text'] = 'Define transport'; # XXX $PALANG['pAdminEdit_domain_backupmx'] = 'Mail server is backup MX'; # XXX $PALANG['pAdminEdit_domain_active'] = 'Aktif'; $PALANG['pAdminEdit_domain_button'] = 'Domain düzenle'; $PALANG['pAdminEdit_domain_result_error'] = 'Domain düzenlenemedi!'; $PALANG['pAdminCreate_admin_welcome'] = 'Yöneticiye yeni bir domain ekle'; $PALANG['pAdminCreate_admin_username'] = 'Yönetici'; $PALANG['pAdminCreate_admin_username_text'] = 'Eposta adresi'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Eposta adresi
Yönetici uygun bir eposta adresi deðil!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Eposta adresi
Yönetici halen bulunmakta ya da uygun deðil'; $PALANG['pAdminCreate_admin_password'] = 'Þifre'; $PALANG['pAdminCreate_admin_password2'] = 'Þifre (tekrar)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Girdiðiniz þifreler uymuyor!
Ya da boþ!
'; $PALANG['pAdminCreate_admin_button'] = 'Yönetici ekle'; $PALANG['pAdminCreate_admin_result_error'] = 'Yönetici eklenemiyor!'; $PALANG['pAdminCreate_admin_result_success'] = 'Yönetici eklendi!'; $PALANG['pAdminCreate_admin_address'] = 'Domain'; $PALANG['pAdminEdit_admin_welcome'] = 'Domain yöneticisi düzenle'; $PALANG['pAdminEdit_admin_username'] = 'Yönetici'; $PALANG['pAdminEdit_admin_password'] = 'Þifre'; $PALANG['pAdminEdit_admin_password2'] = 'þifre (tekrar)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Verdiðiniz þifreler birbirini tutmuyor!
Ya da boþ!
'; $PALANG['pAdminEdit_admin_active'] = 'Aktif'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super admin'; # XXX $PALANG['pAdminEdit_admin_button'] = 'Yönetici Ekle'; $PALANG['pAdminEdit_admin_result_error'] = 'Yönetici düzenlenemedi!'; $PALANG['pAdminEdit_admin_result_success'] = 'Yönetici düzenlendi!'; $PALANG['pUsersLogin_welcome'] = 'Posta kutusu sahipleri, þifre ddeðiþtirmek için giriþ yapýn.'; $PALANG['pUsersLogin_username'] = 'Giriþ (eposta)'; $PALANG['pUsersLogin_password'] = 'þifre'; $PALANG['pUsersLogin_button'] = 'Kullanýcý adý'; $PALANG['pUsersLogin_username_incorrect'] = 'Kullanýcý adýnýz doðru deðil. E-posta adresiniz ile giriþ yaptýðýnýzdan emin olunuz!'; $PALANG['pUsersLogin_password_incorrect'] = 'Þifreniz doðru deðil!'; $PALANG['pUsersMenu_vacation'] = 'Otomatik cevaplama'; $PALANG['pUsersMenu_edit_alias'] = 'Yönlendirmen deðiþtir'; $PALANG['pUsersMenu_password'] = 'þifre deðiþtir'; $PALANG['pUsersMain_vacation'] = 'Posta kutunuz için "ofis dýþý" mesajý veya otomatik cevaplama ekleyin.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' is ON, click \'' . $PALANG['pUsersMenu_vacation'] . '\' to ' . $PALANG['edit'] . '/remove'; # XXX $PALANG['pUsersMain_edit_alias'] = 'Eposta yönlendirmenizi deðiþtirin.'; $PALANG['pUsersMain_password'] = 'þifrenizi deðiþtirin.'; $PALANG['pUsersVacation_welcome'] = 'Otomatik Cevaplama.'; $PALANG['pUsersVacation_welcome_text'] = 'Zaten bir otomatik cevaplamanýz bulunmakta!'; $PALANG['pUsersVacation_subject'] = 'konu'; $PALANG['pUsersVacation_subject_text'] = 'Ofis dýþýnda'; $PALANG['pUsersVacation_body'] = 'Metin'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << tarihinden den ine burada bulunmayacaðým. Acil durumlarda lütfen a baþvurunuz. EOM; $PALANG['pUsersVacation_button_away'] = 'Dýþarý gidiyorum.'; $PALANG['pUsersVacation_button_back'] = 'Geri Geliyorum'; $PALANG['pUsersVacation_result_error'] = 'otomatik cevaplama ayarlarýnýzý deðiþtirilemiyor!'; $PALANG['pUsersVacation_result_success'] = 'Otomatik cevaplamanýz kaldýrýldý!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'create mailbox'; # XXX $PALANG['pCreate_dbLog_createalias'] = 'create alias'; # XXX $PALANG['pDelete_dbLog_deletealias'] = 'delete alias'; # XXX $PALANG['pDelete_dbLog_deletemailbox'] = 'delete mailbox'; # XXX $PALANG['pEdit_dbLog_editactive'] = 'change active state'; # XXX $PALANG['pEdit_dbLog_editalias'] = 'edit alias'; # XXX $PALANG['pEdit_dbLog_editmailbox'] = 'edit mailbox'; # XXX $PALANG['pSearch'] = 'search'; # XXX $PALANG['pSearch_welcome'] = 'Searching for: '; # XXX $PALANG['pReturn_to'] = 'Return to'; # XXX $PALANG['pBroadcast_title'] = 'Send broadcast message'; # XXX $PALANG['pBroadcast_from'] = 'From'; # XXX $PALANG['pBroadcast_name'] = 'Your name'; # XXX $PALANG['pBroadcast_subject'] = 'Subject'; # XXX $PALANG['pBroadcast_message'] = 'Message'; # XXX $PALANG['pBroadcast_send'] = 'Send message'; # XXX $PALANG['pBroadcast_success'] = 'Your broadcast message was sent.'; # XXX $PALANG['pAdminMenu_broadcast_message'] = 'Broadcast message'; # XXX $PALANG['pBroadcast_error_empty'] = 'The fields Name, Subject and Message should\'t be empty !'; # XXX $PALANG['pStatus_undeliverable'] = 'maybe UNDELIVERABLE '; # XXX $PALANG['pStatus_custom'] = 'Delivers to '; # XXX $PALANG['pStatus_popimap'] = 'POP/IMAP '; # XXX $PALANG['pPasswordTooShort'] = "Password is too short - requires %s characters"; # XXX $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Fetch mail for:'; # XXX $PALANG['pFetchmail_new_entry'] = 'New entry'; # XXX $PALANG['pFetchmail_database_save_error'] = 'Could not save this entry in the database!'; # XXX $PALANG['pFetchmail_database_save_success'] = 'Entry saved in database.'; # XXX $PALANG['pFetchmail_error_invalid_id'] = 'No entry with ID %s found!'; # XXX $PALANG['pFetchmail_invalid_mailbox'] = 'Invalid mailbox!'; # XXX $PALANG['pFetchmail_server_missing'] = 'Please enter the remote server name!'; # XXX $PALANG['pFetchmail_user_missing'] = 'Please enter the remote username!'; # XXX $PALANG['pFetchmail_password_missing'] = 'Please enter the remote password!'; # XXX $PALANG['pFetchmail_field_id'] = 'ID'; # XXX $PALANG['pFetchmail_field_mailbox'] = 'Mailbox'; # XXX $PALANG['pFetchmail_field_src_server'] = 'Server'; # XXX $PALANG['pFetchmail_field_src_auth'] = 'Auth Type'; # XXX $PALANG['pFetchmail_field_src_user'] = 'User'; # XXX $PALANG['pFetchmail_field_src_password'] = 'Password'; # XXX $PALANG['pFetchmail_field_src_folder'] = 'Folder'; # XXX $PALANG['pFetchmail_field_poll_time'] = 'Poll'; # XXX $PALANG['pFetchmail_field_fetchall'] = 'Fetch All'; # XXX $PALANG['pFetchmail_field_keep'] = 'Keep'; # XXX $PALANG['pFetchmail_field_protocol'] = 'Protocol'; # XXX $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra Options'; # XXX $PALANG['pFetchmail_field_mda'] = 'MDA'; # XXX $PALANG['pFetchmail_field_date'] = 'Date'; # XXX $PALANG['pFetchmail_field_returned_text'] = 'Returned Text'; # XXX $PALANG['pFetchmail_desc_id'] = 'Record ID'; # XXX $PALANG['pFetchmail_desc_mailbox'] = 'Local mailbox'; # XXX $PALANG['pFetchmail_desc_src_server'] = 'Remote Server'; # XXX $PALANG['pFetchmail_desc_src_auth'] = 'Mostly \'password\''; # Translators: Please do NOT translate 'password' here # XXX $PALANG['pFetchmail_desc_src_user'] = 'Remote User'; # XXX $PALANG['pFetchmail_desc_src_password'] = 'Remote Password'; # XXX $PALANG['pFetchmail_desc_src_folder'] = 'Remote Folder'; # XXX $PALANG['pFetchmail_desc_poll_time'] = 'Poll every ... minutes'; # XXX $PALANG['pFetchmail_desc_fetchall'] = 'Retrieve both old (seen) and new messages'; # XXX $PALANG['pFetchmail_desc_keep'] = 'Keep retrieved messages on the remote mailserver'; # XXX $PALANG['pFetchmail_desc_protocol'] = 'Protocol to use'; # XXX $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Extra fetchmail Options'; # XXX $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; # XXX $PALANG['pFetchmail_desc_date'] = 'Date of last polling/configuration change'; # XXX $PALANG['pFetchmail_desc_returned_text'] = 'Text message from last polling'; # XXX $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/lt.lang0000664000175000017620000006516712111774247017534 0ustar davidpalepurple // $PALANG['YES'] = 'TAIP'; $PALANG['NO'] = 'NE'; $PALANG['edit'] = 'keisti'; $PALANG['del'] = 'šalinti'; $PALANG['exit'] = 'Išeiti'; $PALANG['cancel'] = 'Atšaukti'; $PALANG['save'] = 'Išsaugoti'; $PALANG['confirm'] = 'Tikrai norite šalinti?\n'; $PALANG['confirm_domain'] = 'Tikrai norite šalinti visus šios srities įrašus? Operacija negrįžtama!\n'; $PALANG['check_update'] = 'Patikrinti versiją'; $PALANG['invalid_parameter'] = 'Neteisingas parametras!'; $PALANG['pFooter_logged_as'] = 'Prisijungęs kaip %s'; $PALANG['pLogin_welcome'] = 'Pašto srities administratorius.'; $PALANG['pLogin_username'] = 'Vartotojas (el.paštas)'; $PALANG['pLogin_password'] = 'Slaptažodis'; $PALANG['pLogin_button'] = 'Prisijungti'; $PALANG['pLogin_failed'] = 'Neteisingas el. pašto adresas arba slaptažodis.'; $PALANG['pLogin_login_users'] = 'Pašto vartotojams jungtis prie vartotojų sekcijos.'; $PALANG['pMenu_main'] = 'Pagrindinis'; $PALANG['pMenu_overview'] = 'Peržiūra'; $PALANG['pMenu_create_alias'] = 'Naujas sinonimas'; $PALANG['pMenu_create_alias_domain'] = 'Naujas srities sinonimas'; $PALANG['pMenu_create_mailbox'] = 'Nauja pašto dėžutė'; $PALANG['pMenu_fetchmail'] = 'Atsisiųsti paštą'; $PALANG['pMenu_sendmail'] = 'Siųsti laišką'; $PALANG['pMenu_password'] = 'Slaptažodis'; $PALANG['pMenu_viewlog'] = 'Žurnalas'; $PALANG['pMenu_logout'] = 'Atsijungti'; $PALANG['pMain_welcome'] = 'Sveiki prisijungę prie pašto administratoriaus!'; $PALANG['pMain_overview'] = 'Pežiūrėti visas pašto dėžutes ir sinonimus. Čionai atliekami pakeitimai, šalinimas.'; $PALANG['pMain_create_alias'] = 'Naujas pašto sinonimas.'; $PALANG['pMain_create_mailbox'] = 'Nauja pašto dėžutė.'; $PALANG['pMain_sendmail'] = 'Siųsti laišką į vieną naujai sukurtą pašto dėžutę.'; $PALANG['pMain_password'] = 'Keisti administratoriaus slaptažodį.'; $PALANG['pMain_viewlog'] = 'Peržiūrėti įvykių žurnalus.'; $PALANG['pMain_logout'] = 'Atsijungti nuo sistemos'; $PALANG['pOverview_disabled'] = 'Išjungta(s)'; $PALANG['pOverview_unlimited'] = 'Neribota(s)'; $PALANG['pOverview_title'] = ':: Nustatytos sritys'; $PALANG['pOverview_up_arrow'] = 'Eiti į viršų'; $PALANG['pOverview_right_arrow'] = 'Kitas puslapis'; $PALANG['pOverview_left_arrow'] = 'Ankstesnis puslapis'; $PALANG['pOverview_alias_domain_title'] = ':: Srities sinonimai'; $PALANG['pOverview_alias_title'] = ':: Sinonimai'; $PALANG['pOverview_mailbox_title'] = ':: Pašto dėžutės'; $PALANG['pOverview_button'] = 'Eiti'; $PALANG['pOverview_welcome'] = 'Peržiūra '; $PALANG['pOverview_alias_domain_aliases'] = 'Srities sinonimai'; $PALANG['pOverview_alias_domain_target'] = '%s yra srities sinonimas:'; $PALANG['pOverview_alias_alias_count'] = 'sinonimų'; $PALANG['pOverview_alias_mailbox_count'] = 'pašto dėžučių'; $PALANG['pOverview_alias_address'] = 'Iš'; $PALANG['pOverview_alias_goto'] = 'Į'; $PALANG['pOverview_alias_modified'] = 'Paskutinis keitimas'; $PALANG['pOverview_alias_domain_modified'] = 'Paskutinis keitimas'; $PALANG['pOverview_alias_active'] = 'Įjungtas'; $PALANG['pOverview_alias_domain_active'] = 'Įjungtas'; $PALANG['pOverview_alias_edit'] = 'Sinonimas'; $PALANG['and_x_more'] = '[ir %s daugiau...]'; $PALANG['pOverview_mailbox_username'] = 'El.paštas'; $PALANG['pOverview_mailbox_name'] = 'Vardas'; $PALANG['pOverview_mailbox_quota'] = 'Kvota (MB)'; $PALANG['pOverview_mailbox_modified'] = 'Paskutinis keitimas'; $PALANG['pOverview_mailbox_active'] = 'Įjungta(s)'; $PALANG['pOverview_vacation_edit'] = 'ATOSTOGOS ĮJUNGTOS'; $PALANG['pOverview_vacation_option'] = 'Atostogų nustatymai'; $PALANG['pOverview_get_domain'] = 'Sritis'; $PALANG['pOverview_get_aliases'] = 'Sinonimai'; $PALANG['pOverview_get_alias_domains'] = 'Srities sinonimai'; $PALANG['pOverview_get_mailboxes'] = 'Pašto dėžutės'; $PALANG['pOverview_get_quota'] = 'Pašto dėžutės kvota (MB)'; $PALANG['pOverview_get_modified'] = 'Paskutinis keitimas'; $PALANG['pDelete_delete_error'] = 'Nepavyko pašalinti įrašo '; $PALANG['pDelete_delete_success'] = '%s pašalinta(s).'; $PALANG['pDelete_postdelete_error'] = 'Nepavyko pašalinti pašto dėžutės '; $PALANG['pDelete_domain_error'] = 'Ne jūsų sritis '; $PALANG['pDelete_domain_alias_error'] = 'Ne jūsų sritis '; $PALANG['pDelete_alias_error'] = 'Nepavyko pašalinti sinonimo '; $PALANG['pCreate_alias_domain_welcome'] = 'Sričių sinonimai.'; $PALANG['pCreate_alias_domain_alias'] = 'Srities sinonimas'; $PALANG['pCreate_alias_domain_alias_text'] = 'Sritis, kuriai ateina laiškai.'; $PALANG['pCreate_alias_domain_target'] = 'Nukreipta sritis'; $PALANG['pCreate_alias_domain_target_text'] = 'Sritis, į kurią turi būti nukreipti laiškai.'; $PALANG['pCreate_alias_domain_active'] = 'Įjungta'; $PALANG['pCreate_alias_domain_button'] = 'Pridėti srities sinonimą'; $PALANG['pCreate_alias_domain_error1'] = 'Jūs negalite sukurti pasirinktos konfigūracijos.'; $PALANG['pCreate_alias_domain_error2'] = 'Pasirinkta neteisinga konfigūracija, pasirinkite kitą!'; $PALANG['pCreate_alias_domain_error3'] = 'Duomenų bazės papildyti nepavyko.'; $PALANG['pCreate_alias_domain_error4'] = 'Visos sritys jau turi sinonimus.'; $PALANG['pCreate_alias_domain_success'] = 'Srities sinonimas užregistruotas!'; $PALANG['pCreate_alias_welcome'] = 'Naujas sinonimas.'; $PALANG['pCreate_alias_address'] = 'Sinonimas'; $PALANG['pCreate_alias_address_text_error1'] = '
Netinkamas sinonimas!'; $PALANG['pCreate_alias_address_text_error2'] = '
Šis el.pašto adresas jau yra, pasirinkite kitą pavadinimą!'; $PALANG['pCreate_alias_address_text_error3'] = '
Išnaudota visa pašto sinonimų kvota!'; $PALANG['pCreate_alias_goto'] = 'Persiųsti'; $PALANG['pCreate_alias_active'] = 'Įjungtas'; $PALANG['pCreate_alias_button'] = 'Naujas sinonimas'; $PALANG['pCreate_alias_goto_text'] = 'Adresas, kuriuo persiųsti paštą.'; $PALANG['pCreate_alias_goto_text_error'] = 'Adresas, kuriuo persiųsti paštą.
Įvestas neteisingai!'; $PALANG['pCreate_alias_result_error'] = 'Sinonimo registruoti nepavyko!'; $PALANG['pCreate_alias_result_success'] = 'Sinonimas užregistruotas!'; $PALANG['pCreate_alias_catchall_text'] = 'Jei norite sukurti sinonimą, kuris gautų visas žinutes neegzistuojantiems adresatams, naudokite "*".'; $PALANG['pEdit_alias_welcome'] = 'Keisti sinonimą.
Eilutėje leidžiamas tik vienas įrašas.'; $PALANG['pEdit_alias_address'] = 'Sinonimas'; $PALANG['pEdit_alias_address_error'] = 'Sinonimas nerastas!'; $PALANG['pEdit_alias_goto'] = 'Kam'; $PALANG['pEdit_alias_active'] = 'Įjungtas'; $PALANG['pEdit_alias_goto_text_error1'] = 'Neužpildėte lauko "Kam"'; $PALANG['pEdit_alias_goto_text_error2'] = 'Įvestas neteisingas pašto adresas: '; $PALANG['pEdit_alias_domain_error'] = 'Ši sritis ne jūsų: '; $PALANG['pEdit_alias_domain_result_error'] = 'Nepavyko pakeisti srities sinonimo!'; $PALANG['pEdit_alias_forward_and_store'] = 'Pristatyti į vietinę pašto dėžutę.'; $PALANG['pEdit_alias_forward_only'] = 'Persiųsti nurodytiems el. pašto adresams.'; $PALANG['pEdit_alias_button'] = 'Keisti sinonimą'; $PALANG['pEdit_alias_result_error'] = 'Sinonimo pakeisti nepavyko!'; $PALANG['pCreate_mailbox_welcome'] = 'Nauja pašto dėžutė.'; $PALANG['pCreate_mailbox_username'] = 'Vartotojas'; $PALANG['pCreate_mailbox_username_text_error1'] = '
Šis el.pašto adresas neteisingas!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Šis el.pašto adresas jau yra, pasirinkite kitą pavadinimą!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Išnaudota srities pašto dėžučių kvota!'; $PALANG['pCreate_mailbox_password'] = 'Slaptažodis'; $PALANG['pCreate_mailbox_password2'] = 'Slaptažodis (dar kartą)'; $PALANG['pCreate_mailbox_password_text'] = 'Slaptažodis jungtis prie POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Slaptažodis jungtis prie POP3/IMAP
Įvesti slaptažodžiai nesutampa
Arba neįvesti!
'; $PALANG['pCreate_mailbox_name'] = 'Vardas'; $PALANG['pCreate_mailbox_name_text'] = 'Vardas Pavardė'; $PALANG['pCreate_mailbox_quota'] = 'Kvota'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Įvesta per didelė kvota!'; $PALANG['pCreate_mailbox_active'] = 'Įjungta(s)'; $PALANG['pCreate_mailbox_mail'] = 'Siųsti pasveikinimo žinutę'; $PALANG['pCreate_mailbox_button'] = 'Nauja pašto dėžutė'; $PALANG['pCreate_mailbox_result_error'] = 'Pašto dėžutės užregistruoti nepavyko!'; $PALANG['pCreate_mailbox_result_success'] = 'Pašto dėžutė užregistruota!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'Pašto dėžutė užregistruota, bet nepavyko sukurti (galbūt kai kurių) nustatytų subdirektorijų'; $PALANG['pEdit_mailbox_welcome'] = 'Keisti pašto dėžutę.'; $PALANG['pEdit_mailbox_username'] = 'Vartotojas'; $PALANG['pEdit_mailbox_username_error'] = 'Pašto dėžutė nerasta!'; $PALANG['pEdit_mailbox_password'] = 'Naujas slaptažodis'; $PALANG['pEdit_mailbox_password2'] = 'Naujas slaptažodis (dar kartą)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Įvesti slaptažodžiai nesutampa!'; $PALANG['pEdit_mailbox_name'] = 'Vardas'; $PALANG['pEdit_mailbox_name_text'] = 'Vardas Pavardė'; $PALANG['pEdit_mailbox_quota'] = 'Kvota'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Įvesta per didelė kvota!'; $PALANG['pEdit_mailbox_domain_error'] = 'Ne jūsų sritis: '; $PALANG['pEdit_mailbox_button'] = 'Keisti pašto dėžutę'; $PALANG['pEdit_mailbox_result_error'] = 'Pašto dėžutės pakeisti nepavyko!'; $PALANG['pPassword_welcome'] = 'Pakeiskite prisijungimo slaptažodį.'; $PALANG['pPassword_admin'] = 'Prisijungti'; $PALANG['pPassword_admin_text_error'] = 'Tokios pašto dėžutės nėra!'; $PALANG['pPassword_password_current'] = 'Dabartinis slaptažodis'; $PALANG['pPassword_password_current_text_error'] = 'Neįvedėte dabartinio slaptažodžio!'; $PALANG['pPassword_password'] = 'Naujas slaptažodis'; $PALANG['pPassword_password2'] = 'Naujas slaptažodis (dar kartą)'; $PALANG['pPassword_password_text_error'] = 'Įvesti slaptažodžiai nesutampa!
Arba neįvesti!
'; $PALANG['pPassword_button'] = 'Keisti slaptažodį'; $PALANG['pPassword_result_error'] = 'Slaptažodžio pakeisti nepavyko!'; $PALANG['pPassword_result_success'] = 'Slaptažodis pakeistas!'; $PALANG['pEdit_vacation_set'] = 'Pakeisti / nustatyti atostogų pranešimą'; $PALANG['pEdit_vacation_remove'] = 'Išjungti atostogų pranešimą'; $PALANG['pVacation_result_error'] = 'Nepavyko pakeisti atostogų nustatymų!'; $PALANG['pVacation_result_removed'] = 'Atostogų pranešimas išjungtas!'; $PALANG['pVacation_result_added'] = 'Atostogų pranešimas įjungtas!'; $PALANG['pViewlog_welcome'] = 'Peržiūrėti paskutinius 10 vartotojo veiksmų '; $PALANG['pViewlog_timestamp'] = 'Laikas'; $PALANG['pViewlog_username'] = 'Vartotojas'; $PALANG['pViewlog_domain'] = 'Sritis'; $PALANG['pViewlog_action'] = 'Veiksmas'; $PALANG['pViewlog_data'] = 'Duomenys'; $PALANG['pViewlog_action_create_mailbox'] = 'sukurta pašto dėžutė'; $PALANG['pViewlog_action_delete_mailbox'] = 'panaikinta pašto dėžutė'; $PALANG['pViewlog_action_edit_mailbox'] = 'pakeista pašto dėžutė'; $PALANG['pViewlog_action_edit_mailbox_state'] = '(į)išjungta pašto dėžutė'; $PALANG['pViewlog_action_create_alias'] = 'sukurtas sinonimas'; $PALANG['pViewlog_action_create_alias_domain'] = 'sukurtas srities sinonimas'; $PALANG['pViewlog_action_delete_alias'] = 'panaikintas sinonimas'; $PALANG['pViewlog_action_delete_alias_domain'] = 'panaikintas srities sinonimas'; $PALANG['pViewlog_action_edit_alias'] = 'pakeistas sinonimas'; $PALANG['pViewlog_action_edit_alias_state'] = '(į)išjungtas sinonimas'; $PALANG['pViewlog_action_edit_alias_domain_state'] = '(į)išjungtas srities sinonimas'; $PALANG['pViewlog_action_edit_password'] = 'pakeistas slaptažodis'; $PALANG['pViewlog_button'] = 'Eiti'; $PALANG['pViewlog_result_error'] = 'Įvykių žurnalas nerastas!'; $PALANG['pSendmail_welcome'] = 'Siųsti laišką'; $PALANG['pSendmail_admin'] = 'Nuo'; $PALANG['pSendmail_to'] = 'Kam'; $PALANG['pSendmail_to_text_error'] = 'Adresatas neįvestas arba neteisingas pašto adresas!'; $PALANG['pSendmail_subject'] = 'Tema'; $PALANG['pSendmail_subject_text'] = 'Sveiki'; $PALANG['pSendmail_body'] = 'Žinutė'; $PALANG['pSendmail_button'] = 'Siųsti'; $PALANG['pSendmail_result_error'] = 'Žinutės išsiųsti nepavyko!'; $PALANG['pSendmail_result_success'] = 'Žinutė išsiųsta!'; $PALANG['pAdminMenu_list_admin'] = 'Administratoriai'; $PALANG['pAdminMenu_list_domain'] = 'Sritys'; $PALANG['pAdminMenu_list_virtual'] = 'Sinonimai'; $PALANG['pAdminMenu_viewlog'] = 'Žurnalas'; $PALANG['pAdminMenu_backup'] = 'Kopijos'; $PALANG['pAdminMenu_create_domain_admins'] = 'Sričių administratoriai'; $PALANG['pAdminMenu_create_admin'] = 'Naujas administratorius'; $PALANG['pAdminMenu_create_domain'] = 'Nauja sritis'; $PALANG['pAdminMenu_create_alias'] = 'Naujas sinonimas'; $PALANG['pAdminMenu_create_mailbox'] = 'Nauja pašto dėžutė'; $PALANG['pAdminList_admin_domain'] = 'Sritis'; $PALANG['pAdminList_admin_username'] = 'Administratorius'; $PALANG['pAdminList_admin_count'] = 'Sritys'; $PALANG['pAdminList_admin_modified'] = 'Paskutinį kartą keista(s)'; $PALANG['pAdminList_admin_active'] = 'Įjungta(s)'; $PALANG['pAdminList_domain_domain'] = 'Sritis'; $PALANG['pAdminList_domain_description'] = 'Aprašymas'; $PALANG['pAdminList_domain_aliases'] = 'Sinonimai'; $PALANG['pAdminList_domain_mailboxes'] = 'Pašto dėžutės'; $PALANG['pAdminList_domain_maxquota'] = 'Kvota (MB)'; $PALANG['pAdminList_domain_transport'] = 'Srities transportas'; $PALANG['pAdminList_domain_backupmx'] = 'Atsarginis MX'; $PALANG['pAdminList_domain_modified'] = 'Paskutinį kartą keista(s)'; $PALANG['pAdminList_domain_active'] = 'Įjungta'; $PALANG['pAdminList_virtual_button'] = 'Eiti'; $PALANG['pAdminList_virtual_welcome'] = 'Peržiūrėti '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'sinonimus'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'pašto dėžutes'; $PALANG['pAdminList_virtual_alias_address'] = 'Iš'; $PALANG['pAdminList_virtual_alias_goto'] = 'Į'; $PALANG['pAdminList_virtual_alias_modified'] = 'Paskutinį kartą keistas'; $PALANG['pAdminList_virtual_mailbox_username'] = 'El.paštas'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Vardas'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Kvota (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Paskutinį kartą keista'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Įjungta'; $PALANG['pAdminCreate_domain_welcome'] = 'Nauja sritis'; $PALANG['pAdminCreate_domain_domain'] = 'Sritis'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Tokia sritis jau yra!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'Neteisinga sritis!'; $PALANG['pAdminCreate_domain_description'] = 'Aprašymas'; $PALANG['pAdminCreate_domain_aliases'] = 'Sinonimai'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = išjungta(s) | 0 = neribota(s)'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Pašto dėžutės'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = išjungta(s) | 0 = neribota(s)'; $PALANG['pAdminCreate_domain_maxquota'] = 'Maksimali kvota'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = išjungta(s) | 0 = neribota(s)'; $PALANG['pAdminCreate_domain_transport'] = 'Srities transportas'; $PALANG['pAdminCreate_domain_transport_text'] = 'Nustatyti transportą'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Registruoti tipinius pašto sinonimus'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'Tai atsarginis pašto serveris (MX)'; $PALANG['pAdminCreate_domain_button'] = 'Registruoti sritį'; $PALANG['pAdminCreate_domain_result_error'] = 'Srities užregistruoti nepavyko!'; $PALANG['pAdminCreate_domain_result_success'] = 'Sritis užregistruota!'; $PALANG['pAdminDelete_admin_error'] = 'Nepavyko panaikinti administratoriaus!'; $PALANG['pAdminDelete_domain_error'] = 'Nepavyko panaikinti srities!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Nepavyko panaikinti srities sinonimo!'; $PALANG['pAdminEdit_domain_welcome'] = 'Keisti sritį'; $PALANG['pAdminEdit_domain_domain'] = 'Sritis'; $PALANG['pAdminEdit_domain_description'] = 'Aprašymas'; $PALANG['pAdminEdit_domain_aliases'] = 'Sinonimai'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 išjungta(s) | 0 = neribota(s)'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Pašto dėžutės'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 išjungta(s) | 0 = neribota(s)'; $PALANG['pAdminEdit_domain_maxquota'] = 'Maksimali kvota'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = išjungta(s) | 0 = neribota(s)'; $PALANG['pAdminEdit_domain_transport'] = 'Srities transportas'; $PALANG['pAdminEdit_domain_transport_text'] = 'Nustatyti transportą'; $PALANG['pAdminEdit_domain_backupmx'] = 'Tai atsarginis pašto serveris (MX)'; $PALANG['pAdminEdit_domain_active'] = 'Įjungtas'; $PALANG['pAdminEdit_domain_button'] = 'Keisti sritį'; $PALANG['pAdminEdit_domain_result_error'] = 'Srities pakeisti nepavyko!'; $PALANG['pAdminCreate_admin_welcome'] = 'Registruoti naują srities administratorių'; $PALANG['pAdminCreate_admin_username'] = 'Administratorius'; $PALANG['pAdminCreate_admin_username_text'] = 'El.pašto adresas'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'El.pašto adresas
Neteisingas Administratoriaus el.pašto adresas!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'El.pašto adresas
Administratorius šiai sričiai jau yra'; $PALANG['pAdminCreate_admin_password'] = 'Slaptažodis'; $PALANG['pAdminCreate_admin_password2'] = 'Slaptažodis (dar kartą)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Įvesti slaptažodžiai nesutampa!
Arba neįvesti!
'; $PALANG['pAdminCreate_admin_button'] = 'Registruoti administratorių'; $PALANG['pAdminCreate_admin_result_error'] = 'Administratoriaus užregistruoti nepavyko!'; $PALANG['pAdminCreate_admin_result_success'] = 'Administratorius užregistruotas!'; $PALANG['pAdminCreate_admin_address'] = 'Sritis'; $PALANG['pAdminEdit_admin_welcome'] = 'Registruoti srities administratorių'; $PALANG['pAdminEdit_admin_username'] = 'Administratorius'; $PALANG['pAdminEdit_admin_password'] = 'Slaptažodis'; $PALANG['pAdminEdit_admin_password2'] = 'Slaptažodis (dar kartą)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Įvesti slaptažodžiai nesutampa!
Arba neįvesti!
'; $PALANG['pAdminEdit_admin_active'] = 'Įjungta(s)'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super administratorius'; $PALANG['pAdminEdit_admin_button'] = 'Keisti administratorių'; $PALANG['pAdminEdit_admin_result_error'] = 'Administratoriaus pakeisti nepavyko!'; $PALANG['pAdminEdit_admin_result_success'] = 'Administratorius pakeistas!'; $PALANG['pUsersLogin_welcome'] = 'Pašto vartotojai prisijungia ir keičia slaptažodžius ir sinonimus.'; $PALANG['pUsersLogin_username'] = 'Vartotojas (el.paštas)'; $PALANG['pUsersLogin_password'] = 'Slaptažodis'; $PALANG['pUsersLogin_button'] = 'Prisijungti'; $PALANG['pUsersLogin_username_incorrect'] = 'Prisijungti nepavyko. Įsitikinkite, kad gerai įvedėte savo el.pašto adresą!'; $PALANG['pUsersLogin_password_incorrect'] = 'Slaptažodis neteisingas!'; $PALANG['pUsersMenu_vacation'] = 'Automatinis (atostogų) atsakymas'; $PALANG['pUsersMenu_edit_alias'] = 'Keisti laiškų peradresaciją'; $PALANG['pUsersMenu_password'] = 'Keisti slaptažodį'; $PALANG['pUsersMain_vacation'] = 'Nustatyti "Esu išvykęs" automatinį atsakymą visiems ateinantiems laiškams.'; $PALANG['pUsersMain_vacationSet'] = 'Automatinis atsakymas ĮJUNGTAS, paspauskite \'Automatinis (atostogų) atsakymas\' pakeisti ar ištrinti'; $PALANG['pUsersMain_edit_alias'] = 'Pakeisti laiškų peradresavimą.'; $PALANG['pUsersMain_password'] = 'Pakeisti slaptažodį.'; $PALANG['pUsersVacation_welcome'] = 'Automatinis (atostogų) atsakymas.'; $PALANG['pUsersVacation_welcome_text'] = 'Auto atsakiklis jau nustatytas!'; $PALANG['pUsersVacation_subject'] = 'Tema'; $PALANG['pUsersVacation_subject_text'] = 'Esu išvykęs'; $PALANG['pUsersVacation_body'] = 'Žinutė'; $PALANG['pUsersVacation_body_text'] = << iki . Esant neatidėliotiniems reikalams, kreipkitės į . I will be away from until . For urgent matters you can contact . EOM; $PALANG['pUsersVacation_button_away'] = 'Išvykstu'; $PALANG['pUsersVacation_button_back'] = 'Grįžtu'; $PALANG['pUsersVacation_result_error'] = 'Nepavyko nustatyti el.pašto auto atsakiklio!'; $PALANG['pUsersVacation_result_success'] = 'Auto atsakiklis išjungtas!'; $PALANG['pUsersVacation_activefrom'] = 'Įjungtas nuo'; $PALANG['pUsersVacation_activeuntil'] = 'Įjungtas iki'; $PALANG['pCreate_dbLog_createmailbox'] = 'pašto dėžutė sukurta'; $PALANG['pCreate_dbLog_createalias'] = 'sinonimas sukurtas'; $PALANG['pDelete_dbLog_deletealias'] = 'sinonimas pašalintas'; $PALANG['pDelete_dbLog_deletemailbox'] = 'pašto dėžutė pašalinta'; $PALANG['pEdit_dbLog_editactive'] = 'pakeista būsena'; $PALANG['pEdit_dbLog_editalias'] = 'sinonimas pakeistas'; $PALANG['pEdit_dbLog_editmailbox'] = 'pašto dėžutė pakeista'; $PALANG['pSearch'] = 'ieškoti'; $PALANG['pSearch_welcome'] = 'Ieškoti: '; $PALANG['pReturn_to'] = 'Grįžti į'; $PALANG['pBroadcast_title'] = 'Send broadcast message'; # XXX $PALANG['pBroadcast_from'] = 'From'; # XXX $PALANG['pBroadcast_name'] = 'Your name'; # XXX $PALANG['pBroadcast_subject'] = 'Subject'; # XXX $PALANG['pBroadcast_message'] = 'Message'; # XXX $PALANG['pBroadcast_send'] = 'Send message'; # XXX $PALANG['pBroadcast_success'] = 'Your broadcast message was sent.'; # XXX $PALANG['pAdminMenu_broadcast_message'] = 'Broadcast message'; # XXX $PALANG['pBroadcast_error_empty'] = 'The fields Name, Subject and Message should\'t be empty !'; # XXX $PALANG['pStatus_undeliverable'] = 'maybe UNDELIVERABLE '; # XXX $PALANG['pStatus_custom'] = 'Delivers to '; # XXX $PALANG['pStatus_popimap'] = 'POP/IMAP '; # XXX $PALANG['pPasswordTooShort'] = "Password is too short - requires %s characters"; # XXX $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Fetch mail for:'; # XXX $PALANG['pFetchmail_new_entry'] = 'New entry'; # XXX $PALANG['pFetchmail_database_save_error'] = 'Could not save this entry in the database!'; # XXX $PALANG['pFetchmail_database_save_success'] = 'Entry saved in database.'; # XXX $PALANG['pFetchmail_error_invalid_id'] = 'No entry with ID %s found!'; # XXX $PALANG['pFetchmail_invalid_mailbox'] = 'Invalid mailbox!'; # XXX $PALANG['pFetchmail_server_missing'] = 'Please enter the remote server name!'; # XXX $PALANG['pFetchmail_user_missing'] = 'Please enter the remote username!'; # XXX $PALANG['pFetchmail_password_missing'] = 'Please enter the remote password!'; # XXX $PALANG['pFetchmail_field_id'] = 'ID'; # XXX $PALANG['pFetchmail_field_mailbox'] = 'Mailbox'; # XXX $PALANG['pFetchmail_field_src_server'] = 'Server'; # XXX $PALANG['pFetchmail_field_src_auth'] = 'Auth Type'; # XXX $PALANG['pFetchmail_field_src_user'] = 'User'; # XXX $PALANG['pFetchmail_field_src_password'] = 'Password'; # XXX $PALANG['pFetchmail_field_src_folder'] = 'Folder'; # XXX $PALANG['pFetchmail_field_poll_time'] = 'Poll'; # XXX $PALANG['pFetchmail_field_fetchall'] = 'Fetch All'; # XXX $PALANG['pFetchmail_field_keep'] = 'Keep'; # XXX $PALANG['pFetchmail_field_protocol'] = 'Protocol'; # XXX $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra Options'; # XXX $PALANG['pFetchmail_field_mda'] = 'MDA'; # XXX $PALANG['pFetchmail_field_date'] = 'Date'; # XXX $PALANG['pFetchmail_field_returned_text'] = 'Returned Text'; # XXX $PALANG['pFetchmail_desc_id'] = 'Record ID'; # XXX $PALANG['pFetchmail_desc_mailbox'] = 'Local mailbox'; # XXX $PALANG['pFetchmail_desc_src_server'] = 'Remote Server'; # XXX $PALANG['pFetchmail_desc_src_auth'] = 'Mostly \'password\''; # Translators: Please do NOT translate 'password' here # XXX $PALANG['pFetchmail_desc_src_user'] = 'Remote User'; # XXX $PALANG['pFetchmail_desc_src_password'] = 'Remote Password'; # XXX $PALANG['pFetchmail_desc_src_folder'] = 'Remote Folder'; # XXX $PALANG['pFetchmail_desc_poll_time'] = 'Poll every ... minutes'; # XXX $PALANG['pFetchmail_desc_fetchall'] = 'Retrieve both old (seen) and new messages'; # XXX $PALANG['pFetchmail_desc_keep'] = 'Keep retrieved messages on the remote mailserver'; # XXX $PALANG['pFetchmail_desc_protocol'] = 'Protocol to use'; # XXX $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Extra fetchmail Options'; # XXX $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; # XXX $PALANG['pFetchmail_desc_date'] = 'Date of last polling/configuration change'; # XXX $PALANG['pFetchmail_desc_returned_text'] = 'Text message from last polling'; # XXX $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/eu.lang0000664000175000017620000006501311636730120017505 0ustar davidpalepurpleEzinezkoa sarrera ezabatzea '; $PALANG['pDelete_delete_success'] = '%s deleted.'; # XXX $PALANG['pDelete_postdelete_error'] = 'Unable to remove mailbox '; # XXX $PALANG['pDelete_domain_error'] = 'Ez zara domeinu honen jabe'; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = 'Unable to delete alias '; # XXX $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = 'Domeinuarentzat alias berri bat sortu.'; $PALANG['pCreate_alias_address'] = 'Aliasa'; $PALANG['pCreate_alias_address_text_error1'] = '
ALIASa okerra da!'; $PALANG['pCreate_alias_address_text_error2'] = '
Helbide hau existitzen da, ezberdin bat aukera ezazu mesedez!'; $PALANG['pCreate_alias_address_text_error3'] = '
Alias sortze mugara heldu zara!'; $PALANG['pCreate_alias_goto'] = 'Norakoa'; $PALANG['pCreate_alias_active'] = 'Active'; # XXX $PALANG['pCreate_alias_button'] = 'Aliasa gehitu'; $PALANG['pCreate_alias_goto_text'] = 'Nora bidali behar den e-maila.'; $PALANG['pCreate_alias_goto_text_error'] = 'Nora bidali behar den e-maila.
NORAKO okerra!'; $PALANG['pCreate_alias_result_error'] = 'Ezinezkoa aliasa alias taulan sartzea!'; $PALANG['pCreate_alias_result_success'] = 'Aliasa alias taulan gehituta!'; $PALANG['pCreate_alias_catchall_text'] = 'Alias orokor bat sortzeko "*" erabil ezazu alias gisa.
Domeinuz domeinurako birbideraketa baterako Norako gisa "*@domain.tld" erabil ezazu.'; $PALANG['pEdit_alias_welcome'] = 'Domeinuarentzat aliasa aldatu.
Lerroko sarrera bat.'; $PALANG['pEdit_alias_address'] = 'Aliasa'; $PALANG['pEdit_alias_address_error'] = 'Ezinezkoa aliasa aurkitzea!'; $PALANG['pEdit_alias_goto'] = 'Norakoa'; $PALANG['pEdit_alias_active'] = 'Active'; # XXX $PALANG['pEdit_alias_goto_text_error1'] = 'Norakoan ez duzu ezer jarri'; $PALANG['pEdit_alias_goto_text_error2'] = 'Sartutako e-mail helbidea baliiogabekoa da: '; $PALANG['pEdit_alias_domain_error'] = 'Ez zara domeinu honen jabe: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Deliver to the local mailbox.'; # XXX $PALANG['pEdit_alias_forward_only'] = 'Forward to given email addresses only.'; # XXX $PALANG['pEdit_alias_button'] = 'Aliasa aldatu'; $PALANG['pEdit_alias_result_error'] = 'Ezinezkoa aliasa aldatzea!'; $PALANG['pCreate_mailbox_welcome'] = 'Postontzi berri bat sortu domeinuarentzat.'; $PALANG['pCreate_mailbox_username'] = 'Erabiltzailea'; $PALANG['pCreate_mailbox_username_text_error1'] = '
E-maila baliogabekoa da!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
E-mail hau existitzen da. Ezberdin bat aukera ezazu, mesedez!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Postontzi sorkuntza mugara iritsi zara!'; $PALANG['pCreate_mailbox_password'] = 'Pasahitza'; $PALANG['pCreate_mailbox_password2'] = 'Pasahitza (errepikatu)'; $PALANG['pCreate_mailbox_password_text'] = 'POP3/IMAP-entzat pasahitza'; $PALANG['pCreate_mailbox_password_text_error'] = 'POP3/IMAP-entzat pasahitza
Sartutako pasahitzak ez datoz bat
edo zuriz daude!
'; $PALANG['pCreate_mailbox_name'] = 'Izena'; $PALANG['pCreate_mailbox_name_text'] = 'Izen osoa'; $PALANG['pCreate_mailbox_quota'] = 'Kuota'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Zehazturiko kuota altuegia da!'; $PALANG['pCreate_mailbox_active'] = 'Aktibatua'; $PALANG['pCreate_mailbox_mail'] = 'Postontzia sortu'; $PALANG['pCreate_mailbox_button'] = 'Postontzia gehitu'; $PALANG['pCreate_mailbox_result_error'] = 'Ezinezkoa postontzi taulara postontzia gehitzea!'; $PALANG['pCreate_mailbox_result_success'] = 'Postontzia postontzi taulara sartu da!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'The mailbox has been added to the mailbox table, but none (or only some) of the predefined sub-folders could be created'; # XXX $PALANG['pEdit_mailbox_welcome'] = 'Domeinuarentzat postontzi bat aldatu.'; $PALANG['pEdit_mailbox_username'] = 'Erabiltzailea'; $PALANG['pEdit_mailbox_username_error'] = 'Ezinezkoa postontzia aurkitzea!'; $PALANG['pEdit_mailbox_password'] = 'Pasahitz berria'; $PALANG['pEdit_mailbox_password2'] = 'Pasahitz berria (errepikatu)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Sartutako pasahitzak ez datoz bat!'; $PALANG['pEdit_mailbox_name'] = 'Izena'; $PALANG['pEdit_mailbox_name_text'] = 'Full name'; # XXX $PALANG['pEdit_mailbox_quota'] = 'Kuota'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Zehazturiko kuota altuegia da!'; $PALANG['pEdit_mailbox_domain_error'] = 'Ez zara domeinu honen jabe: '; $PALANG['pEdit_mailbox_button'] = 'Postontzia aldatu'; $PALANG['pEdit_mailbox_result_error'] = 'Ezinezkoa pasahitza aldatzea!'; $PALANG['pPassword_welcome'] = 'Login pasahitza aldatu.'; $PALANG['pPassword_admin'] = 'Login'; $PALANG['pPassword_admin_text_error'] = 'Emandako LOGINa ez dator inolako postontziekin bat!'; $PALANG['pPassword_password_current'] = 'Egungo pasahitza'; $PALANG['pPassword_password_current_text_error'] = 'Ez duzu egungo pasahitzik sartu!'; $PALANG['pPassword_password'] = 'Pasahitz berria'; $PALANG['pPassword_password2'] = 'Pasahitz berria (errepikatu)'; $PALANG['pPassword_password_text_error'] = 'Sarturiko pasahitzak ez datoz bat
edo zuriz daude!
'; $PALANG['pPassword_button'] = 'Pasahitza aldatu'; $PALANG['pPassword_result_error'] = 'Ezinezkoa pasahitza aldatzea!'; $PALANG['pPassword_result_success'] = 'Pasahitza aldatuta!'; $PALANG['pEdit_vacation_set'] = 'Change / Set away message'; # XXX $PALANG['pEdit_vacation_remove'] = 'Remove away message'; # XXX $PALANG['pVacation_result_error'] = 'Unable to update auto response settings!'; # XXX $PALANG['pVacation_result_removed'] = 'Auto response has been removed!'; # XXX $PALANG['pVacation_result_added'] = 'Auto response has been enabled!'; # XXX $PALANG['pViewlog_welcome'] = 'Honen azken 10 ekintzak ikusi '; $PALANG['pViewlog_timestamp'] = 'Data/ordua'; $PALANG['pViewlog_username'] = 'Kudeatzailea'; $PALANG['pViewlog_domain'] = 'Domeinua'; $PALANG['pViewlog_action'] = 'Ekintza'; $PALANG['pViewlog_data'] = 'Datuak'; $PALANG['pViewlog_action_create_mailbox'] = 'create mailbox'; # XXX $PALANG['pViewlog_action_delete_mailbox'] = 'delete mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox'] = 'edit mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox_state'] = 'edit mailbox active'; # XXX $PALANG['pViewlog_action_create_alias'] = 'create alias'; # XXX $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'delete alias'; # XXX $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'edit alias'; # XXX $PALANG['pViewlog_action_edit_alias_state'] = 'edit alias active'; # XXX $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'change password'; # XXX $PALANG['pViewlog_button'] = 'Joan'; $PALANG['pViewlog_result_error'] = 'Ezinezkoa logak aurkitzea!'; $PALANG['pSendmail_welcome'] = 'e-mail bat bidali.'; $PALANG['pSendmail_admin'] = 'Igorlea'; $PALANG['pSendmail_to'] = 'Norakoa'; $PALANG['pSendmail_to_text_error'] = 'Norako helbidea hutsa dago edo okerra da!'; $PALANG['pSendmail_subject'] = 'Gaia'; $PALANG['pSendmail_subject_text'] = 'Ongi etorri'; $PALANG['pSendmail_body'] = 'Gorputza'; $PALANG['pSendmail_button'] = 'Mezua bidali'; $PALANG['pSendmail_result_error'] = 'Ezinezkoa postontzia sortzea!'; # XXX text change - new: Unable to send email! $PALANG['pSendmail_result_success'] = 'Postontzia sortuta!'; # XXX text change - new: Email sent! $PALANG['pAdminMenu_list_admin'] = 'Kudeatzaile zerrenda'; $PALANG['pAdminMenu_list_domain'] = 'Domeinu zerrenda'; $PALANG['pAdminMenu_list_virtual'] = 'Helbide birtualen zerrenda'; $PALANG['pAdminMenu_viewlog'] = 'Logak ikusi'; $PALANG['pAdminMenu_backup'] = 'Segurtasun kopia'; $PALANG['pAdminMenu_create_domain_admins'] = 'Domeinu kudeatzaileak'; $PALANG['pAdminMenu_create_admin'] = 'Kudeatzaile berria'; $PALANG['pAdminMenu_create_domain'] = 'Domeinu berria'; $PALANG['pAdminMenu_create_alias'] = 'Aliasa gehitu'; $PALANG['pAdminMenu_create_mailbox'] = 'Postontzia gehitu'; $PALANG['pAdminList_admin_domain'] = 'Domeinua'; $PALANG['pAdminList_admin_username'] = 'Kudeatzailea'; $PALANG['pAdminList_admin_count'] = 'Domeinuak'; $PALANG['pAdminList_admin_modified'] = 'Azken aldaketa'; $PALANG['pAdminList_admin_active'] = 'Aktibatua'; $PALANG['pAdminList_domain_domain'] = 'Domeinua'; $PALANG['pAdminList_domain_description'] = 'Deskripzioa'; $PALANG['pAdminList_domain_aliases'] = 'Aliasa'; $PALANG['pAdminList_domain_mailboxes'] = 'Postontziak'; $PALANG['pAdminList_domain_maxquota'] = 'Gehienezko kuota (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; $PALANG['pAdminList_domain_modified'] = 'Azken aldaketa'; $PALANG['pAdminList_domain_active'] = 'Aktibatua'; $PALANG['pAdminList_virtual_button'] = 'Joan'; $PALANG['pAdminList_virtual_welcome'] = 'Laburpena '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Aliasa'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Postontziak'; $PALANG['pAdminList_virtual_alias_address'] = 'Igorlea'; $PALANG['pAdminList_virtual_alias_goto'] = 'Norakoa'; $PALANG['pAdminList_virtual_alias_modified'] = 'Azken aldaketa'; $PALANG['pAdminList_virtual_mailbox_username'] = 'E-mail'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Izena'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Kuota (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Azken aldaketa'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Aktibatua'; $PALANG['pAdminCreate_domain_welcome'] = 'Domeinu berria gehitu'; $PALANG['pAdminCreate_domain_domain'] = 'Domeinua'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Domeinua existitzen da!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'The domain is invalid!'; # XXX $PALANG['pAdminCreate_domain_description'] = 'Deskripzioa'; $PALANG['pAdminCreate_domain_aliases'] = 'Aliasa'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = desegokitu | 0 = mugagabea'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Postontziak'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = desegokitu | 0 = mugagabea'; $PALANG['pAdminCreate_domain_maxquota'] = 'Gehienezko kuota'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = desegokitu | 0 = mugagabea'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Define transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Aurremugatutako aliasa gehitu'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; # XXX $PALANG['pAdminCreate_domain_backupmx'] = 'Mail server is backup MX'; # XXX $PALANG['pAdminCreate_domain_button'] = 'Domeinua gehitu'; $PALANG['pAdminCreate_domain_result_error'] = 'Ezinezkoa domeinua gehitzea!'; $PALANG['pAdminCreate_domain_result_success'] = 'Domeinua gehituta!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Unable to remove domain!'; # XXX $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = 'Domeinu bat aldatu'; $PALANG['pAdminEdit_domain_domain'] = 'Domeinua'; $PALANG['pAdminEdit_domain_description'] = 'Deskripzioa'; $PALANG['pAdminEdit_domain_aliases'] = 'Aliasa'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = desegokitu | 0 = mugagabea'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Postontziak'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = desegokitu | 0 = mugagabea'; $PALANG['pAdminEdit_domain_maxquota'] = 'Gehienezko kuota'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = desegokitu | 0 = mugagabea'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminEdit_domain_transport_text'] = 'Define transport'; # XXX $PALANG['pAdminEdit_domain_backupmx'] = 'Mail server is backup MX'; # XXX $PALANG['pAdminEdit_domain_active'] = 'Aktibatua'; $PALANG['pAdminEdit_domain_button'] = 'Domeinua aldatu'; $PALANG['pAdminEdit_domain_result_error'] = 'Ezinezkoa domeinua aldatzea!'; $PALANG['pAdminCreate_admin_welcome'] = 'Domeinu kudeatzaile berri bat gehitu'; $PALANG['pAdminCreate_admin_username'] = 'Kudeatzailea'; $PALANG['pAdminCreate_admin_username_text'] = 'E-mail helbidea'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'E-mail helbidea
Kudeatzaile e-mailak ez du balio!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'E-mail
Kudeatzailea existitzen da edo ez du balio!'; $PALANG['pAdminCreate_admin_password'] = 'Pasahitza'; $PALANG['pAdminCreate_admin_password2'] = 'Pasahitza (errepikatu)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Sartutako pasahitzak ez datoz bat
edo zuriz daude!
'; $PALANG['pAdminCreate_admin_button'] = 'Kudeatzailea gehitu'; $PALANG['pAdminCreate_admin_result_error'] = 'Ezinezkoa kudeatzailea gehitzea!'; $PALANG['pAdminCreate_admin_result_success'] = 'Kudeatzailea gehituta1'; $PALANG['pAdminCreate_admin_address'] = 'Domeinua'; $PALANG['pAdminEdit_admin_welcome'] = 'Domeinu kudeatzaile bat aldatu'; $PALANG['pAdminEdit_admin_username'] = 'Kudeatzailea'; $PALANG['pAdminEdit_admin_password'] = 'Pasahitza'; $PALANG['pAdminEdit_admin_password2'] = 'Pasahitza (errepikatu)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Sartutako pasahitzak ez datoz bat
edo zuriz daude!
'; $PALANG['pAdminEdit_admin_active'] = 'Aktibatua'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super admin'; # XXX $PALANG['pAdminEdit_admin_button'] = 'Kudeatzailea aldatu'; $PALANG['pAdminEdit_admin_result_error'] = 'Ezinezkoa kudeatzailea aldatzea!'; $PALANG['pAdminEdit_admin_result_success'] = 'Kudeatzailea aldatu da!'; $PALANG['pUsersLogin_welcome'] = 'Erabiltzaileen logina pasahitz eta aliasa aldatzeko.'; $PALANG['pUsersLogin_username'] = 'Login (e-mail)'; $PALANG['pUsersLogin_password'] = 'Pasahitza'; $PALANG['pUsersLogin_button'] = 'Login'; $PALANG['pUsersLogin_username_incorrect'] = 'Login okerra. Ziurta zaitez posta helbidea login gisa sartu duzula!'; $PALANG['pUsersLogin_password_incorrect'] = 'Pasahitz okerra!'; $PALANG['pUsersMenu_vacation'] = 'Erantzun automatikoa'; $PALANG['pUsersMenu_edit_alias'] = 'Berbiderapen helbidea aldatu'; $PALANG['pUsersMenu_password'] = 'Pasahitza aldatu'; $PALANG['pUsersMain_vacation'] = 'Konfigura ezazu "lanetik kanpo" motako mezu bat edo erantzun automatikoa zure postarentzat.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' is ON, click \'' . $PALANG['pUsersMenu_vacation'] . '\' to ' . $PALANG['edit'] . '/remove'; # XXX $PALANG['pUsersMain_edit_alias'] = 'Alda ezazu posta helbidea.'; $PALANG['pUsersMain_password'] = 'Alda ezazu pasahitza.'; $PALANG['pUsersVacation_welcome'] = 'Erantzun automatikoa.'; $PALANG['pUsersVacation_welcome_text'] = 'Erantzun automatiko bat konfiguratuta duzu!'; $PALANG['pUsersVacation_subject'] = 'Gaia'; $PALANG['pUsersVacation_subject_text'] = 'Lanetik kanpo'; $PALANG['pUsersVacation_body'] = 'Gorputza'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = <<-tik arte kanpoan egongo naiz. Larrialdiko gaientzat, hemen kontakta dezakezu nirekin. EOM; $PALANG['pUsersVacation_button_away'] = 'Aldeginda'; $PALANG['pUsersVacation_button_back'] = 'Itzulita'; $PALANG['pUsersVacation_result_error'] = 'Ezinezkoa zure erantzun atomatikoaren konfigurazioa eguneratzea!'; $PALANG['pUsersVacation_result_success'] = 'Zure erantzun automatikoa borratu da!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'create mailbox'; # XXX $PALANG['pCreate_dbLog_createalias'] = 'create alias'; # XXX $PALANG['pDelete_dbLog_deletealias'] = 'delete alias'; # XXX $PALANG['pDelete_dbLog_deletemailbox'] = 'delete mailbox'; # XXX $PALANG['pEdit_dbLog_editactive'] = 'change active state'; # XXX $PALANG['pEdit_dbLog_editalias'] = 'edit alias'; # XXX $PALANG['pEdit_dbLog_editmailbox'] = 'edit mailbox'; # XXX $PALANG['pSearch'] = 'search'; # XXX $PALANG['pSearch_welcome'] = 'Searching for: '; # XXX $PALANG['pReturn_to'] = 'Return to'; # XXX $PALANG['pBroadcast_title'] = 'Send broadcast message'; # XXX $PALANG['pBroadcast_from'] = 'From'; # XXX $PALANG['pBroadcast_name'] = 'Your name'; # XXX $PALANG['pBroadcast_subject'] = 'Subject'; # XXX $PALANG['pBroadcast_message'] = 'Message'; # XXX $PALANG['pBroadcast_send'] = 'Send message'; # XXX $PALANG['pBroadcast_success'] = 'Your broadcast message was sent.'; # XXX $PALANG['pAdminMenu_broadcast_message'] = 'Broadcast message'; # XXX $PALANG['pBroadcast_error_empty'] = 'The fields Name, Subject and Message should\'t be empty !'; # XXX $PALANG['pStatus_undeliverable'] = 'maybe UNDELIVERABLE '; # XXX $PALANG['pStatus_custom'] = 'Delivers to '; # XXX $PALANG['pStatus_popimap'] = 'POP/IMAP '; # XXX $PALANG['pPasswordTooShort'] = "Password is too short - requires %s characters"; # XXX $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Fetch mail for:'; # XXX $PALANG['pFetchmail_new_entry'] = 'New entry'; # XXX $PALANG['pFetchmail_database_save_error'] = 'Could not save this entry in the database!'; # XXX $PALANG['pFetchmail_database_save_success'] = 'Entry saved in database.'; # XXX $PALANG['pFetchmail_error_invalid_id'] = 'No entry with ID %s found!'; # XXX $PALANG['pFetchmail_invalid_mailbox'] = 'Invalid mailbox!'; # XXX $PALANG['pFetchmail_server_missing'] = 'Please enter the remote server name!'; # XXX $PALANG['pFetchmail_user_missing'] = 'Please enter the remote username!'; # XXX $PALANG['pFetchmail_password_missing'] = 'Please enter the remote password!'; # XXX $PALANG['pFetchmail_field_id'] = 'ID'; # XXX $PALANG['pFetchmail_field_mailbox'] = 'Mailbox'; # XXX $PALANG['pFetchmail_field_src_server'] = 'Server'; # XXX $PALANG['pFetchmail_field_src_auth'] = 'Auth Type'; # XXX $PALANG['pFetchmail_field_src_user'] = 'User'; # XXX $PALANG['pFetchmail_field_src_password'] = 'Password'; # XXX $PALANG['pFetchmail_field_src_folder'] = 'Folder'; # XXX $PALANG['pFetchmail_field_poll_time'] = 'Poll'; # XXX $PALANG['pFetchmail_field_fetchall'] = 'Fetch All'; # XXX $PALANG['pFetchmail_field_keep'] = 'Keep'; # XXX $PALANG['pFetchmail_field_protocol'] = 'Protocol'; # XXX $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra Options'; # XXX $PALANG['pFetchmail_field_mda'] = 'MDA'; # XXX $PALANG['pFetchmail_field_date'] = 'Date'; # XXX $PALANG['pFetchmail_field_returned_text'] = 'Returned Text'; # XXX $PALANG['pFetchmail_desc_id'] = 'Record ID'; # XXX $PALANG['pFetchmail_desc_mailbox'] = 'Local mailbox'; # XXX $PALANG['pFetchmail_desc_src_server'] = 'Remote Server'; # XXX $PALANG['pFetchmail_desc_src_auth'] = 'Mostly \'password\''; # Translators: Please do NOT translate 'password' here # XXX $PALANG['pFetchmail_desc_src_user'] = 'Remote User'; # XXX $PALANG['pFetchmail_desc_src_password'] = 'Remote Password'; # XXX $PALANG['pFetchmail_desc_src_folder'] = 'Remote Folder'; # XXX $PALANG['pFetchmail_desc_poll_time'] = 'Poll every ... minutes'; # XXX $PALANG['pFetchmail_desc_fetchall'] = 'Retrieve both old (seen) and new messages'; # XXX $PALANG['pFetchmail_desc_keep'] = 'Keep retrieved messages on the remote mailserver'; # XXX $PALANG['pFetchmail_desc_protocol'] = 'Protocol to use'; # XXX $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Extra fetchmail Options'; # XXX $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; # XXX $PALANG['pFetchmail_desc_date'] = 'Date of last polling/configuration change'; # XXX $PALANG['pFetchmail_desc_returned_text'] = 'Text message from last polling'; # XXX $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/it.lang0000664000175000017620000006615111636730120017514 0ustar davidpalepurple // updated by Luca Accomazzi (luca chiocciola accomazzi punto it) // $PALANG['YES'] = 'SI'; $PALANG['NO'] = 'NO'; $PALANG['edit'] = 'modifica'; $PALANG['del'] = 'cancella'; $PALANG['exit'] = 'Esci'; $PALANG['cancel'] = 'Annulla'; $PALANG['save'] = 'registra'; $PALANG['confirm'] = 'Sei certo di volerlo cancellare?\n'; $PALANG['confirm_domain'] = 'Sei sicuro di voler cancellare tutti gli indirizzi di questo dominio? Questa modifica sarà permanente!\n'; $PALANG['check_update'] = 'Verifica gli aggiornamenti'; $PALANG['invalid_parameter'] = 'Parametro non valido!'; $PALANG['pFooter_logged_as'] = 'Collegato come %s'; $PALANG['pLogin_welcome'] = 'Gli amministratori di posta devono effettuare il login qui per amministrare il proprio dominio.'; $PALANG['pLogin_username'] = 'Nome utente (email)'; $PALANG['pLogin_password'] = 'Password'; $PALANG['pLogin_button'] = 'Entra'; $PALANG['pLogin_failed'] = 'Your email address or password are not correct.'; # XXX $PALANG['pLogin_login_users'] = 'Gli utenti devono cliccare qui per entrare nella propria sezione.'; $PALANG['pMenu_main'] = 'Principale'; $PALANG['pMenu_overview'] = 'Resoconto'; $PALANG['pMenu_create_alias'] = 'Aggiungi Alias'; $PALANG['pMenu_create_alias_domain'] = 'Add Alias Domain'; # XXX $PALANG['pMenu_create_mailbox'] = 'Aggiungi casella di posta'; $PALANG['pMenu_fetchmail'] = 'Ricevi Email'; $PALANG['pMenu_sendmail'] = 'Spedisci Email'; $PALANG['pMenu_password'] = 'Password'; $PALANG['pMenu_viewlog'] = 'Vedi Log'; $PALANG['pMenu_logout'] = 'Esci'; $PALANG['pMain_welcome'] = 'Benvenuti a Postfix Admin!'; $PALANG['pMain_overview'] = 'Elenco dei tuoi alias e delle caselle di posta. Puoi modificarli / aggiungerli da qui.'; $PALANG['pMain_create_alias'] = 'Crea nuovi alias per il tuo dominio.'; $PALANG['pMain_create_mailbox'] = 'Crea una nuova casella di posta per il tuo dominio.'; $PALANG['pMain_sendmail'] = 'Spedisci una email ad una delle nuove casella di posta che hai creato.'; $PALANG['pMain_password'] = 'Cambia la password per il tuo account di amministratore.'; $PALANG['pMain_viewlog'] = 'Guarda i files di log.'; $PALANG['pMain_logout'] = 'Esci dal sistema'; $PALANG['pOverview_disabled'] = 'Disabilitato'; $PALANG['pOverview_unlimited'] = 'Illimitato'; $PALANG['pOverview_title'] = ':: Domini definiti'; $PALANG['pOverview_up_arrow'] = 'Torna in cima'; $PALANG['pOverview_right_arrow'] = 'Pagina successiva'; $PALANG['pOverview_left_arrow'] = 'Pagina precedente'; $PALANG['pOverview_alias_domain_title'] = ':: Domain Aliases'; # XXX $PALANG['pOverview_alias_title'] = ':: Alias'; $PALANG['pOverview_mailbox_title'] = ':: Caselle di posta'; $PALANG['pOverview_button'] = 'Vai'; $PALANG['pOverview_welcome'] = 'Resoconto per '; $PALANG['pOverview_alias_domain_aliases'] = 'Alias Domains'; # XXX $PALANG['pOverview_alias_domain_target'] = '%s is an Alias Domain for:'; # XXX $PALANG['pOverview_alias_alias_count'] = 'Alias'; $PALANG['pOverview_alias_mailbox_count'] = 'Caselle di posta'; $PALANG['pOverview_alias_address'] = 'Da'; $PALANG['pOverview_alias_goto'] = 'a'; $PALANG['pOverview_alias_modified'] = 'Ultima modifica'; $PALANG['pOverview_alias_domain_modified'] = 'Last Modified'; # XXX $PALANG['pOverview_alias_active'] = 'Attivo'; $PALANG['pOverview_alias_domain_active'] = 'Active'; # XXX $PALANG['pOverview_alias_edit'] = 'Alias'; $PALANG['and_x_more'] = '[più %s altri...]'; $PALANG['pOverview_mailbox_username'] = 'Email'; $PALANG['pOverview_mailbox_name'] = 'Nome'; $PALANG['pOverview_mailbox_quota'] = 'Quota (MB)'; $PALANG['pOverview_mailbox_modified'] = 'Ultima modifica'; $PALANG['pOverview_mailbox_active'] = 'Attivo'; $PALANG['pOverview_vacation_edit'] = 'AUTORISPONDITORE ATTIVO'; $PALANG['pOverview_vacation_option'] = 'Attiva autorisponditore'; $PALANG['pOverview_get_domain'] = 'Dominio'; $PALANG['pOverview_get_aliases'] = 'Alias'; $PALANG['pOverview_get_alias_domains'] = 'Domain Aliases'; # XXX $PALANG['pOverview_get_mailboxes'] = 'Caselle di posta'; $PALANG['pOverview_get_quota'] = 'Quota delle caselle di posta (MB)'; $PALANG['pOverview_get_modified'] = 'Ultima modifica'; $PALANG['pDelete_delete_error'] = 'Impossibile cancellare '; $PALANG['pDelete_delete_success'] = '%s cancellati.'; $PALANG['pDelete_postdelete_error'] = 'Impossibile cancellare la casella '; $PALANG['pDelete_domain_error'] = 'Questo dominio non è tuo '; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = 'Impossibile cancellate lo alias '; $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = 'Crea un nuovo alias per il tuo dominio.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
L\' Alias non è valido!'; $PALANG['pCreate_alias_address_text_error2'] = '
Questo indirizzo di posta esiste già, per favore sceglierne uno diverso!'; $PALANG['pCreate_alias_address_text_error3'] = '
Hai raggiunto il tuo limite per creare alias!'; $PALANG['pCreate_alias_goto'] = 'A'; $PALANG['pCreate_alias_active'] = 'Attivo'; $PALANG['pCreate_alias_button'] = 'Aggiungi Alias'; $PALANG['pCreate_alias_goto_text'] = 'Dove la mail deve essere spedita.'; $PALANG['pCreate_alias_goto_text_error'] = 'Dove l\'email deve andare.
Il campo A non è valido!'; $PALANG['pCreate_alias_result_error'] = 'Non sono riuscito ad aggiungere l\'alias alla tabella degli alias!'; $PALANG['pCreate_alias_result_success'] = 'L\'alias è stato aggiunto alla tabella degli alias!'; $PALANG['pCreate_alias_catchall_text'] = 'Per creare un account universale, usare "*" come alias.
Per inoltri da dominio a dominio, usare "*@domain.tld" come campo "a".'; $PALANG['pEdit_alias_welcome'] = 'Modifica un alias per il tuo dominio.
Un indirizzo per linea.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Impossibile allocare alias!'; $PALANG['pEdit_alias_goto'] = 'A'; $PALANG['pEdit_alias_active'] = 'Attivo'; $PALANG['pEdit_alias_goto_text_error1'] = 'Non hai inserito nulla nel campo To'; $PALANG['pEdit_alias_goto_text_error2'] = 'L\'indirizzo email che hai inserito non è valido : '; $PALANG['pEdit_alias_domain_error'] = 'Questo dominio non è tuo: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Consegna anche a una casella su questo server.'; $PALANG['pEdit_alias_forward_only'] = 'Inoltra solo a un altro server.'; $PALANG['pEdit_alias_button'] = 'Modifica Alias'; $PALANG['pEdit_alias_result_error'] = 'Impossibile modificare alias!'; $PALANG['pCreate_mailbox_welcome'] = 'Crea una nuova casella di posta locale per il tuo dominio.'; $PALANG['pCreate_mailbox_username'] = 'Nome utente'; $PALANG['pCreate_mailbox_username_text_error1'] = '
L\'indirizzo EMAIL non è valido!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Questo indirizzo email esiste già, per favore scegline uno diverso!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Hai raggiunto il limite per creare caselle di posta!'; $PALANG['pCreate_mailbox_password'] = 'Password'; $PALANG['pCreate_mailbox_password2'] = 'Password (ripeti)'; $PALANG['pCreate_mailbox_password_text'] = 'Password per POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Password per POP3/IMAP
Le password che hai fornito non sono uguali!
O sono vuote!
'; $PALANG['pCreate_mailbox_name'] = 'Nome'; $PALANG['pCreate_mailbox_name_text'] = 'Nome completo'; $PALANG['pCreate_mailbox_quota'] = 'Quota'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
La quota che hai specificato è troppo alta!'; $PALANG['pCreate_mailbox_active'] = 'Attiva'; $PALANG['pCreate_mailbox_mail'] = 'Crea casella di posta'; $PALANG['pCreate_mailbox_button'] = 'Aggiungi casella di posta'; $PALANG['pCreate_mailbox_result_error'] = 'Impossibile aggiungere la casella di posta alla tabella delle caselle di posta!'; $PALANG['pCreate_mailbox_result_success'] = 'La casella di posta è stata aggiunta alla tabella!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'La casella è stata aggiunta, ma non sono riuscito ad aggiungere (tutte) le sottocartelle definite'; $PALANG['pEdit_mailbox_welcome'] = 'Modifica una casella di posta per il tuo dominio.'; $PALANG['pEdit_mailbox_username'] = 'Nome utente'; $PALANG['pEdit_mailbox_username_error'] = 'Impossibile trovare la casella di posta!'; $PALANG['pEdit_mailbox_password'] = 'Nuova Password'; $PALANG['pEdit_mailbox_password2'] = 'Nuova Password (ripeti)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Le password che hai fornito non sono uguali!'; $PALANG['pEdit_mailbox_name'] = 'Nome'; $PALANG['pEdit_mailbox_name_text'] = 'Nome e cognome'; $PALANG['pEdit_mailbox_quota'] = 'Quota'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
La quota che hai specificato è troppo alta!'; $PALANG['pEdit_mailbox_domain_error'] = 'Questo dominio non è tuo: '; $PALANG['pEdit_mailbox_button'] = 'Modifica casella di posta'; $PALANG['pEdit_mailbox_result_error'] = 'Impossibile cambiare la password!'; $PALANG['pPassword_welcome'] = 'Cambia la tua password per entrare.'; $PALANG['pPassword_admin'] = 'Nome utente'; $PALANG['pPassword_admin_text_error'] = 'Il NOME UTENTE che hai fornito non è associato a nessuna casella di posta!'; $PALANG['pPassword_password_current'] = 'Password Corrente'; $PALANG['pPassword_password_current_text_error'] = 'Non hai fornito una password corretta!'; $PALANG['pPassword_password'] = 'Nuova Password'; $PALANG['pPassword_password2'] = 'Nuova Password (ripeti)'; $PALANG['pPassword_password_text_error'] = 'Le password che hai fornito non sono uguali!
O sono vuote!
'; $PALANG['pPassword_button'] = 'Cambia Password'; $PALANG['pPassword_result_error'] = 'Impossibile cambiare password!'; $PALANG['pPassword_result_success'] = 'La tua password è stata modificata!'; $PALANG['pEdit_vacation_set'] = 'Cambia / inserisci messaggio'; $PALANG['pEdit_vacation_remove'] = 'Rimuovi messaggio'; $PALANG['pVacation_result_error'] = 'Impossibile registrare le modifiche!'; $PALANG['pVacation_result_removed'] = 'Autorisponditore disabilitato!'; $PALANG['pVacation_result_added'] = 'Autorisponditore abilitato!'; $PALANG['pViewlog_welcome'] = 'Elenca gli ultimi dieci eventi per '; $PALANG['pViewlog_timestamp'] = 'Orario'; $PALANG['pViewlog_username'] = 'Amministratore'; $PALANG['pViewlog_domain'] = 'Dominio'; $PALANG['pViewlog_action'] = 'Azione'; $PALANG['pViewlog_data'] = 'Dati'; $PALANG['pViewlog_action_create_mailbox'] = 'crea casella'; $PALANG['pViewlog_action_delete_mailbox'] = 'distruggi casella'; $PALANG['pViewlog_action_edit_mailbox'] = 'modifica casella'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'cambia stato casella'; $PALANG['pViewlog_action_create_alias'] = 'crea alias'; $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'distruggi alias'; $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'modifica alias'; $PALANG['pViewlog_action_edit_alias_state'] = 'cambia stato alias'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'cambia password'; $PALANG['pViewlog_button'] = 'Vai'; $PALANG['pViewlog_result_error'] = 'Impossibile trovare i file di log!'; $PALANG['pSendmail_welcome'] = 'Spedisci una email.'; $PALANG['pSendmail_admin'] = 'Da'; $PALANG['pSendmail_to'] = 'A'; $PALANG['pSendmail_to_text_error'] = 'Il campo "A" è vuoto o non è un indirizzo valido!'; $PALANG['pSendmail_subject'] = 'Oggetto'; $PALANG['pSendmail_subject_text'] = 'Benvenuto'; $PALANG['pSendmail_body'] = 'Corpo'; $PALANG['pSendmail_button'] = 'Spedisci messaggio'; $PALANG['pSendmail_result_error'] = 'Impossibile creare la casella di posta!'; # XXX text change - new: Unable to send email! $PALANG['pSendmail_result_success'] = 'La casella di posta è stata creata!'; # XXX text change - new: Email sent! $PALANG['pAdminMenu_list_admin'] = 'Lista degli amministratori'; $PALANG['pAdminMenu_list_domain'] = 'Lista dei domini'; $PALANG['pAdminMenu_list_virtual'] = 'Lista virtuale'; $PALANG['pAdminMenu_viewlog'] = 'Vedi Log'; $PALANG['pAdminMenu_backup'] = 'Fai Backup'; $PALANG['pAdminMenu_create_domain_admins'] = 'Amministratori del dominio'; $PALANG['pAdminMenu_create_admin'] = 'Nuovo Amministratore'; $PALANG['pAdminMenu_create_domain'] = 'Nuovo Dominio'; $PALANG['pAdminMenu_create_alias'] = 'Aggiungi Alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Aggiungi casella di posta'; $PALANG['pAdminList_admin_domain'] = 'Dominio'; $PALANG['pAdminList_admin_username'] = 'Amministratori'; $PALANG['pAdminList_admin_count'] = 'Domini'; $PALANG['pAdminList_admin_modified'] = 'Ultima modifica'; $PALANG['pAdminList_admin_active'] = 'Attivo'; $PALANG['pAdminList_domain_domain'] = 'Dominio'; $PALANG['pAdminList_domain_description'] = 'Descrizione'; $PALANG['pAdminList_domain_aliases'] = 'Alias'; $PALANG['pAdminList_domain_mailboxes'] = 'Caselle di posta'; $PALANG['pAdminList_domain_maxquota'] = 'Quota massima (MB)'; $PALANG['pAdminList_domain_transport'] = 'Trasporto'; $PALANG['pAdminList_domain_backupmx'] = 'MX secondario'; $PALANG['pAdminList_domain_modified'] = 'Ultima modifica'; $PALANG['pAdminList_domain_active'] = 'Attivo'; $PALANG['pAdminList_virtual_button'] = 'Vai'; $PALANG['pAdminList_virtual_welcome'] = 'Resoconto per '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Alias'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Caselle di posta'; $PALANG['pAdminList_virtual_alias_address'] = 'Da'; $PALANG['pAdminList_virtual_alias_goto'] = 'A'; $PALANG['pAdminList_virtual_alias_modified'] = 'Ultima modifica'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Email'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Nome'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Quota (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Ultima modifica'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Attivo'; $PALANG['pAdminCreate_domain_welcome'] = 'Aggiungi nuovo dominio'; $PALANG['pAdminCreate_domain_domain'] = 'Dominio'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Il dominio esiste già!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'Dominio non valido!'; $PALANG['pAdminCreate_domain_description'] = 'Descrizione'; $PALANG['pAdminCreate_domain_aliases'] = 'Alias'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = disabilita | 0 = illimitati'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Caselle di posta'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = disabilita | 0 = illimitate'; $PALANG['pAdminCreate_domain_maxquota'] = 'Quota Massima'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = disabilita | 0 = illimitata'; $PALANG['pAdminCreate_domain_transport'] = 'Trasporto'; $PALANG['pAdminCreate_domain_transport_text'] = 'Definisci trasporto'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Aggiungi gli alias di default'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'Questo server è un MX secondario'; $PALANG['pAdminCreate_domain_button'] = 'Aggiungi dominio'; $PALANG['pAdminCreate_domain_result_error'] = 'Impossibile aggiungere il dominio!'; $PALANG['pAdminCreate_domain_result_success'] = 'Il dominio è stato aggiunto!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Impossibile cancellare il dominio!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = 'Modifica un domain'; $PALANG['pAdminEdit_domain_domain'] = 'Dominio'; $PALANG['pAdminEdit_domain_description'] = 'Descrizione'; $PALANG['pAdminEdit_domain_aliases'] = 'Alias'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = disabilita | 0 = illimitati'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Caselle di posta'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = disabilita | 0 = illimitate'; $PALANG['pAdminEdit_domain_maxquota'] = 'Quota massima'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = disabilita | 0 = illimitato'; $PALANG['pAdminEdit_domain_transport'] = 'Trasporto'; $PALANG['pAdminEdit_domain_transport_text'] = 'Definisci il trasporto'; $PALANG['pAdminEdit_domain_backupmx'] = 'Questo server è un MX secondario'; $PALANG['pAdminEdit_domain_active'] = 'Attivo'; $PALANG['pAdminEdit_domain_button'] = 'Modifica dominio'; $PALANG['pAdminEdit_domain_result_error'] = 'Impossibile modificare il dominio!'; $PALANG['pAdminCreate_admin_welcome'] = 'Aggiungi un nuovo amministratore per il dominio'; $PALANG['pAdminCreate_admin_username'] = 'Amministratore'; $PALANG['pAdminCreate_admin_username_text'] = 'Indirizzo email'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Indirizzo Email
L\'indirizzo dell\'amministratore non è valido!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Indirizzo Email
L\'amministratore esiste di già, oppure non è valido'; $PALANG['pAdminCreate_admin_password'] = 'Password'; $PALANG['pAdminCreate_admin_password2'] = 'Password (ancora)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Le password che hai digitato non sono uguali!
Oppure sono vuote!
'; $PALANG['pAdminCreate_admin_button'] = 'Aggiungi amministratore'; $PALANG['pAdminCreate_admin_result_error'] = 'Impossibile aggiungere amministratore!'; $PALANG['pAdminCreate_admin_result_success'] = 'L\'amministratore è stato aggiunto!'; $PALANG['pAdminCreate_admin_address'] = 'Dominio'; $PALANG['pAdminEdit_admin_welcome'] = 'Modifica l\'amministratore del dominio'; $PALANG['pAdminEdit_admin_username'] = 'Amministratore'; $PALANG['pAdminEdit_admin_password'] = 'Password'; $PALANG['pAdminEdit_admin_password2'] = 'Password (ancora)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Le password che hai fornito non sono uguali!
Oppure sono vuote!
'; $PALANG['pAdminEdit_admin_active'] = 'Attivo'; $PALANG['pAdminEdit_admin_super_admin'] = 'Superutente'; $PALANG['pAdminEdit_admin_button'] = 'Modifica amministratore'; $PALANG['pAdminEdit_admin_result_error'] = 'Impossibile modificare amministratore!'; $PALANG['pAdminEdit_admin_result_success'] = 'L\'amministratore è stato modificato!'; $PALANG['pUsersLogin_welcome'] = 'Gli utenti di caselle di posta devono entrare qui per modificare le proprie opzioni.'; $PALANG['pUsersLogin_username'] = 'Nome utente (email)'; $PALANG['pUsersLogin_password'] = 'Password'; $PALANG['pUsersLogin_button'] = 'Entra'; $PALANG['pUsersLogin_username_incorrect'] = 'Il tuo nome utente non è corretto. Assicurati di avere inserito il tuo indirizzo email!'; $PALANG['pUsersLogin_password_incorrect'] = 'La tua password non è corretta!'; $PALANG['pUsersMenu_vacation'] = 'Risposta automatica'; $PALANG['pUsersMenu_edit_alias'] = 'Cambia il tuo inoltro'; $PALANG['pUsersMenu_password'] = 'Cambia password'; $PALANG['pUsersMain_vacation'] = 'Setta un messaggio di "Fuori ufficio" o un autorisponditore per la tua posta'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' è attivo, fai clic su \'' . $PALANG['pUsersMenu_vacation'] . '\' per ' . $PALANG['edit'] . '/rimuovere'; $PALANG['pUsersMain_edit_alias'] = 'Cambia le impostazioni di inoltro della tua email.'; $PALANG['pUsersMain_password'] = 'Cambia la tua password corrente.'; $PALANG['pUsersVacation_welcome'] = 'Autorisponditore.'; $PALANG['pUsersVacation_welcome_text'] = 'Hai già un autorisponditore configurato'; $PALANG['pUsersVacation_subject'] = 'Soggetto'; $PALANG['pUsersVacation_subject_text'] = 'Assente dall\'ufficio'; $PALANG['pUsersVacation_body'] = 'Corpo'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << al . Per problemi urgenti potete contattare . EOM; $PALANG['pUsersVacation_button_away'] = 'Imposta autorisponditore'; $PALANG['pUsersVacation_button_back'] = 'Rimuovi autorisponditore'; $PALANG['pUsersVacation_result_error'] = 'Impossibile registrare i valori per l\'autorisponditore!'; $PALANG['pUsersVacation_result_success'] = 'La tua risposta automatica è stata tolta!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'crea casella'; $PALANG['pCreate_dbLog_createalias'] = 'crea alias'; $PALANG['pDelete_dbLog_deletealias'] = 'distruggi alias'; $PALANG['pDelete_dbLog_deletemailbox'] = 'distruggi casella'; $PALANG['pEdit_dbLog_editactive'] = 'attiva o disattiva'; $PALANG['pEdit_dbLog_editalias'] = 'modifica alias'; $PALANG['pEdit_dbLog_editmailbox'] = 'modifica casella'; $PALANG['pSearch'] = 'cerca'; $PALANG['pSearch_welcome'] = 'Stiamo cercando: '; $PALANG['pReturn_to'] = 'Ritorna a'; $PALANG['pBroadcast_title'] = 'Invio di gruppo'; $PALANG['pBroadcast_from'] = 'Da'; $PALANG['pBroadcast_name'] = 'Il tuo nome'; $PALANG['pBroadcast_subject'] = 'Oggetto'; $PALANG['pBroadcast_message'] = 'Messaggio'; $PALANG['pBroadcast_send'] = 'Invia'; $PALANG['pBroadcast_success'] = 'Il tuo messaggio è stato inoltrato a tutto il gruppo.'; $PALANG['pAdminMenu_broadcast_message'] = 'Invio di gruppo'; $PALANG['pBroadcast_error_empty'] = 'Nome, oggetto e testo del messaggio non possono restare vuoti!'; $PALANG['pStatus_undeliverable'] = 'presumibilmente NON CONSEGNABILE '; $PALANG['pStatus_custom'] = 'In consegna a '; $PALANG['pStatus_popimap'] = 'POP/IMAP '; $PALANG['pPasswordTooShort'] = "Password troppo breve - minimo %s caratteri"; $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Ricevi posta per:'; $PALANG['pFetchmail_new_entry'] = 'Nuova voce'; $PALANG['pFetchmail_database_save_error'] = 'Impossibile registrare nel database!'; $PALANG['pFetchmail_database_save_success'] = 'Registrato nel database.'; $PALANG['pFetchmail_error_invalid_id'] = 'Impossibile trovare i dati per l\'ID %s!'; $PALANG['pFetchmail_invalid_mailbox'] = 'Casella non valida!'; $PALANG['pFetchmail_server_missing'] = 'Digita il nome del server remoto!'; $PALANG['pFetchmail_user_missing'] = 'Digita il nome dell\'utente remoto!'; $PALANG['pFetchmail_password_missing'] = 'Digita la password per il server remoto!'; $PALANG['pFetchmail_field_id'] = 'ID'; $PALANG['pFetchmail_field_mailbox'] = 'Casella'; $PALANG['pFetchmail_field_src_server'] = 'Server'; $PALANG['pFetchmail_field_src_auth'] = 'Autenticazione'; $PALANG['pFetchmail_field_src_user'] = 'Utente'; $PALANG['pFetchmail_field_src_password'] = 'Password'; $PALANG['pFetchmail_field_src_folder'] = 'Cartella'; $PALANG['pFetchmail_field_poll_time'] = 'Scansione'; $PALANG['pFetchmail_field_fetchall'] = 'Ricevi tutto'; $PALANG['pFetchmail_field_keep'] = 'Conserva'; $PALANG['pFetchmail_field_protocol'] = 'Protocollo'; $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra'; $PALANG['pFetchmail_field_mda'] = 'MDA'; $PALANG['pFetchmail_field_date'] = 'Data'; $PALANG['pFetchmail_field_returned_text'] = 'Risultato ottenuto'; $PALANG['pFetchmail_desc_id'] = 'Record ID'; $PALANG['pFetchmail_desc_mailbox'] = 'Casella locale'; $PALANG['pFetchmail_desc_src_server'] = 'Server remoto'; $PALANG['pFetchmail_desc_src_auth'] = 'Sostanzialmente \'password\''; # Translators: Please do NOT translate 'password' here $PALANG['pFetchmail_desc_src_user'] = 'Utente remoto'; $PALANG['pFetchmail_desc_src_password'] = 'Pasword remota'; $PALANG['pFetchmail_desc_src_folder'] = 'Casella remota'; $PALANG['pFetchmail_desc_poll_time'] = 'Recupera ogni ... minuti'; $PALANG['pFetchmail_desc_fetchall'] = 'Recupera anche i messaggi già letti'; $PALANG['pFetchmail_desc_keep'] = 'Conserva una copia del messaggi sul server remoto'; $PALANG['pFetchmail_desc_protocol'] = 'Protocollo da usare'; $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Opzioni extra'; $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; $PALANG['pFetchmail_desc_date'] = 'Data dell\'ultima modifica o attività'; $PALANG['pFetchmail_desc_returned_text'] = 'Risultato dell\'ultima attività'; $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/tw.lang0000664000175000017620000006343011636730120017527 0ustar davidpalepurple不能刪除本記錄'; $PALANG['pDelete_delete_success'] = '%s deleted.'; # XXX $PALANG['pDelete_postdelete_error'] = 'Unable to remove mailbox '; # XXX $PALANG['pDelete_domain_error'] = '你沒有該網域的管理權限'; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = 'Unable to delete alias '; # XXX $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = '在你的網域中新建一個別名.'; $PALANG['pCreate_alias_address'] = '別名'; $PALANG['pCreate_alias_address_text_error1'] = '
該別名非法!'; $PALANG['pCreate_alias_address_text_error2'] = '
郵件地址已經存在, 請重新選擇!'; $PALANG['pCreate_alias_address_text_error3'] = '
你的別名已經達到上限!'; $PALANG['pCreate_alias_goto'] = '轉到'; $PALANG['pCreate_alias_active'] = 'Active'; # XXX $PALANG['pCreate_alias_button'] = '新建別名'; $PALANG['pCreate_alias_goto_text'] = '郵件接收地址.'; $PALANG['pCreate_alias_goto_text_error'] = '郵件接收地址.
接收地址不正確!'; $PALANG['pCreate_alias_result_error'] = '不能將別名添加到別名表中!'; $PALANG['pCreate_alias_result_success'] = '添加別名成功!'; $PALANG['pCreate_alias_catchall_text'] = '要將所有的郵件全部轉發請使用"*"作為別名.
網域到網域的轉發請使用"*@domain.tld".'; $PALANG['pEdit_alias_welcome'] = '編輯你網域名中的別名.
每行一條記錄.'; $PALANG['pEdit_alias_address'] = '別名'; $PALANG['pEdit_alias_address_error'] = '不能定位別名!'; $PALANG['pEdit_alias_goto'] = '轉到'; $PALANG['pEdit_alias_active'] = 'Active'; # XXX $PALANG['pEdit_alias_goto_text_error1'] = '你沒有填寫收信人'; $PALANG['pEdit_alias_goto_text_error2'] = '郵件地址非法: '; $PALANG['pEdit_alias_domain_error'] = '你沒有該網域的管理權限: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Deliver to the local mailbox.'; # XXX $PALANG['pEdit_alias_forward_only'] = 'Forward to given email addresses only.'; # XXX $PALANG['pEdit_alias_button'] = '編輯別名'; $PALANG['pEdit_alias_result_error'] = '不能修改該別名!'; $PALANG['pCreate_mailbox_welcome'] = '在你的網域中新建一個本地郵箱.'; $PALANG['pCreate_mailbox_username'] = '用戶名'; $PALANG['pCreate_mailbox_username_text_error1'] = '
郵件非法!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
郵件地址已經存在,請重新選擇!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
郵箱地址已經達到上限!'; $PALANG['pCreate_mailbox_password'] = '密碼'; $PALANG['pCreate_mailbox_password2'] = '密碼 (再次輸入)'; $PALANG['pCreate_mailbox_password_text'] = 'POP3/IMAP 密碼'; $PALANG['pCreate_mailbox_password_text_error'] = 'POP3/IMAP 密碼
你輸入的密碼不相同!
或者為空!
'; $PALANG['pCreate_mailbox_name'] = '名字'; $PALANG['pCreate_mailbox_name_text'] = '全名'; $PALANG['pCreate_mailbox_quota'] = '限制'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
你輸入的容量限制超出範圍!'; $PALANG['pCreate_mailbox_active'] = '活動'; $PALANG['pCreate_mailbox_mail'] = '新建郵箱'; $PALANG['pCreate_mailbox_button'] = '增加郵箱'; $PALANG['pCreate_mailbox_result_error'] = '不能將郵箱增加到郵箱表中!'; $PALANG['pCreate_mailbox_result_success'] = '增加郵箱成功!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'The mailbox has been added to the mailbox table, but none (or only some) of the predefined sub-folders could be created'; # XXX $PALANG['pEdit_mailbox_welcome'] = '編輯你網域中的郵箱.'; $PALANG['pEdit_mailbox_username'] = '用戶名'; $PALANG['pEdit_mailbox_username_error'] = '不能定們郵箱!'; $PALANG['pEdit_mailbox_password'] = '新密碼'; $PALANG['pEdit_mailbox_password2'] = '新密碼 (驗證)'; $PALANG['pEdit_mailbox_password_text_error'] = '你輸入的兩個新密碼不相同!'; $PALANG['pEdit_mailbox_name'] = '姓名'; $PALANG['pEdit_mailbox_name_text'] = 'Full name'; # XXX $PALANG['pEdit_mailbox_quota'] = '限制'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
你輸入的容量限制超出範圍!'; $PALANG['pEdit_mailbox_domain_error'] = '你沒有該網域的管理權限: '; $PALANG['pEdit_mailbox_button'] = '編輯郵箱'; $PALANG['pEdit_mailbox_result_error'] = '不能編輯該郵箱!'; $PALANG['pPassword_welcome'] = '更改你的登錄密碼.'; $PALANG['pPassword_admin'] = '帳號'; $PALANG['pPassword_admin_text_error'] = '你所提供的登錄帳號不正確!'; $PALANG['pPassword_password_current'] = '當前密碼'; $PALANG['pPassword_password_current_text_error'] = '你沒有填寫當前密碼!'; $PALANG['pPassword_password'] = '新密碼'; $PALANG['pPassword_password2'] = '新密碼 (驗證)'; $PALANG['pPassword_password_text_error'] = '你兩次輸入的新密碼不相同!
或者為空!
'; $PALANG['pPassword_button'] = '更改密碼'; $PALANG['pPassword_result_error'] = '更改密碼失敗!'; $PALANG['pPassword_result_success'] = '更改密碼成功!'; $PALANG['pEdit_vacation_set'] = 'Change / Set away message'; # XXX $PALANG['pEdit_vacation_remove'] = 'Remove away message'; # XXX $PALANG['pVacation_result_error'] = 'Unable to update auto response settings!'; # XXX $PALANG['pVacation_result_removed'] = 'Auto response has been removed!'; # XXX $PALANG['pVacation_result_added'] = 'Auto response has been enabled!'; # XXX $PALANG['pViewlog_welcome'] = '查看最新的10項操作日誌 網域名: '; $PALANG['pViewlog_timestamp'] = '時間'; $PALANG['pViewlog_username'] = '管理員'; $PALANG['pViewlog_domain'] = '網域'; $PALANG['pViewlog_action'] = '操作'; $PALANG['pViewlog_data'] = '內容'; $PALANG['pViewlog_action_create_mailbox'] = 'create mailbox'; # XXX $PALANG['pViewlog_action_delete_mailbox'] = 'delete mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox'] = 'edit mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox_state'] = 'edit mailbox active'; # XXX $PALANG['pViewlog_action_create_alias'] = 'create alias'; # XXX $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'delete alias'; # XXX $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'edit alias'; # XXX $PALANG['pViewlog_action_edit_alias_state'] = 'edit alias active'; # XXX $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'change password'; # XXX $PALANG['pViewlog_button'] = '執行'; $PALANG['pViewlog_result_error'] = '未找到相關的日誌!'; $PALANG['pSendmail_welcome'] = '發送郵件.'; $PALANG['pSendmail_admin'] = '發件人'; $PALANG['pSendmail_to'] = '收件人'; $PALANG['pSendmail_to_text_error'] = '收件人為空或者收件人地址不正確!'; $PALANG['pSendmail_subject'] = '主題'; $PALANG['pSendmail_subject_text'] = '歡迎'; $PALANG['pSendmail_body'] = '內容'; $PALANG['pSendmail_button'] = '發送'; $PALANG['pSendmail_result_error'] = '建立郵箱失敗!'; # XXX text change - new: Unable to send email! $PALANG['pSendmail_result_success'] = '建立郵箱成功!'; # XXX text change - new: Email sent! $PALANG['pAdminMenu_list_admin'] = '管理員清單'; $PALANG['pAdminMenu_list_domain'] = '網域名清單'; $PALANG['pAdminMenu_list_virtual'] = '虛擬用戶清單'; $PALANG['pAdminMenu_viewlog'] = '查看日誌'; $PALANG['pAdminMenu_backup'] = '備份'; $PALANG['pAdminMenu_create_domain_admins'] = '網域管理員'; $PALANG['pAdminMenu_create_admin'] = '新建管理員'; $PALANG['pAdminMenu_create_domain'] = '新建網域'; $PALANG['pAdminMenu_create_alias'] = '新建別名'; $PALANG['pAdminMenu_create_mailbox'] = '新建郵箱'; $PALANG['pAdminList_admin_domain'] = '網域'; $PALANG['pAdminList_admin_username'] = '管理員'; $PALANG['pAdminList_admin_count'] = '管理網域數量'; $PALANG['pAdminList_admin_modified'] = '最後修改日期'; $PALANG['pAdminList_admin_active'] = '活動'; $PALANG['pAdminList_domain_domain'] = '網域'; $PALANG['pAdminList_domain_description'] = '描述'; $PALANG['pAdminList_domain_aliases'] = '別名數'; $PALANG['pAdminList_domain_mailboxes'] = '郵箱數'; $PALANG['pAdminList_domain_maxquota'] = '最大容量限制 (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; # XXX $PALANG['pAdminList_domain_modified'] = '最後修改日期'; $PALANG['pAdminList_domain_active'] = '活動'; $PALANG['pAdminList_virtual_button'] = '執行'; $PALANG['pAdminList_virtual_welcome'] = '網域概覽 網域名: '; $PALANG['pAdminList_virtual_alias_alias_count'] = '別名數量'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = '郵箱數'; $PALANG['pAdminList_virtual_alias_address'] = '前往'; $PALANG['pAdminList_virtual_alias_goto'] = '轉到'; $PALANG['pAdminList_virtual_alias_modified'] = '最後修改日期'; $PALANG['pAdminList_virtual_mailbox_username'] = '郵箱'; $PALANG['pAdminList_virtual_mailbox_name'] = '姓名'; $PALANG['pAdminList_virtual_mailbox_quota'] = '限制 (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = '最後修改日期'; $PALANG['pAdminList_virtual_mailbox_active'] = '活動'; $PALANG['pAdminCreate_domain_welcome'] = '新建網域'; $PALANG['pAdminCreate_domain_domain'] = '網域名'; $PALANG['pAdminCreate_domain_domain_text_error'] = '該網域已經存在!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'The domain is invalid!'; # XXX $PALANG['pAdminCreate_domain_description'] = '描述'; $PALANG['pAdminCreate_domain_aliases'] = '別名數'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = 禁用 | 0 = 無限制'; $PALANG['pAdminCreate_domain_mailboxes'] = '郵箱數'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = 禁用 | 0 = 無限制'; $PALANG['pAdminCreate_domain_maxquota'] = '最大容量限制'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = 禁用 | 0 = 無限制'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Define transport'; # XXX $PALANG['pAdminCreate_domain_defaultaliases'] = '增加默認別名'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; # XXX $PALANG['pAdminCreate_domain_backupmx'] = '備份郵件服務器'; $PALANG['pAdminCreate_domain_button'] = '新增'; $PALANG['pAdminCreate_domain_result_error'] = '新增網域失敗!'; $PALANG['pAdminCreate_domain_result_success'] = '新增網域成功!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Unable to remove domain!'; # XXX $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = '修改網域'; $PALANG['pAdminEdit_domain_domain'] = '網域名'; $PALANG['pAdminEdit_domain_description'] = '描述'; $PALANG['pAdminEdit_domain_aliases'] = '別名數'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = 禁止 | 0 = 無限制'; $PALANG['pAdminEdit_domain_mailboxes'] = '郵箱數'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = 禁止 | 0 = 無限制'; $PALANG['pAdminEdit_domain_maxquota'] = '最大容量限制'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = 禁止 | 0 = 無限制'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminEdit_domain_transport_text'] = 'Define transport'; # XXX $PALANG['pAdminEdit_domain_backupmx'] = '備份郵件服務器'; $PALANG['pAdminEdit_domain_active'] = '活動'; $PALANG['pAdminEdit_domain_button'] = '修改'; $PALANG['pAdminEdit_domain_result_error'] = '修改網域失敗!'; $PALANG['pAdminCreate_admin_welcome'] = '新增網域管理員'; $PALANG['pAdminCreate_admin_username'] = '管理員'; $PALANG['pAdminCreate_admin_username_text'] = '郵件地址'; $PALANG['pAdminCreate_admin_username_text_error1'] = '郵件地址
管理員名不是一個合法的郵件地址!'; $PALANG['pAdminCreate_admin_username_text_error2'] = '郵件地址
管理員已經存在或者管理員名非法!'; $PALANG['pAdminCreate_admin_password'] = '密碼'; $PALANG['pAdminCreate_admin_password2'] = '密碼 (驗證)'; $PALANG['pAdminCreate_admin_password_text_error'] = '新所輸入的兩次新密碼不相同!
或者為空!
'; $PALANG['pAdminCreate_admin_button'] = '新增'; $PALANG['pAdminCreate_admin_result_error'] = '新增管理員失敗!'; $PALANG['pAdminCreate_admin_result_success'] = '新增管理員成功!'; $PALANG['pAdminCreate_admin_address'] = '網域'; $PALANG['pAdminEdit_admin_welcome'] = '修改網域管理員'; $PALANG['pAdminEdit_admin_username'] = '管理員'; $PALANG['pAdminEdit_admin_password'] = '密碼'; $PALANG['pAdminEdit_admin_password2'] = '密碼 (驗證)'; $PALANG['pAdminEdit_admin_password_text_error'] = '你兩次輸入的新密碼不相同!
或者為空!
'; $PALANG['pAdminEdit_admin_active'] = '活動'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super admin'; # XXX $PALANG['pAdminEdit_admin_button'] = '修改'; $PALANG['pAdminEdit_admin_result_error'] = '編輯網域管理員失敗!'; $PALANG['pAdminEdit_admin_result_success'] = '編輯網域管理員成功!'; $PALANG['pUsersLogin_welcome'] = '郵件用戶從這裡登錄管理你的密碼和別名.'; $PALANG['pUsersLogin_username'] = '帳號 (郵箱地址)'; $PALANG['pUsersLogin_password'] = '密碼'; $PALANG['pUsersLogin_button'] = '登錄'; $PALANG['pUsersLogin_username_incorrect'] = '登錄失敗. 請確認你是使用你的郵箱地址登錄!'; $PALANG['pUsersLogin_password_incorrect'] = '登錄密碼不正確!'; $PALANG['pUsersMenu_vacation'] = '自動回復'; $PALANG['pUsersMenu_edit_alias'] = '修改轉發'; $PALANG['pUsersMenu_password'] = '修改密碼'; $PALANG['pUsersMain_vacation'] = '設置外出信息或自動回復.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' is ON, click \'' . $PALANG['pUsersMenu_vacation'] . '\' to ' . $PALANG['edit'] . '/remove'; # XXX $PALANG['pUsersMain_edit_alias'] = '修改郵箱轉發.'; $PALANG['pUsersMain_password'] = '修改當前密碼.'; $PALANG['pUsersVacation_welcome'] = '自動回復.'; $PALANG['pUsersVacation_welcome_text'] = '你已經設置了自動回復!'; $PALANG['pUsersVacation_subject'] = '主題'; $PALANG['pUsersVacation_subject_text'] = '我現在無法回信'; $PALANG['pUsersVacation_body'] = '內容'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << 這段時間內暫時無法回信. 如果你有急事請與 聯繫. EOM; $PALANG['pUsersVacation_button_away'] = '開啟自動回復'; $PALANG['pUsersVacation_button_back'] = '關閉自動回復'; $PALANG['pUsersVacation_result_error'] = '更新自動回復失敗!'; $PALANG['pUsersVacation_result_success'] = '你的自動回復已經關閉!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = '新建郵箱'; $PALANG['pCreate_dbLog_createalias'] = '新建別名'; $PALANG['pDelete_dbLog_deletealias'] = '刪除別名'; $PALANG['pDelete_dbLog_deletemailbox'] = '郵件郵箱'; $PALANG['pEdit_dbLog_editactive'] = '改變活動狀態'; $PALANG['pEdit_dbLog_editalias'] = '編輯別名'; $PALANG['pEdit_dbLog_editmailbox'] = '編輯郵箱'; $PALANG['pSearch'] = 'search'; # XXX $PALANG['pSearch_welcome'] = '搜索: '; $PALANG['pReturn_to'] = 'Return to'; # XXX $PALANG['pBroadcast_title'] = 'Send broadcast message'; # XXX $PALANG['pBroadcast_from'] = 'From'; # XXX $PALANG['pBroadcast_name'] = 'Your name'; # XXX $PALANG['pBroadcast_subject'] = 'Subject'; # XXX $PALANG['pBroadcast_message'] = 'Message'; # XXX $PALANG['pBroadcast_send'] = 'Send message'; # XXX $PALANG['pBroadcast_success'] = 'Your broadcast message was sent.'; # XXX $PALANG['pAdminMenu_broadcast_message'] = 'Broadcast message'; # XXX $PALANG['pBroadcast_error_empty'] = 'The fields Name, Subject and Message should\'t be empty !'; # XXX $PALANG['pStatus_undeliverable'] = 'maybe UNDELIVERABLE '; # XXX $PALANG['pStatus_custom'] = 'Delivers to '; # XXX $PALANG['pStatus_popimap'] = 'POP/IMAP '; # XXX $PALANG['pPasswordTooShort'] = "Password is too short - requires %s characters"; # XXX $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Fetch mail for:'; # XXX $PALANG['pFetchmail_new_entry'] = 'New entry'; # XXX $PALANG['pFetchmail_database_save_error'] = 'Could not save this entry in the database!'; # XXX $PALANG['pFetchmail_database_save_success'] = 'Entry saved in database.'; # XXX $PALANG['pFetchmail_error_invalid_id'] = 'No entry with ID %s found!'; # XXX $PALANG['pFetchmail_invalid_mailbox'] = 'Invalid mailbox!'; # XXX $PALANG['pFetchmail_server_missing'] = 'Please enter the remote server name!'; # XXX $PALANG['pFetchmail_user_missing'] = 'Please enter the remote username!'; # XXX $PALANG['pFetchmail_password_missing'] = 'Please enter the remote password!'; # XXX $PALANG['pFetchmail_field_id'] = 'ID'; # XXX $PALANG['pFetchmail_field_mailbox'] = 'Mailbox'; # XXX $PALANG['pFetchmail_field_src_server'] = 'Server'; # XXX $PALANG['pFetchmail_field_src_auth'] = 'Auth Type'; # XXX $PALANG['pFetchmail_field_src_user'] = 'User'; # XXX $PALANG['pFetchmail_field_src_password'] = 'Password'; # XXX $PALANG['pFetchmail_field_src_folder'] = 'Folder'; # XXX $PALANG['pFetchmail_field_poll_time'] = 'Poll'; # XXX $PALANG['pFetchmail_field_fetchall'] = 'Fetch All'; # XXX $PALANG['pFetchmail_field_keep'] = 'Keep'; # XXX $PALANG['pFetchmail_field_protocol'] = 'Protocol'; # XXX $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra Options'; # XXX $PALANG['pFetchmail_field_mda'] = 'MDA'; # XXX $PALANG['pFetchmail_field_date'] = 'Date'; # XXX $PALANG['pFetchmail_field_returned_text'] = 'Returned Text'; # XXX $PALANG['pFetchmail_desc_id'] = 'Record ID'; # XXX $PALANG['pFetchmail_desc_mailbox'] = 'Local mailbox'; # XXX $PALANG['pFetchmail_desc_src_server'] = 'Remote Server'; # XXX $PALANG['pFetchmail_desc_src_auth'] = 'Mostly \'password\''; # Translators: Please do NOT translate 'password' here # XXX $PALANG['pFetchmail_desc_src_user'] = 'Remote User'; # XXX $PALANG['pFetchmail_desc_src_password'] = 'Remote Password'; # XXX $PALANG['pFetchmail_desc_src_folder'] = 'Remote Folder'; # XXX $PALANG['pFetchmail_desc_poll_time'] = 'Poll every ... minutes'; # XXX $PALANG['pFetchmail_desc_fetchall'] = 'Retrieve both old (seen) and new messages'; # XXX $PALANG['pFetchmail_desc_keep'] = 'Keep retrieved messages on the remote mailserver'; # XXX $PALANG['pFetchmail_desc_protocol'] = 'Protocol to use'; # XXX $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Extra fetchmail Options'; # XXX $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; # XXX $PALANG['pFetchmail_desc_date'] = 'Date of last polling/configuration change'; # XXX $PALANG['pFetchmail_desc_returned_text'] = 'Text message from last polling'; # XXX $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/hu.lang0000664000175000017620000006673711636730120017526 0ustar davidpalepurple and Levente Farkas // $PALANG['YES'] = 'IGEN'; $PALANG['NO'] = 'NEM'; $PALANG['edit'] = 'szerkeszt'; $PALANG['del'] = 'töröl'; $PALANG['exit'] = 'Kilép'; $PALANG['cancel'] = 'Cancel'; # XXX $PALANG['save'] = 'Save'; # XXX $PALANG['confirm'] = 'Biztos vagy benne hogy törlöd ezt?\n'; $PALANG['confirm_domain'] = 'Biztos hogy törölni akarod az összes bejegyzést ez alól a domain alól? Nem lehet visszahozni késõbb!\n'; $PALANG['check_update'] = 'Check for update'; # XXX $PALANG['invalid_parameter'] = 'Invalid parameter!'; # XXX $PALANG['pFooter_logged_as'] = '%s-ként bejelentkezve'; $PALANG['pLogin_welcome'] = 'Mail adminisztrátorok itt jelentkezzenek be, hogy adminisztrálják a domainjüket.'; $PALANG['pLogin_username'] = 'Bejelentkezés (email)'; $PALANG['pLogin_password'] = 'Jelszó'; $PALANG['pLogin_button'] = 'Bejelentkezés'; $PALANG['pLogin_failed'] = 'Your email address or password are not correct.'; # XXX $PALANG['pLogin_login_users'] = 'A felhasználók kattintsanak ide a felhasználói felülethez.'; $PALANG['pMenu_main'] = 'Főmenü'; $PALANG['pMenu_overview'] = 'Áttekintés'; $PALANG['pMenu_create_alias'] = 'Alias felvétele'; $PALANG['pMenu_create_alias_domain'] = 'Add Alias Domain'; # XXX $PALANG['pMenu_create_mailbox'] = 'Felhasználó felvétele'; $PALANG['pMenu_fetchmail'] = 'Email lehozása'; $PALANG['pMenu_sendmail'] = 'Email küldése'; $PALANG['pMenu_password'] = 'Jelszó'; $PALANG['pMenu_viewlog'] = 'Napló megtekintése'; $PALANG['pMenu_logout'] = 'Kilépés'; $PALANG['pMain_welcome'] = 'Üdvözöllek a Postfix Adminisztrációs rendszerben!'; $PALANG['pMain_overview'] = 'Listázd az alias-okat és a postafiókokat. Innen tudod õket törölni / módosítani.'; $PALANG['pMain_create_alias'] = 'Új alias készítése az adott domainhez.'; $PALANG['pMain_create_mailbox'] = 'Új felhasználó felvétele az adott domainhez.'; $PALANG['pMain_sendmail'] = 'Küldjön a rendszer emailt minden egyes új felhasználónak.'; $PALANG['pMain_password'] = 'Admin jelszó megváltoztatása.'; $PALANG['pMain_viewlog'] = 'Naplófájlok megtekintése.'; $PALANG['pMain_logout'] = 'Kijelentkezés a rendszerbõl'; $PALANG['pOverview_disabled'] = 'Letiltva'; $PALANG['pOverview_unlimited'] = 'Korlátlan'; $PALANG['pOverview_title'] = ':: Definiált Domain-ok'; $PALANG['pOverview_up_arrow'] = 'Vissza a tetejére'; $PALANG['pOverview_right_arrow'] = 'Következő oldal'; $PALANG['pOverview_left_arrow'] = 'Előző oldal'; $PALANG['pOverview_alias_domain_title'] = ':: Domain Aliases'; # XXX $PALANG['pOverview_alias_title'] = ':: Alias'; $PALANG['pOverview_mailbox_title'] = ':: Mailbox-ok'; $PALANG['pOverview_button'] = 'Gyerünk'; $PALANG['pOverview_welcome'] = 'Áttekintés: '; $PALANG['pOverview_alias_domain_aliases'] = 'Alias Domains'; # XXX $PALANG['pOverview_alias_domain_target'] = '%s is an Alias Domain for:'; # XXX $PALANG['pOverview_alias_alias_count'] = 'Alias-ok'; $PALANG['pOverview_alias_mailbox_count'] = 'Postafiókok'; $PALANG['pOverview_alias_address'] = 'Honnan'; $PALANG['pOverview_alias_goto'] = 'Hova'; $PALANG['pOverview_alias_modified'] = 'Utolsó módosítás'; $PALANG['pOverview_alias_domain_modified'] = 'Last Modified'; # XXX $PALANG['pOverview_alias_active'] = 'Aktív'; $PALANG['pOverview_alias_domain_active'] = 'Active'; # XXX $PALANG['pOverview_alias_edit'] = 'Alias'; $PALANG['and_x_more'] = '[and %s more...]'; # XXX $PALANG['pOverview_mailbox_username'] = 'Email'; $PALANG['pOverview_mailbox_name'] = 'Név'; $PALANG['pOverview_mailbox_quota'] = 'Quota (MB)'; $PALANG['pOverview_mailbox_modified'] = 'Utolsó módosítás'; $PALANG['pOverview_mailbox_active'] = 'Aktív'; $PALANG['pOverview_vacation_edit'] = 'SZABADSÁG EKKOR'; $PALANG['pOverview_vacation_option'] = 'Szabadság beállítása'; $PALANG['pOverview_get_domain'] = 'Domain'; $PALANG['pOverview_get_aliases'] = 'Alias-ok'; $PALANG['pOverview_get_alias_domains'] = 'Domain Aliases'; # XXX $PALANG['pOverview_get_mailboxes'] = 'Postafiókok'; $PALANG['pOverview_get_quota'] = 'Postafiók Quota (MB)'; $PALANG['pOverview_get_modified'] = 'Utolsó módosítás'; $PALANG['pDelete_delete_error'] = 'Nem sikerült törölni a bejegyzést '; $PALANG['pDelete_delete_success'] = '%s deleted.'; # XXX $PALANG['pDelete_postdelete_error'] = 'Nem sikerült törölni a mailbox-ot '; $PALANG['pDelete_domain_error'] = 'Ehhez a domainhez nincs jogosultságod '; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = 'Nem sikerült törölni az alias-t '; $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = 'Új alias készítése az adott domainhez'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
Az ALIAS érvénytelen!'; $PALANG['pCreate_alias_address_text_error2'] = '
Ez az email cím már létezik, kérlek válassz másikat!'; $PALANG['pCreate_alias_address_text_error3'] = '
Elérted a maximális alias limitet!'; $PALANG['pCreate_alias_goto'] = 'Hova'; $PALANG['pCreate_alias_active'] = 'Aktív'; $PALANG['pCreate_alias_button'] = 'Alias felvétele'; $PALANG['pCreate_alias_goto_text'] = 'Ahova a levélnek mennie kell.'; $PALANG['pCreate_alias_goto_text_error'] = 'Ahova a levélnek mennie kell.
Érvénytelen a HOVA mezõ!'; $PALANG['pCreate_alias_result_error'] = 'Nemsikerült hozzáadni az aliast az alias táblához!'; $PALANG['pCreate_alias_result_success'] = 'Az aliast felvettük az alias táblába!'; $PALANG['pCreate_alias_catchall_text'] = 'A catch-all (*@valami.hu) beállításához használj "*" -ot az alias mezõnél.
A domain-domain közötti átirányításhoz használd a "*@akarmi.hu" címet.'; $PALANG['pEdit_alias_welcome'] = 'Alias szerkesztése a domainhez.
Soronként egy.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Nemsikerült megtalálni az aliast!'; $PALANG['pEdit_alias_goto'] = 'Hova'; $PALANG['pEdit_alias_active'] = 'Aktív'; $PALANG['pEdit_alias_goto_text_error1'] = 'Nem írtál semmit a \'Hova\' mezõbe'; $PALANG['pEdit_alias_goto_text_error2'] = 'Az email cím amit beírtál érvénytelen: '; $PALANG['pEdit_alias_domain_error'] = 'Ehhez a domainhez nincs jogosultságod: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Kézbesítés helyi mailbox-ba.'; $PALANG['pEdit_alias_forward_only'] = 'Továbbítás csak az adott email címre.'; $PALANG['pEdit_alias_button'] = 'Alias szerkesztése'; $PALANG['pEdit_alias_result_error'] = 'Nemsikerült módosítani az Aliast!'; $PALANG['pCreate_mailbox_welcome'] = 'Új postafiók létrehozása az adott domainhez.'; $PALANG['pCreate_mailbox_username'] = 'Felhasználónév'; $PALANG['pCreate_mailbox_username_text_error1'] = '
Érvénytelen EMAIL !'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Ez az email cím már létezik, kérlek válassz másikat!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Elérted a maximális postafiók számot!'; $PALANG['pCreate_mailbox_password'] = 'Jelszó'; $PALANG['pCreate_mailbox_password2'] = 'Jelszó (mégegyszer)'; $PALANG['pCreate_mailbox_password_text'] = 'Jelszó a POP3/IMAP -hoz'; $PALANG['pCreate_mailbox_password_text_error'] = 'Jelszó a POP3/IMAP -hoz
A jelszavak amiket megadtál nem egyeznek!
Vagy üresek!
'; $PALANG['pCreate_mailbox_name'] = 'Név'; $PALANG['pCreate_mailbox_name_text'] = 'Teljes név'; $PALANG['pCreate_mailbox_quota'] = 'Quota'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Túl magas quota értéket adtál meg!'; $PALANG['pCreate_mailbox_active'] = 'Aktív'; $PALANG['pCreate_mailbox_mail'] = 'Postafiók létrehozása'; $PALANG['pCreate_mailbox_button'] = 'Postafiók létrehozása'; $PALANG['pCreate_mailbox_result_error'] = 'Nemsikerült a postafiókot felvenni a mailbox adatbázis táblába!'; $PALANG['pCreate_mailbox_result_success'] = 'A postafiókot sikeresen felvettük a mailbox adatbázis táblába!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'A postafiókot hozzáadtuk a postafiók táblához, de egyik előre definiált alkönyvtárat sem tudtuk létrehozni (vagy csak néhányat)'; $PALANG['pEdit_mailbox_welcome'] = 'Postafiók szerkesztése az adott domainhez.'; $PALANG['pEdit_mailbox_username'] = 'Felhasználónév'; $PALANG['pEdit_mailbox_username_error'] = 'Nem sikerült megtalálni a postafiókot!'; $PALANG['pEdit_mailbox_password'] = 'Új jelszó'; $PALANG['pEdit_mailbox_password2'] = 'Új jelszó (mégegyszer)'; $PALANG['pEdit_mailbox_password_text_error'] = 'A beírt jelszavak nem egyeznek!'; $PALANG['pEdit_mailbox_name'] = 'Név'; $PALANG['pEdit_mailbox_name_text'] = 'Teljes név'; $PALANG['pEdit_mailbox_quota'] = 'Quota'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
A megadott quota érték túl magas!'; $PALANG['pEdit_mailbox_domain_error'] = 'Ehhez a domainhez nincs jogosultságod: '; $PALANG['pEdit_mailbox_button'] = 'Postafiók szerkesztése'; $PALANG['pEdit_mailbox_result_error'] = 'Nemsikerült megváltoztatni a jelszót!'; $PALANG['pPassword_welcome'] = 'Bejelentkezési jelszó megváltoztatása'; $PALANG['pPassword_admin'] = 'Bejelentkezés'; $PALANG['pPassword_admin_text_error'] = 'A felhasználónév amit megadtál egyetlen postafiókkal sem egyezik!'; $PALANG['pPassword_password_current'] = 'Régi jelszó'; $PALANG['pPassword_password_current_text_error'] = 'Nem adtad meg a régi jelszavadat!'; $PALANG['pPassword_password'] = 'Új jelszó'; $PALANG['pPassword_password2'] = 'Új jelszó (mégegyszer)'; $PALANG['pPassword_password_text_error'] = 'A jelszavak amiket megadtál nem egyeznek!
Vagy üresek!
'; $PALANG['pPassword_button'] = 'Jelszó megváltoztatása'; $PALANG['pPassword_result_error'] = 'Nemsikerült megváltoztatni a jelszavad!'; $PALANG['pPassword_result_success'] = 'A jelszavad megváltozott!'; $PALANG['pEdit_vacation_set'] = 'Nem vagyok elérhatő üzenet módosítás / beállítás'; $PALANG['pEdit_vacation_remove'] = 'Nem vagyok elérhatő üzenet törlése'; $PALANG['pVacation_result_error'] = 'Nem sikerült frissíteni az automatikus válasz beállításait!'; $PALANG['pVacation_result_removed'] = 'Az automatikus válasz törölve!'; $PALANG['pVacation_result_added'] = 'Az automatikus válasz engedélyezve!'; $PALANG['pViewlog_welcome'] = 'Az utolsó 10 esemény megtekintése: '; $PALANG['pViewlog_timestamp'] = 'Idõbélyeg'; $PALANG['pViewlog_username'] = 'Admin'; $PALANG['pViewlog_domain'] = 'Domain'; $PALANG['pViewlog_action'] = 'Akció'; $PALANG['pViewlog_data'] = 'Adat'; $PALANG['pViewlog_action_create_mailbox'] = 'postafiók létrehozása'; $PALANG['pViewlog_action_delete_mailbox'] = 'postafiók törlése'; $PALANG['pViewlog_action_edit_mailbox'] = 'postafiók módosítása'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'postafiók aktivitás módosítása'; $PALANG['pViewlog_action_create_alias'] = 'alias létrehozása'; $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'alias törlése'; $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'alias módosítása'; $PALANG['pViewlog_action_edit_alias_state'] = 'alias aktivitás módosítása'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'jelszó módosítása'; $PALANG['pViewlog_button'] = 'Gyerünk'; $PALANG['pViewlog_result_error'] = 'Nemsikerült megtalálni a napló fájlokat!'; $PALANG['pSendmail_welcome'] = 'Email küldése.'; $PALANG['pSendmail_admin'] = 'Feladó'; $PALANG['pSendmail_to'] = 'Címzett'; $PALANG['pSendmail_to_text_error'] = 'Ez egy üres, vagy nem megfelelõ email cím!'; $PALANG['pSendmail_subject'] = 'Tárgy'; $PALANG['pSendmail_subject_text'] = 'Postafiókja sikeresen elkészült!'; $PALANG['pSendmail_body'] = 'Üzenet'; $PALANG['pSendmail_button'] = 'Üzenet küldése'; $PALANG['pSendmail_result_error'] = 'Postafiók létrehozása sikertelen!'; # XXX text change - new: Unable to send email! $PALANG['pSendmail_result_success'] = 'A postafiók sikeresen elkészült!'; # XXX text change - new: Email sent! $PALANG['pAdminMenu_list_admin'] = 'Admin Lista'; $PALANG['pAdminMenu_list_domain'] = 'Domain Lista'; $PALANG['pAdminMenu_list_virtual'] = 'Postafiók Lista'; $PALANG['pAdminMenu_viewlog'] = 'Napló'; $PALANG['pAdminMenu_backup'] = 'Adatbázis mentés'; $PALANG['pAdminMenu_create_domain_admins'] = 'Domain Adminok'; $PALANG['pAdminMenu_create_admin'] = 'Új Admin'; $PALANG['pAdminMenu_create_domain'] = 'Új Domain'; $PALANG['pAdminMenu_create_alias'] = 'Új Alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Új Postafiók'; $PALANG['pAdminList_admin_domain'] = 'Domain'; $PALANG['pAdminList_admin_username'] = 'Admin'; $PALANG['pAdminList_admin_count'] = 'Domain-ek'; $PALANG['pAdminList_admin_modified'] = 'Utolsó módosítás'; $PALANG['pAdminList_admin_active'] = 'Aktív'; $PALANG['pAdminList_domain_domain'] = 'Domain'; $PALANG['pAdminList_domain_description'] = 'Leírás'; $PALANG['pAdminList_domain_aliases'] = 'Alias-ok'; $PALANG['pAdminList_domain_mailboxes'] = 'Postafiókok'; $PALANG['pAdminList_domain_maxquota'] = 'Max Quota (MB)'; # XXX $PALANG['pAdminList_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; # XXX $PALANG['pAdminList_domain_modified'] = 'Utolsó módosítás'; $PALANG['pAdminList_domain_active'] = 'Aktív'; $PALANG['pAdminList_virtual_button'] = 'Tovább'; $PALANG['pAdminList_virtual_welcome'] = 'Áttekintés: '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Alias-ok'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Postafiókok'; $PALANG['pAdminList_virtual_alias_address'] = 'Honnan'; $PALANG['pAdminList_virtual_alias_goto'] = 'Hova'; $PALANG['pAdminList_virtual_alias_modified'] = 'Utolsó módosítás'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Email'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Név'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Quota (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Utolsó módosítás'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Aktív'; $PALANG['pAdminCreate_domain_welcome'] = 'Új domain felvétele'; $PALANG['pAdminCreate_domain_domain'] = 'Domain'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'A domain már létezik!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'A domain érvénytelen!'; $PALANG['pAdminCreate_domain_description'] = 'Leírás'; $PALANG['pAdminCreate_domain_aliases'] = 'Alias-ok'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = kikapcsol | 0 = végtelen'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Postafiókok'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = kikapcsol | 0 = végtelen'; $PALANG['pAdminCreate_domain_maxquota'] = 'Max Quota'; # XXX $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = kikapcsol | 0 = végtelen'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Transport definiálása'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Alapértelmezett alias-ok hozzáadása'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'A mail szerver egy backup MX'; $PALANG['pAdminCreate_domain_button'] = 'Domain felvétele'; $PALANG['pAdminCreate_domain_result_error'] = 'A domain felvétele sikertelen!'; $PALANG['pAdminCreate_domain_result_success'] = 'A domain-t felvettük az adatbázisba!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'A domain törlése nem sikerült!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = 'Domain szerkesztése'; $PALANG['pAdminEdit_domain_domain'] = 'Domain'; $PALANG['pAdminEdit_domain_description'] = 'Leírás'; $PALANG['pAdminEdit_domain_aliases'] = 'Alias-ok'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = kikapcsol | 0 = végtelen'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Postafiókok'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = kikapcsol | 0 = végtelen'; $PALANG['pAdminEdit_domain_maxquota'] = 'Max Quota'; # XXX $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = kikapcsol | 0 = végtelen'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Transport definiálása'; $PALANG['pAdminEdit_domain_backupmx'] = 'A mail szerver egy backup MX'; $PALANG['pAdminEdit_domain_active'] = 'Aktív'; $PALANG['pAdminEdit_domain_button'] = 'Domain szerkesztése'; $PALANG['pAdminEdit_domain_result_error'] = 'A domain módosítása sikertelen!'; $PALANG['pAdminCreate_admin_welcome'] = 'Új domain admin felvétele'; $PALANG['pAdminCreate_admin_username'] = 'Admin'; $PALANG['pAdminCreate_admin_username_text'] = 'Email cím'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Email cím
Az Admin nem valós email cím!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Email cím
Az Admin már létezik, vagy nem valós a cím!'; $PALANG['pAdminCreate_admin_password'] = 'Jelszó'; $PALANG['pAdminCreate_admin_password2'] = 'Jelszó (mégegyszer)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'A beírt jelszavak nem egyeznek!
Vagy üresek!
'; $PALANG['pAdminCreate_admin_button'] = 'Admin felvétele'; $PALANG['pAdminCreate_admin_result_error'] = 'Nemsikerült az Admint felvenni!'; $PALANG['pAdminCreate_admin_result_success'] = 'Az Admin sikeresen bekerült az adatbázisba!'; $PALANG['pAdminCreate_admin_address'] = 'Domain'; $PALANG['pAdminEdit_admin_welcome'] = 'Domain admin szerkesztése'; $PALANG['pAdminEdit_admin_username'] = 'Admin'; $PALANG['pAdminEdit_admin_password'] = 'Jelszó'; $PALANG['pAdminEdit_admin_password2'] = 'Jelszó (mégegyszer)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'A beírt jelszavak nem egyeznek!
Vagy üresek!
'; $PALANG['pAdminEdit_admin_active'] = 'Aktív'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super admin'; # XXX $PALANG['pAdminEdit_admin_button'] = 'Admin szerkesztése'; $PALANG['pAdminEdit_admin_result_error'] = 'Nemsikerült módosítani az admint!'; $PALANG['pAdminEdit_admin_result_success'] = 'Az Admin módosítása megtörtént!'; $PALANG['pUsersLogin_welcome'] = 'A felhasználók ezen a felületen tudnak bejelentkezni a levelezõ rendszerbe a saját
felhasználó nevükkel (azaz email címükkel) és itt tudják megváltoztatni az aliasokat, stb..'; $PALANG['pUsersLogin_username'] = 'Login (email)'; $PALANG['pUsersLogin_password'] = 'Jelszó'; $PALANG['pUsersLogin_button'] = 'Login'; $PALANG['pUsersLogin_username_incorrect'] = 'Nem megfelelõ a Login (email) cím! Kérlek pontosítsd!'; $PALANG['pUsersLogin_password_incorrect'] = 'Nem megfelelõ a jelszavad!'; $PALANG['pUsersMenu_vacation'] = 'Automatikus Válasz'; $PALANG['pUsersMenu_edit_alias'] = 'Átirányítás beállítása'; $PALANG['pUsersMenu_password'] = 'Jelszó megváltoztatása'; $PALANG['pUsersMain_vacation'] = 'Itt lehet beállítani az automatikus válasz levél szövegét, ha az ember távol van.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' bekapcsolva, click \'' . $PALANG['pUsersMenu_vacation'] . '\' to ' . $PALANG['edit'] . '/remove'; $PALANG['pUsersMain_edit_alias'] = 'Email átirányítás beállítása.'; $PALANG['pUsersMain_password'] = 'Jelenlegi jelszó megváltoztatása.'; $PALANG['pUsersVacation_welcome'] = 'Automatikus válasz.'; $PALANG['pUsersVacation_welcome_text'] = 'Már van be állítva automatikus válasz !'; $PALANG['pUsersVacation_subject'] = 'Tárgy'; $PALANG['pUsersVacation_subject_text'] = 'Sajnálom, de jelenleg nem vagyok email közelben!'; $PALANG['pUsersVacation_body'] = 'Üzenet'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << postfixadmin-2.3.7/languages/nb.lang0000664000175000017620000006425111636730120017476 0ustar davidpalepurpleKan ikke slette oppføringen '; $PALANG['pDelete_delete_success'] = '%s slettet.'; $PALANG['pDelete_postdelete_error'] = 'Kan ikke slette e-postkontoen '; $PALANG['pDelete_domain_error'] = 'Dette domenet tilhører deg ikke '; $PALANG['pDelete_domain_alias_error'] = 'Dette domenet tilhører deg ikke '; $PALANG['pDelete_alias_error'] = 'Kan ikke slette alias '; $PALANG['pCreate_alias_domain_welcome'] = 'Videresender alt som sendes til et domene til et annet domene.'; $PALANG['pCreate_alias_domain_alias'] = 'Aliasdomene'; $PALANG['pCreate_alias_domain_alias_text'] = 'Domenet de innkommende e-postmeldingene er adressert til.'; $PALANG['pCreate_alias_domain_target'] = 'Destinasjonsdomene'; $PALANG['pCreate_alias_domain_target_text'] = 'Domenet e-postmeldingene skal videresendes til.'; $PALANG['pCreate_alias_domain_active'] = 'Aktiv'; $PALANG['pCreate_alias_domain_button'] = 'Legg til aliasdomene'; $PALANG['pCreate_alias_domain_error1'] = 'Du har ikke tillatelse til å opprette den valgte konfigurasjonen.'; $PALANG['pCreate_alias_domain_error2'] = 'Den valgte konfigurasjonen er ugyldig, vennligst endre den!'; $PALANG['pCreate_alias_domain_error3'] = 'Det mislyktes å lagre informasjonen i databasen.'; $PALANG['pCreate_alias_domain_error4'] = 'Det er allerede opprettet alias for alle domenene.'; $PALANG['pCreate_alias_domain_success'] = 'Domenealiaset har blitt lagt inn i tabellen over aliasdomener!'; $PALANG['pCreate_alias_welcome'] = 'Opprett et nytt alias.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
Aliaset er ikke gyldig!'; $PALANG['pCreate_alias_address_text_error2'] = '
Denne e-postadressen eksisterer allerede, vennligst velg en annen!'; $PALANG['pCreate_alias_address_text_error3'] = '
Du har nådd grensen for antall aliaser under dette domenet!'; $PALANG['pCreate_alias_goto'] = 'Til'; $PALANG['pCreate_alias_active'] = 'Aktiv'; $PALANG['pCreate_alias_button'] = 'Legg til alias'; $PALANG['pCreate_alias_goto_text'] = 'Hvor e-postmeldingen skal videresendes til.'; $PALANG['pCreate_alias_goto_text_error'] = 'Hvor e-postmeldingen skal videresendes til.
Til-adressen er ikke gyldig!'; $PALANG['pCreate_alias_result_error'] = 'Kunne ikke legge til aliaset i alias-tabellen!'; $PALANG['pCreate_alias_result_success'] = 'Aliaset er blitt lagt til i alias-tabellen!'; $PALANG['pCreate_alias_catchall_text'] = 'For å opprette et "catch-all"-alias, bruk "*" som alias.
For domene-til-domene-videresending, bruk "*@domene.tld" i Til-feltet.'; $PALANG['pEdit_alias_welcome'] = 'Endre et alias.
Én e-postadresse per linje.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Finner ikke aliaset!'; $PALANG['pEdit_alias_goto'] = 'Til'; $PALANG['pEdit_alias_active'] = 'Aktiv'; $PALANG['pEdit_alias_goto_text_error1'] = 'Du skrev ingenting i Til-feltet'; $PALANG['pEdit_alias_goto_text_error2'] = 'E-postadressen er ikke gyldig: '; $PALANG['pEdit_alias_domain_error'] = 'Dette domenet tilhører deg ikke: '; $PALANG['pEdit_alias_domain_result_error'] = 'Kan ikke endre aliasdomenet!'; $PALANG['pEdit_alias_forward_and_store'] = 'Lever til den lokale e-postkontoen i tillegg.'; $PALANG['pEdit_alias_forward_only'] = 'Bare videresend til de angitte e-postadressene.'; $PALANG['pEdit_alias_button'] = 'Endre alias'; $PALANG['pEdit_alias_result_error'] = 'Kan ikke endre aliaset!'; $PALANG['pCreate_mailbox_welcome'] = 'Opprett en ny e-postkonto.'; $PALANG['pCreate_mailbox_username'] = 'Brukernavn'; $PALANG['pCreate_mailbox_username_text_error1'] = '
E-postadressen er ikke gyldig!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
E-postadressen eksisterer allerede, vennligst velg en annen!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Du har nådd grensen for antall e-postkontoer under dette domenet!'; $PALANG['pCreate_mailbox_password'] = 'Passord'; $PALANG['pCreate_mailbox_password2'] = 'Passord (bekreft)'; $PALANG['pCreate_mailbox_password_text'] = 'Passord for POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Passord for POP3/IMAP
Passordene du oppga stemmer ikke overens!
Eller du har ikke fylt ut feltene!
'; $PALANG['pCreate_mailbox_name'] = 'Navn'; $PALANG['pCreate_mailbox_name_text'] = 'Fullt navn'; $PALANG['pCreate_mailbox_quota'] = 'Kvote'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Kvoten du har angitt er for høy!'; $PALANG['pCreate_mailbox_active'] = 'Aktiv'; $PALANG['pCreate_mailbox_mail'] = 'Send velkomstmelding'; $PALANG['pCreate_mailbox_button'] = 'Opprett e-postkonto'; $PALANG['pCreate_mailbox_result_error'] = 'Kunne ikke legge til e-postkontoen i mailbox-tabellen!'; $PALANG['pCreate_mailbox_result_success'] = 'E-postkontoen er blitt opprettet i mailbox-tabellen!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'E-postkontoen er blitt opprettet i mailbox-tabellen, men ingen (eller kun noen) av de forhåndsdefinerte undermappene kunne opprettes.'; $PALANG['pEdit_mailbox_welcome'] = 'Endre en e-postkonto.'; $PALANG['pEdit_mailbox_username'] = 'Brukernavn'; $PALANG['pEdit_mailbox_username_error'] = 'Fant ikke e-postkontoen!'; $PALANG['pEdit_mailbox_password'] = 'Nytt passord'; $PALANG['pEdit_mailbox_password2'] = 'Nytt passord (bekreft)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Passordene du oppga stemmer ikke overens!'; $PALANG['pEdit_mailbox_name'] = 'Navn'; $PALANG['pEdit_mailbox_name_text'] = 'Fullt navn'; $PALANG['pEdit_mailbox_quota'] = 'Kvote'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Kvoten du har angitt er for høy!'; $PALANG['pEdit_mailbox_domain_error'] = 'Dette domenet tilhører deg ikke: '; $PALANG['pEdit_mailbox_button'] = 'Endre e-postkonto'; $PALANG['pEdit_mailbox_result_error'] = 'Kunne ikke endre e-postkontoen!'; $PALANG['pPassword_welcome'] = 'Endring av passord.'; $PALANG['pPassword_admin'] = 'Brukernavn'; $PALANG['pPassword_admin_text_error'] = 'Ingen e-postkonto stemmer overens med brukernavnet du oppga!'; $PALANG['pPassword_password_current'] = 'Nåværende passord'; $PALANG['pPassword_password_current_text_error'] = 'Du oppga ikke ditt nåværende passord!'; $PALANG['pPassword_password'] = 'Nytt passord'; $PALANG['pPassword_password2'] = 'Nytt passord (bekreft)'; $PALANG['pPassword_password_text_error'] = 'Passordene du oppga stemmer ikke overens!
Eller du har ikke fylt ut feltene!
'; $PALANG['pPassword_button'] = 'Endre passord'; $PALANG['pPassword_result_error'] = 'Kunne ikke endre passordet ditt!'; $PALANG['pPassword_result_success'] = 'Ditt passord er nå endret!'; $PALANG['pEdit_vacation_set'] = 'Endre / angi fraværsmelding'; $PALANG['pEdit_vacation_remove'] = 'Fjern fraværsmelding'; $PALANG['pVacation_result_error'] = 'Kunne ikke oppdatere innstillinger for automatisk svar!'; $PALANG['pVacation_result_removed'] = 'Automatisk svar har blitt fjernet!'; $PALANG['pVacation_result_added'] = 'Automatisk svar har blitt aktivert!'; $PALANG['pViewlog_welcome'] = 'Vis de 10 siste handlingene for '; $PALANG['pViewlog_timestamp'] = 'Klokkeslett'; $PALANG['pViewlog_username'] = 'Administrator'; $PALANG['pViewlog_domain'] = 'Domene'; $PALANG['pViewlog_action'] = 'Handling'; $PALANG['pViewlog_data'] = 'Data'; $PALANG['pViewlog_action_create_mailbox'] = 'opprett e-postkonto'; $PALANG['pViewlog_action_delete_mailbox'] = 'slett e-postkonto'; $PALANG['pViewlog_action_edit_mailbox'] = 'rediger e-postkonto'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'endre aktiv-status på e-postkonto'; $PALANG['pViewlog_action_create_alias'] = 'opprett alias'; $PALANG['pViewlog_action_create_alias_domain'] = 'opprett aliasdomene'; $PALANG['pViewlog_action_delete_alias'] = 'slett alias'; $PALANG['pViewlog_action_delete_alias_domain'] = 'slett aliasdomene'; $PALANG['pViewlog_action_edit_alias'] = 'rediger alias'; $PALANG['pViewlog_action_edit_alias_state'] = 'rediger aliasstatus'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'endre aktiv-status på aliasdomene'; $PALANG['pViewlog_action_edit_password'] = 'endre passord'; $PALANG['pViewlog_button'] = 'Vis'; $PALANG['pViewlog_result_error'] = 'Finner ikke den aktuelle loggen!'; $PALANG['pSendmail_welcome'] = 'Send en e-postmelding.'; $PALANG['pSendmail_admin'] = 'Fra'; $PALANG['pSendmail_to'] = 'Til'; $PALANG['pSendmail_to_text_error'] = 'Til-feltet er ikke fylt ut eller inneholder en ugyldig e-postadresse!'; $PALANG['pSendmail_subject'] = 'Emne'; $PALANG['pSendmail_subject_text'] = 'Velkommen'; $PALANG['pSendmail_body'] = 'Meldingstekst'; $PALANG['pSendmail_button'] = 'Send melding'; $PALANG['pSendmail_result_error'] = 'Kunne ikke sende e-postmeldingen!'; $PALANG['pSendmail_result_success'] = 'E-postmeldingen er sendt!'; $PALANG['pAdminMenu_list_admin'] = 'Administratorer'; $PALANG['pAdminMenu_list_domain'] = 'Domener'; $PALANG['pAdminMenu_list_virtual'] = 'Virtuell oversikt'; $PALANG['pAdminMenu_viewlog'] = 'Vis logg'; $PALANG['pAdminMenu_backup'] = 'Sikkerhetskopi'; $PALANG['pAdminMenu_create_domain_admins'] = 'Domeneadministratorer'; $PALANG['pAdminMenu_create_admin'] = 'Ny administrator'; $PALANG['pAdminMenu_create_domain'] = 'Nytt domene'; $PALANG['pAdminMenu_create_alias'] = 'Legg til alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Legg til e-postkonto'; $PALANG['pAdminList_admin_domain'] = 'Domene'; $PALANG['pAdminList_admin_username'] = 'Administrator'; $PALANG['pAdminList_admin_count'] = 'Domener'; $PALANG['pAdminList_admin_modified'] = 'Sist endret'; $PALANG['pAdminList_admin_active'] = 'Aktiv'; $PALANG['pAdminList_domain_domain'] = 'Domene'; $PALANG['pAdminList_domain_description'] = 'Beskrivelse'; $PALANG['pAdminList_domain_aliases'] = 'Alias'; $PALANG['pAdminList_domain_mailboxes'] = 'Epostkontoer'; $PALANG['pAdminList_domain_maxquota'] = 'Makskvote (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; $PALANG['pAdminList_domain_backupmx'] = 'Backup-MX'; $PALANG['pAdminList_domain_modified'] = 'Sist endret'; $PALANG['pAdminList_domain_active'] = 'Aktiv'; $PALANG['pAdminList_virtual_button'] = 'Vis'; $PALANG['pAdminList_virtual_welcome'] = 'Oversikt for '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Alias'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'E-postkontoer'; $PALANG['pAdminList_virtual_alias_address'] = 'Fra'; $PALANG['pAdminList_virtual_alias_goto'] = 'Til'; $PALANG['pAdminList_virtual_alias_modified'] = 'Sist endret'; $PALANG['pAdminList_virtual_mailbox_username'] = 'E-post'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Navn'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Kvote (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Sist endret'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Aktiv'; $PALANG['pAdminCreate_domain_welcome'] = 'Legg til et nytt domene'; $PALANG['pAdminCreate_domain_domain'] = 'Domene'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Domenet finnes allerede!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'Domenet er ugyldig!'; $PALANG['pAdminCreate_domain_description'] = 'Beskrivelse'; $PALANG['pAdminCreate_domain_aliases'] = 'Alias'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = deaktiver | 0 = ubegrenset'; $PALANG['pAdminCreate_domain_mailboxes'] = 'E-postkontoer'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = deaktiver | 0 = ubegrenset'; $PALANG['pAdminCreate_domain_maxquota'] = 'Makskvote'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = deaktiver | 0 = ubegrenset'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Definer transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Legg til standard-aliasadresser'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'E-postserveren er backup-MX'; $PALANG['pAdminCreate_domain_button'] = 'Legg til domene'; $PALANG['pAdminCreate_domain_result_error'] = 'Kunne ikke opprette domenet!'; $PALANG['pAdminCreate_domain_result_success'] = 'Domenet er blitt opprettet!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Kunne ikke fjerne domenet!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Kunne ikke fjerne domenealias!'; $PALANG['pAdminEdit_domain_welcome'] = 'Endre et domene'; $PALANG['pAdminEdit_domain_domain'] = 'Domene'; $PALANG['pAdminEdit_domain_description'] = 'Beskrivelse'; $PALANG['pAdminEdit_domain_aliases'] = 'Alias'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = deaktiver | 0 = ubegrenset'; $PALANG['pAdminEdit_domain_mailboxes'] = 'E-postkontoer'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = deaktiver | 0 = ubegrenset'; $PALANG['pAdminEdit_domain_maxquota'] = 'Makskvote'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = deaktiver | 0 = ubegrenset'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Definer transport'; $PALANG['pAdminEdit_domain_backupmx'] = 'E-postserveren er backup-MX'; $PALANG['pAdminEdit_domain_active'] = 'Aktiv'; $PALANG['pAdminEdit_domain_button'] = 'Endre domene'; $PALANG['pAdminEdit_domain_result_error'] = 'Kunne ikke endre domenet!'; $PALANG['pAdminCreate_admin_welcome'] = 'Legg til en ny domeneadministrator'; $PALANG['pAdminCreate_admin_username'] = 'Administrator'; $PALANG['pAdminCreate_admin_username_text'] = 'E-postadresse'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'E-postadresse
Du har ikke skrevet inn en gyldig e-postadresse!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'E-postadresse
Administratoren er allerede definert, eller du har skrevet inn en ugyldig adresse'; $PALANG['pAdminCreate_admin_password'] = 'Passord'; $PALANG['pAdminCreate_admin_password2'] = 'Passord (bekreft)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Passordene du oppga stemmer ikke overens!
Eller du har ikke fylt ut feltene!
'; $PALANG['pAdminCreate_admin_button'] = 'Legg til en administrator'; $PALANG['pAdminCreate_admin_result_error'] = 'Kunne ikke legge til administratoren!'; $PALANG['pAdminCreate_admin_result_success'] = 'Administratoren er lagt til!'; $PALANG['pAdminCreate_admin_address'] = 'Domene'; $PALANG['pAdminEdit_admin_welcome'] = 'Endre domeneadministrator'; $PALANG['pAdminEdit_admin_username'] = 'Administrator'; $PALANG['pAdminEdit_admin_password'] = 'Passord'; $PALANG['pAdminEdit_admin_password2'] = 'Passord (bekreft)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Passordene du oppga stemmer ikke overens!
Eller du har ikke fylt ut feltene!
'; $PALANG['pAdminEdit_admin_active'] = 'Aktiv'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super-administrator'; $PALANG['pAdminEdit_admin_button'] = 'Endre administrator'; $PALANG['pAdminEdit_admin_result_error'] = 'Klarte ikke å endre administratoren!'; $PALANG['pAdminEdit_admin_result_success'] = 'Administratoren er blitt endret!'; $PALANG['pUsersLogin_welcome'] = 'Brukere kan logge inn her for å endre passord og videresending.'; $PALANG['pUsersLogin_username'] = 'Brukernavn (e-postadresse)'; $PALANG['pUsersLogin_password'] = 'Passord'; $PALANG['pUsersLogin_button'] = 'Logg inn'; $PALANG['pUsersLogin_username_incorrect'] = 'Påloggingsinformasjonen er ikke korrekt. Husk å bruke e-postadressen som brukernavn.'; $PALANG['pUsersLogin_password_incorrect'] = 'Feil passord!'; $PALANG['pUsersMenu_vacation'] = 'Automatisk svar'; $PALANG['pUsersMenu_edit_alias'] = 'Endre videresending'; $PALANG['pUsersMenu_password'] = 'Endre passord'; $PALANG['pUsersMain_vacation'] = 'Angi en fraværsmelding eller annet automatisk svar.'; $PALANG['pUsersMain_vacationSet'] = 'Automatisk svar er PÅ, klikk \'Automatisk svar\' for å endre/fjerne'; $PALANG['pUsersMain_edit_alias'] = 'Endre videresending.'; $PALANG['pUsersMain_password'] = 'Endre passordet ditt.'; $PALANG['pUsersVacation_welcome'] = 'Automatisk svar.'; $PALANG['pUsersVacation_welcome_text'] = 'Du har allerede et autosvar aktivert!'; $PALANG['pUsersVacation_subject'] = 'Emne'; $PALANG['pUsersVacation_subject_text'] = 'Fraværsmelding'; $PALANG['pUsersVacation_body'] = 'Meldingstekst'; $PALANG['pUsersVacation_body_text'] = << postfixadmin-2.3.7/languages/language-update.sh0000775000175000017620000002132211316221026021621 0ustar davidpalepurple#!/bin/bash # Postfix Admin # # LICENSE # This source file is subject to the GPL license that is bundled with # this package in the file LICENSE.TXT. # # Further details on the project are available at : # http://www.postfixadmin.com or http://postfixadmin.sf.net # # @version $Id: language-update.sh 792 2009-12-28 21:24:38Z christian_boltz $ # @license GNU GPL v2 or later. # # File: language-update.sh # Lists missing translations in language files and optionally patches the # english texts into the language file. # Can also rename a $PALANG string. # # written by Christian Boltz function update_string_list() { for file in en.lang $filelist ; do echo "" | php > $file.strings done for file in $filelist ; do test "$file" = "en.lang" && continue LANG=C diff -U2 $file.strings en.lang.strings > $file.diff && echo "*** $file: no difference ***" test $notext = 1 && cat $file.diff && continue grep -v 'No newline at end of file' "$file.diff" | while read line ; do greptext="$(echo $line | sed 's/^[+ -]//')" grepresult=$(grep "'$greptext'" en.lang) || grepresult="***DEFAULT - $greptext dropped from en.lang? *** $line" grepresult2=$(grep "'$greptext'" $file) || grepresult2="$grepresult" case "$line" in ---*) echo "$line" ;; +++*) echo "$line" ;; @*) echo "$line" ;; -*) echo "-$grepresult" ;; +*) # needs translation # already added as comment? test "$grepresult" = "$grepresult2" && { echo "+$grepresult # XXX" # english } || { echo " $grepresult2" # translated echo "keeping line $grepresult2" >&2 echo "This will result in a malformed patch." >&2 } ;; *) echo " $grepresult2" ;; esac done > $file.patch test $patch = 0 && cat $file.patch test $patch = 1 && patch --fuzz=1 $file < $file.patch done } # end update_string_list() function forcepatch() { for i in `seq 1 5` ; do for file in $filelist ; do test "$file" = "en.lang" && { echo "*** skipping en.lang ***"; continue ; } >&2 "$0" "$file" | sed -n '1,3 p ; 5 s/^./-/p ; 5s/^./+/p ; 6p' | recountdiff | patch "$file" done done } # end forcepatch function rename_string() { for file in $filelist ; do line="$(grep "PALANG\['$rename_old'\]" "$file")" || { echo "*** $file does not contain \$PALANG['$rename_old'] ***" >&2 continue } newline="$(echo "$line" | sed "s/'$rename_old'/'$rename_new'/")" # create patch echo " --- $file.old +++ $file @@ -1,1 +1,1 @@ -$line +$newline " > "$file.patch" test $patch = 0 && cat $file.patch test $patch = 1 && patch $file < $file.patch done } # end rename_string() function remove_string() { for file in $filelist ; do line="$(grep "PALANG\['$remove_string'\]" "$file")" || { echo "*** $file does not contain \$PALANG['$remove_string'] ***" >&2 continue } # create patch echo " --- $file.old +++ $file @@ -1,1 +1,0 @@ -$line " > "$file.patch" test $patch = 0 && cat $file.patch test $patch = 1 && patch $file < $file.patch done } # end remove_string() function addcomment() { for file in $filelist ; do test "$file" = "en.lang" && { echo "*** skipping en.lang ***"; continue ; } >&2 line="$(grep "PALANG\['$text'\]" "$file")" || { echo "*** $file does not contain \$PALANG['$text'] ***" >&2 continue } newline="$line # XXX $comment" # create patch echo " --- $file.old +++ $file @@ -1,1 +1,1 @@ -$line +$newline " > "$file.patch" test $patch = 0 && cat $file.patch test $patch = 1 && patch $file < $file.patch done } # end add_comment function cleanup() { # check for duplicated strings for file in $filelist ; do sed -n "/PALANG/ s/[ ]*\$PALANG\['// ; s/'.*//p" $file |sort |uniq -c |grep -v " *1 " >&2 && \ echo "*** duplicated string in $file, see above for details ***" >&2 done # cleanup tempfiles test $nocleanup = 0 && for file in $filelist ; do rm -f $file.patch $file.strings $file.diff done } # end cleanup() statistics() { ( cat << 'EOF' Postfixadmin - translation statistics ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Translating is easy: - download your language file from SVN http://postfixadmin.svn.sourceforge.net/viewvc/postfixadmin/trunk/languages/ - search for lines with '# XXX' comments and - translate the line - remove the '# XXX' Note: The file is utf-8 encoded. You can also use htmlentities. - post your translation to the tracker http://sourceforge.net/tracker/?group_id=191583&atid=937966 Number of missing translations: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EOF grep -c XXX *.lang |sed 's/:/: /' cat << 'EOF' Statistics based on: EOF LANG=C svn info |grep 'Revision:\|Last Changed Date:' ) > postfixadmin-languages.txt echo "Translation statistics have been saved as postfixadmin-languages.txt" } # end statistics() usage() { echo ' Usage: ~~~~~~ '"$0"' [--notext | --patch] [--nocleanup] [foo.lang [bar.lang [...] ] ] List missing translations in language files and optionally patch the english texts into the language file --notext only list the translation keys (useful for a quick overview) Note for translators: untranslated entries have a comment # XXX attached. '"$0"' --rename old_string new_string [--patch] [--nocleanup] [foo.lang [bar.lang [...] ] ] Rename $PALANG['"'"'old_string'"'"'] to $PALANG['"'"'new_string'"'"'] '"$0"' --remove string [--patch] [--nocleanup] [foo.lang [bar.lang [...] ] ] Remove $PALANG['"'"'string'"'"'] from language files '"$0"' --addcomment string comment [--patch] [--nocleanup] [foo.lang [bar.lang [...] ] ] Add a comment to $PALANG['"'"'string'"'"'] Useful if a string needs to be translated again. '"$0"' --forcepatch [foo.lang [bar.lang [...] ] ] Similar to --patch, but applies the patch line by line. Useful if --patch fails because of empty lines etc., but much slower. --forcepatch patches 10 lines per run. When you only see messages like "patch: **** Only garbage was found in the patch input.", take it as success message :-) (no difference remaining) '"$0"' --stats Print translation statistics to postfixadmin-languages.txt Common parameters: --patch patch the language file directly (instead of displaying the patch) --nocleanup keep all temp files (for debugging) You can give any number of langugage files as parameter. If no files are given, all *.lang files will be used. ' } # end usage() # main script notext=0 # output full lines by default patch=0 # do not patch by default forcepatch=0 # no forcepatch by default nocleanup=0 # don't delete tempfiles rename=0 # rename a string remove=0 # remove a string stats=0 # create translation statistics addcomment=0 # add translation comment text='' comment='' rename_old='' renane_new='' filelist='' while [ -n "$1" ] ; do case "$1" in --help) usage exit 0; ;; --notext) notext=1 ;; --patch) patch=1 ;; --nocleanup) nocleanup=1 ;; --rename) rename=1 shift ; rename_old="$1" shift ; rename_new="$1" echo "$rename_old" | grep '^[a-z_-]*\.lang$' && rename_new='' # error out on *.lang - probably a filename echo "$rename_new" | grep '^[a-z_-]*\.lang$' && rename_new='' # error out on *.lang - probably a filename test -z "$rename_new" && { echo '--rename needs two parameters' >&2 ; exit 1 ; } ;; --remove) remove=1 shift ; remove_string="$1" test -z "$remove-string" && { echo '--remove needs a parameter' >&2 ; exit 1 ; } ;; --addcomment) addcomment=1 shift ; text="$1" shift ; comment="$1" echo "$text" | grep '^[a-z_-]*\.lang$' && comment='' # error out on *.lang - probably a filename echo "$comment" | grep '^[a-z_-]*\.lang$' && comment='' # error out on *.lang - probably a filename test -z "$comment" && { echo '--addcomment needs two parameters' >&2 ; exit 1 ; } ;; --forcepatch) forcepatch=1 ;; --stats) stats=1 ;; -*) echo 'unknown option. Try --help ;-)' >&2 exit 1 ;; *) filelist="$filelist $1" ;; esac shift done # end $@ loop test $notext = 1 && test $patch = 1 && echo "ERROR: You can't use --notext AND --patch at the same time." >&2 && exit 2 test $notext = 1 && test $rename = 1 && echo "ERROR: You can't use --notext AND --rename at the same time." >&2 && exit 2 test "$filelist" = "" && filelist="`ls -1 *.lang`" test "$addcomment" = 1 && { addcomment ; cleanup ; exit 0 ; } test "$rename" = 1 && { rename_string ; cleanup ; exit 0 ; } test "$remove" = 1 && { remove_string ; cleanup ; exit 0 ; } test "$forcepatch" = 1 && { forcepatch ; cleanup ; exit 0 ; } test "$stats" = 1 && { statistics ; exit 0 ; } update_string_list ; cleanup # default operation postfixadmin-2.3.7/languages/pt-br.lang0000664000175000017620000006562411636730120020130 0ustar davidpalepurple // $PALANG['YES'] = 'Sim'; $PALANG['NO'] = 'Não'; $PALANG['edit'] = 'Editar'; $PALANG['del'] = 'Remover'; $PALANG['exit'] = 'Sair'; $PALANG['cancel'] = 'Cancelar'; $PALANG['save'] = 'Gravar'; $PALANG['confirm'] = 'Tem certeza de que deseja remover?\n'; $PALANG['confirm_domain'] = 'Tem certeza de que deseja remover todos os registros deste domínio? Essa ação não pode ser desfeita!\n'; $PALANG['check_update'] = 'Checar por atualização'; $PALANG['invalid_parameter'] = 'Parâmetro inválido!'; $PALANG['pFooter_logged_as'] = 'Autenticado como %s'; $PALANG['pLogin_welcome'] = 'Administradores devem se autenticar aqui para gerenciar seus domínios.'; $PALANG['pLogin_username'] = 'Usuário (email)'; $PALANG['pLogin_password'] = 'Senha'; $PALANG['pLogin_button'] = 'Entrar'; $PALANG['pLogin_failed'] = 'Your email address or password are not correct.'; # XXX $PALANG['pLogin_login_users'] = 'Usuários devem clicar aqui para acessar a seção de usuários.'; $PALANG['pMenu_main'] = 'Menu Principal'; $PALANG['pMenu_overview'] = 'Visão Geral'; $PALANG['pMenu_create_alias'] = 'Criar Alias'; $PALANG['pMenu_create_alias_domain'] = 'Criar Alias de Domínio'; $PALANG['pMenu_create_mailbox'] = 'Criar Conta de Email'; $PALANG['pMenu_fetchmail'] = 'Recuperar Mensagens'; $PALANG['pMenu_sendmail'] = 'Enviar Mensagem'; $PALANG['pMenu_password'] = 'Alterar Senha'; $PALANG['pMenu_viewlog'] = 'Histórico'; $PALANG['pMenu_logout'] = 'Sair'; $PALANG['pMain_welcome'] = 'Bem-vindo ao Postfix Admin!'; $PALANG['pMain_overview'] = 'Liste seus aliases (redirecionadores) e contas de email. Você pode editá-los / removê-los aqui.'; $PALANG['pMain_create_alias'] = 'Crie um novo alias (redirecionador) para o seu domínio.'; $PALANG['pMain_create_mailbox'] = 'Crie uma nova conta de email para o seu domínio.'; $PALANG['pMain_sendmail'] = 'Envie uma mensagem para uma conta recém-criada.'; $PALANG['pMain_password'] = 'Altere a senha da sua conta de administrador.'; $PALANG['pMain_viewlog'] = 'Veja o histórico de administração.'; $PALANG['pMain_logout'] = 'Saia do sistema.'; $PALANG['pOverview_disabled'] = 'Desabilitado'; $PALANG['pOverview_unlimited'] = 'Ilimitado'; $PALANG['pOverview_title'] = ':: Domínios'; $PALANG['pOverview_up_arrow'] = 'Topo da Página'; $PALANG['pOverview_right_arrow'] = 'Próxima Página'; $PALANG['pOverview_left_arrow'] = 'Página Anterior'; $PALANG['pOverview_alias_domain_title'] = ':: Aliases de Domínio'; $PALANG['pOverview_alias_title'] = ':: Aliases'; $PALANG['pOverview_mailbox_title'] = ':: Contas de email'; $PALANG['pOverview_button'] = 'Acessar'; $PALANG['pOverview_welcome'] = 'Visão geral de '; $PALANG['pOverview_alias_domain_aliases'] = 'Aliases de Domínio'; $PALANG['pOverview_alias_domain_target'] = '%s é um alias de domínio para:'; $PALANG['pOverview_alias_alias_count'] = 'Aliases'; $PALANG['pOverview_alias_mailbox_count'] = 'Contas de email'; $PALANG['pOverview_alias_address'] = 'De'; $PALANG['pOverview_alias_goto'] = 'Para'; $PALANG['pOverview_alias_modified'] = 'Última Modificação'; $PALANG['pOverview_alias_domain_modified'] = 'Última Modificação'; $PALANG['pOverview_alias_active'] = 'Habilitado'; $PALANG['pOverview_alias_domain_active'] = 'Habilitado'; $PALANG['pOverview_alias_edit'] = 'Alias'; $PALANG['and_x_more'] = '[e %s mais...]'; $PALANG['pOverview_mailbox_username'] = 'Email'; $PALANG['pOverview_mailbox_name'] = 'Nome'; $PALANG['pOverview_mailbox_quota'] = 'Cota de Espaço (MB)'; $PALANG['pOverview_mailbox_modified'] = 'Última Modificação'; $PALANG['pOverview_mailbox_active'] = 'Habilitado'; $PALANG['pOverview_vacation_edit'] = 'EM MODO DE FÉRIAS'; $PALANG['pOverview_vacation_option'] = 'Modo de férias'; $PALANG['pOverview_get_domain'] = 'Domínio'; $PALANG['pOverview_get_aliases'] = 'Aliases'; $PALANG['pOverview_get_alias_domains'] = 'Aliases de Domínio'; $PALANG['pOverview_get_mailboxes'] = 'Contas de email'; $PALANG['pOverview_get_quota'] = 'Cota de Espaço (MB)'; $PALANG['pOverview_get_modified'] = 'Última Modificação'; $PALANG['pDelete_delete_error'] = 'Não foi possível remover o registro '; $PALANG['pDelete_delete_success'] = '%s removido.'; $PALANG['pDelete_postdelete_error'] = 'Não foi possível remover a conta de email '; $PALANG['pDelete_domain_error'] = 'Domínio não lhe pertence '; $PALANG['pDelete_domain_alias_error'] = 'Domínio não lhe pertence '; $PALANG['pDelete_alias_error'] = 'Não foi possível remover o alias '; $PALANG['pCreate_alias_domain_welcome'] = 'Configuração de espelhamento de endereços de um domínio para outro.'; $PALANG['pCreate_alias_domain_alias'] = 'Alias de Domínio'; $PALANG['pCreate_alias_domain_alias_text'] = 'O domínio para o qual as mensagens são enviadas.'; $PALANG['pCreate_alias_domain_target'] = 'Domínio Destino'; $PALANG['pCreate_alias_domain_target_text'] = 'O domínio para onde as mensagens devem ir.'; $PALANG['pCreate_alias_domain_active'] = 'Habilitado'; $PALANG['pCreate_alias_domain_button'] = 'Criar Alias de Domínio'; $PALANG['pCreate_alias_domain_error1'] = 'Você não possui permissão para criar a configuração desejada.'; $PALANG['pCreate_alias_domain_error2'] = 'Configuração inválida. Por favor, defina outra configuração!'; $PALANG['pCreate_alias_domain_error3'] = 'Não foi possível criar o alias de domínio.'; $PALANG['pCreate_alias_domain_error4'] = 'Todos os domínios já estão espelhados.'; $PALANG['pCreate_alias_domain_success'] = 'Alias de domínio criado!'; $PALANG['pCreate_alias_welcome'] = 'Criação de um novo alias para o domínio.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
Alias inválido!'; $PALANG['pCreate_alias_address_text_error2'] = '
Endereço de email fornecido já existe. Por favor, escolha outro endereço!'; $PALANG['pCreate_alias_address_text_error3'] = '
Você alcançou seu limite de aliases!'; $PALANG['pCreate_alias_goto'] = 'Para'; $PALANG['pCreate_alias_active'] = 'Habilitado'; $PALANG['pCreate_alias_button'] = 'Criar Alias'; $PALANG['pCreate_alias_goto_text'] = 'Para onde as mensagens serão enviadas.'; $PALANG['pCreate_alias_goto_text_error'] = 'Para onde as mensagens serão redirecionadas.
O endereço no campo Para é inválido!'; $PALANG['pCreate_alias_result_error'] = 'Não foi possível criar o alias!'; $PALANG['pCreate_alias_result_success'] = 'Alias criado!'; $PALANG['pCreate_alias_catchall_text'] = 'Para criar um alias global, use "*" no campo Alias.
Para encaminhar de um domínio para outro, use "*@dominio.tld" no campo Para.'; $PALANG['pEdit_alias_welcome'] = 'Edição de alias do domínio.
Uma entrada por linha.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Não foi possível encontrar o alias!'; $PALANG['pEdit_alias_goto'] = 'Para'; $PALANG['pEdit_alias_active'] = 'Habilitado'; $PALANG['pEdit_alias_goto_text_error1'] = 'Você não preencheu o campo Para'; $PALANG['pEdit_alias_goto_text_error2'] = 'O endereço de email fornecido é inválido: '; $PALANG['pEdit_alias_domain_error'] = 'Domínio não lhe pertence: '; $PALANG['pEdit_alias_domain_result_error'] = 'Não foi possível editar o alias de domínio!'; $PALANG['pEdit_alias_forward_and_store'] = 'Entregar mensagens na caixa de email local além de redirecioná-las.'; $PALANG['pEdit_alias_forward_only'] = 'Apenas redirecionar as mensagens para os endereços acima.'; $PALANG['pEdit_alias_button'] = 'Editar Alias'; $PALANG['pEdit_alias_result_error'] = 'Não foi possível editar o alias!'; $PALANG['pCreate_mailbox_welcome'] = 'Criação de uma nova conta de email para o domínio.'; $PALANG['pCreate_mailbox_username'] = 'Usuário'; $PALANG['pCreate_mailbox_username_text_error1'] = '
Email inválido!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Endereço de email fornecido já existe. Por favor, escolha outro endereço!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Você alcançou o limite de contas de email!'; $PALANG['pCreate_mailbox_password'] = 'Senha'; $PALANG['pCreate_mailbox_password2'] = 'Senha (confirmação)'; $PALANG['pCreate_mailbox_password_text'] = 'Senha para POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Senha para POP3/IMAP
As senhas fornecidas são diferentes!
Ou não foram digitadas!
'; $PALANG['pCreate_mailbox_name'] = 'Nome'; $PALANG['pCreate_mailbox_name_text'] = 'Nome completo'; $PALANG['pCreate_mailbox_quota'] = 'Cota de espaço'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
A cota de espaço especificada é muito alta!'; $PALANG['pCreate_mailbox_active'] = 'Habilitada'; $PALANG['pCreate_mailbox_mail'] = 'Enviar mensagem de boas-vindas'; $PALANG['pCreate_mailbox_button'] = 'Criar Conta de Email'; $PALANG['pCreate_mailbox_result_error'] = 'Não foi possível criar a conta de email!'; $PALANG['pCreate_mailbox_result_success'] = 'Conta de email criada!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'Conta de email criada, mas nenhum (ou apenas alguns) dos subdiretórios pré-definidos puderam ser criados'; $PALANG['pEdit_mailbox_welcome'] = 'Edição de conta de email do domínio.'; $PALANG['pEdit_mailbox_username'] = 'Usuário'; $PALANG['pEdit_mailbox_username_error'] = 'Não foi possível encontrar a conta de email!'; $PALANG['pEdit_mailbox_password'] = 'Nova senha'; $PALANG['pEdit_mailbox_password2'] = 'Nova senha (confirmação)'; $PALANG['pEdit_mailbox_password_text_error'] = 'As senhas fornecidas são diferentes!'; $PALANG['pEdit_mailbox_name'] = 'Nome'; $PALANG['pEdit_mailbox_name_text'] = 'Nome completo'; $PALANG['pEdit_mailbox_quota'] = 'Cota de espaço'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
A cota de espaço especificada é muito alta!'; $PALANG['pEdit_mailbox_domain_error'] = 'Domínio não lhe pertence: '; $PALANG['pEdit_mailbox_button'] = 'Editar Conta de Email'; $PALANG['pEdit_mailbox_result_error'] = 'Não foi possível editar a conta de email!'; $PALANG['pPassword_welcome'] = 'Alteração de senha.'; $PALANG['pPassword_admin'] = 'Usuário'; $PALANG['pPassword_admin_text_error'] = 'USUÁRIO fornecido não é uma conta de email válida!'; $PALANG['pPassword_password_current'] = 'Senha atual'; $PALANG['pPassword_password_current_text_error'] = 'Você não digitou sua senha atual!'; $PALANG['pPassword_password'] = 'Nova senha'; $PALANG['pPassword_password2'] = 'Nova senha (confirmação)'; $PALANG['pPassword_password_text_error'] = 'As senhas fornecidas são diferentes!
Ou não foram digitadas!
'; $PALANG['pPassword_button'] = 'Alterar Senha'; $PALANG['pPassword_result_error'] = 'Não foi possível alterar sua senha!'; $PALANG['pPassword_result_success'] = 'Senha alterada!'; $PALANG['pEdit_vacation_set'] = 'Editar / Definir Mensagem'; $PALANG['pEdit_vacation_remove'] = 'Remover Mensagem'; $PALANG['pVacation_result_error'] = 'Não foi possível atualizar as opções de resposta automática!'; $PALANG['pVacation_result_removed'] = 'Resposta automática removida!'; $PALANG['pVacation_result_added'] = 'Resposta automática habilitada!'; $PALANG['pViewlog_welcome'] = 'Últimas 10 ações para '; $PALANG['pViewlog_timestamp'] = 'Data/Hora'; $PALANG['pViewlog_username'] = 'Administrador'; $PALANG['pViewlog_domain'] = 'Domínio'; $PALANG['pViewlog_action'] = 'Ação'; $PALANG['pViewlog_data'] = 'Descrição'; $PALANG['pViewlog_action_create_mailbox'] = 'criar conta de email'; $PALANG['pViewlog_action_delete_mailbox'] = 'remover conta de email'; $PALANG['pViewlog_action_edit_mailbox'] = 'editar conta de email'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'habilitar/desabilitar conta de email'; $PALANG['pViewlog_action_create_alias'] = 'criar alias'; $PALANG['pViewlog_action_create_alias_domain'] = 'criar alias de domínio'; $PALANG['pViewlog_action_delete_alias'] = 'remover alias'; $PALANG['pViewlog_action_delete_alias_domain'] = 'remover alias de domínio'; $PALANG['pViewlog_action_edit_alias'] = 'editar alias'; $PALANG['pViewlog_action_edit_alias_state'] = 'habilitar/desabilitar alias'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'habilitar/desabilitar alias de domínio'; $PALANG['pViewlog_action_edit_password'] = 'alterar senha'; $PALANG['pViewlog_button'] = 'Acessar'; $PALANG['pViewlog_result_error'] = 'Não foi possível encontrar o histórico!'; $PALANG['pSendmail_welcome'] = 'Envio de mensagem.'; $PALANG['pSendmail_admin'] = 'De'; $PALANG['pSendmail_to'] = 'Para'; $PALANG['pSendmail_to_text_error'] = 'Campo Para está vazio ou não é um endereço de email válido!'; $PALANG['pSendmail_subject'] = 'Assunto'; $PALANG['pSendmail_subject_text'] = 'Bem-vindo(a)'; $PALANG['pSendmail_body'] = 'Corpo da Mensagem'; $PALANG['pSendmail_button'] = 'Enviar Mensagem'; $PALANG['pSendmail_result_error'] = 'Não foi possível enviar a mensagem!'; $PALANG['pSendmail_result_success'] = 'Mensagem enviada!'; $PALANG['pAdminMenu_list_admin'] = 'Administradores'; $PALANG['pAdminMenu_list_domain'] = 'Domínios'; $PALANG['pAdminMenu_list_virtual'] = 'Virtual'; $PALANG['pAdminMenu_viewlog'] = 'Histórico'; $PALANG['pAdminMenu_backup'] = 'Backup'; $PALANG['pAdminMenu_create_domain_admins'] = 'Administradores de Domínio'; $PALANG['pAdminMenu_create_admin'] = 'Criar Administrador'; $PALANG['pAdminMenu_create_domain'] = 'Criar Domínio'; $PALANG['pAdminMenu_create_alias'] = 'Criar Alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Criar Conta de Email'; $PALANG['pAdminList_admin_domain'] = 'Domínio'; $PALANG['pAdminList_admin_username'] = 'Administrador'; $PALANG['pAdminList_admin_count'] = 'Domínios'; $PALANG['pAdminList_admin_modified'] = 'Última Modificação'; $PALANG['pAdminList_admin_active'] = 'Habilitado'; $PALANG['pAdminList_domain_domain'] = 'Domínio'; $PALANG['pAdminList_domain_description'] = 'Descrição'; $PALANG['pAdminList_domain_aliases'] = 'Aliases'; $PALANG['pAdminList_domain_mailboxes'] = 'Contas de Email'; $PALANG['pAdminList_domain_maxquota'] = 'Cota de Espaço (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transporte'; $PALANG['pAdminList_domain_backupmx'] = 'MX de Backup'; $PALANG['pAdminList_domain_modified'] = 'Última Modificação'; $PALANG['pAdminList_domain_active'] = 'Habilitado'; $PALANG['pAdminList_virtual_button'] = 'Acessar'; $PALANG['pAdminList_virtual_welcome'] = 'Visão geral de '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Aliases'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Contas de email'; $PALANG['pAdminList_virtual_alias_address'] = 'De'; $PALANG['pAdminList_virtual_alias_goto'] = 'Para'; $PALANG['pAdminList_virtual_alias_modified'] = 'Última Modificação'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Email'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Nome'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Cota de Espaço (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Última Modificação'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Habilitado'; $PALANG['pAdminCreate_domain_welcome'] = 'Criação de um novo domínio.'; $PALANG['pAdminCreate_domain_domain'] = 'Domínio'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'O domínio já existe!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'Domínio inválido!'; $PALANG['pAdminCreate_domain_description'] = 'Descrição'; $PALANG['pAdminCreate_domain_aliases'] = 'Aliases'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = desativar | 0 = ilimitado'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Contas de email'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = desativar | 0 = ilimitado'; $PALANG['pAdminCreate_domain_maxquota'] = 'Cota de espaço máxima'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = desativar | 0 = ilimitado'; $PALANG['pAdminCreate_domain_transport'] = 'Transporte'; $PALANG['pAdminCreate_domain_transport_text'] = 'Definir transporte'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Adicionar aliases padrão'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'Servidor de email é um MX de backup'; $PALANG['pAdminCreate_domain_button'] = 'Criar Domínio'; $PALANG['pAdminCreate_domain_result_error'] = 'Não foi possível criar o domínio!'; $PALANG['pAdminCreate_domain_result_success'] = 'Domínio criado!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Não foi possível remover o domínio!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Não foi possível remover o alias de domínio!'; $PALANG['pAdminEdit_domain_welcome'] = 'Edição de domínio.'; $PALANG['pAdminEdit_domain_domain'] = 'Domínio'; $PALANG['pAdminEdit_domain_description'] = 'Descrição'; $PALANG['pAdminEdit_domain_aliases'] = 'Aliases'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = desativar | 0 = ilimitado'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Contas de email'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = desativar | 0 = ilimitado'; $PALANG['pAdminEdit_domain_maxquota'] = 'Cota de espaço máxima'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = desativar | 0 = ilimitado'; $PALANG['pAdminEdit_domain_transport'] = 'Transporte'; $PALANG['pAdminEdit_domain_transport_text'] = 'Definir transporte'; $PALANG['pAdminEdit_domain_backupmx'] = 'Servidor de email é um MX de backup'; $PALANG['pAdminEdit_domain_active'] = 'Habilitado'; $PALANG['pAdminEdit_domain_button'] = 'Editar Domínio'; $PALANG['pAdminEdit_domain_result_error'] = 'Não foi possível editar o domínio!'; $PALANG['pAdminCreate_admin_welcome'] = 'Criação de um novo administrador de domínio.'; $PALANG['pAdminCreate_admin_username'] = 'Administrador'; $PALANG['pAdminCreate_admin_username_text'] = 'Endereço de email'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Endereço de email
Endereço de email inválido!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Endereço de email
Administrador já existe ou é inválido'; $PALANG['pAdminCreate_admin_password'] = 'Senha'; $PALANG['pAdminCreate_admin_password2'] = 'Senha (confirmação)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'As senhas fornecidas são diferentes!
Ou não foram digitadas!
'; $PALANG['pAdminCreate_admin_button'] = 'Criar Administrador'; $PALANG['pAdminCreate_admin_result_error'] = 'Não foi possível criar o administrador!'; $PALANG['pAdminCreate_admin_result_success'] = 'Administrador criado!'; $PALANG['pAdminCreate_admin_address'] = 'Domínio(s)'; $PALANG['pAdminEdit_admin_welcome'] = 'Edição de administrador de domínio.'; $PALANG['pAdminEdit_admin_username'] = 'Administrador'; $PALANG['pAdminEdit_admin_password'] = 'Senha'; $PALANG['pAdminEdit_admin_password2'] = 'Senha (confirmação)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'As senhas fornecidas são diferentes!
Ou não foram digitadas!
'; $PALANG['pAdminEdit_admin_active'] = 'Habilitado'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super administrador'; $PALANG['pAdminEdit_admin_button'] = 'Editar Administrador'; $PALANG['pAdminEdit_admin_result_error'] = 'Não foi possível editar o administrador!'; $PALANG['pAdminEdit_admin_result_success'] = 'Administrador editado!'; $PALANG['pUsersLogin_welcome'] = 'Usuários devem se autenticar aqui para troca de senha e configuração de redirecionamento de mensagens.'; $PALANG['pUsersLogin_username'] = 'Usuário (email)'; $PALANG['pUsersLogin_password'] = 'Senha'; $PALANG['pUsersLogin_button'] = 'Entrar'; $PALANG['pUsersLogin_username_incorrect'] = 'Usuário inválido. Certifique-se de ter digitado o email corretamente!'; $PALANG['pUsersLogin_password_incorrect'] = 'Senha inválida!'; $PALANG['pUsersMenu_vacation'] = 'Resposta Automática'; $PALANG['pUsersMenu_edit_alias'] = 'Configurar Redirecionamento'; $PALANG['pUsersMenu_password'] = 'Alterar Senha'; $PALANG['pUsersMain_vacation'] = 'Configure uma mensagem de ausente ou outra resposta automática.'; $PALANG['pUsersMain_vacationSet'] = 'Resposta automática HABILITADA. Clique em \'Resposta Automática\' para editar/remover.'; $PALANG['pUsersMain_edit_alias'] = 'Defina endereços de email para redirecionamento de mensagens.'; $PALANG['pUsersMain_password'] = 'Altere a senha de sua conta.'; $PALANG['pUsersVacation_welcome'] = 'Configuração de resposta automática.'; $PALANG['pUsersVacation_welcome_text'] = 'Você já possui uma resposta automática configurada!'; $PALANG['pUsersVacation_subject'] = 'Assunto'; $PALANG['pUsersVacation_subject_text'] = 'Ausente'; $PALANG['pUsersVacation_body'] = 'Corpo da Mensagem'; $PALANG['pUsersVacation_body_text'] = << até . Em caso de urgência, favor contatar . EOM; $PALANG['pUsersVacation_button_away'] = 'Ausente'; $PALANG['pUsersVacation_button_back'] = 'De Volta'; $PALANG['pUsersVacation_result_error'] = 'Não foi possível atualizar suas configurações de resposta automática!'; $PALANG['pUsersVacation_result_success'] = 'Resposta automática removida!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'criar conta de email'; $PALANG['pCreate_dbLog_createalias'] = 'criar alias'; $PALANG['pDelete_dbLog_deletealias'] = 'remover alias'; $PALANG['pDelete_dbLog_deletemailbox'] = 'remover conta de email'; $PALANG['pEdit_dbLog_editactive'] = 'habilitar/desabilitar'; $PALANG['pEdit_dbLog_editalias'] = 'editar alias'; $PALANG['pEdit_dbLog_editmailbox'] = 'editar conta de email'; $PALANG['pSearch'] = 'Pesquisar'; $PALANG['pSearch_welcome'] = 'Pesquisando por: '; $PALANG['pReturn_to'] = 'Retornar para'; $PALANG['pBroadcast_title'] = 'Envio de mensagem em massa.'; $PALANG['pBroadcast_from'] = 'De'; $PALANG['pBroadcast_name'] = 'Seu nome'; $PALANG['pBroadcast_subject'] = 'Assunto'; $PALANG['pBroadcast_message'] = 'Mensagem'; $PALANG['pBroadcast_send'] = 'Enviar Mensagem'; $PALANG['pBroadcast_success'] = 'Mensagem em massa enviada.'; $PALANG['pAdminMenu_broadcast_message'] = 'Mensagem em massa'; $PALANG['pBroadcast_error_empty'] = 'Os campos Nome, Assunto e Mensagem devem ser preenchidos!'; $PALANG['pStatus_undeliverable'] = 'talvez NÃO-ENTREGÁVEL '; $PALANG['pStatus_custom'] = 'Envia para '; $PALANG['pStatus_popimap'] = 'POP/IMAP '; $PALANG['pPasswordTooShort'] = "Senha muito curta - requer %s caracteres"; # uso: flash_error(sprintf($PALANG['pPasswordTooShort'], $CONF['min_password_length'])); $PALANG['pInvalidDomainRegex'] = "Nome de domínio inválido %s, falhou checagem por expressão regular"; $PALANG['pInvalidDomainDNS'] = "Domínio inválido %s, e/ou não pôde ser resolvido por DNS"; $PALANG['pInvalidMailRegex'] = "Endereço de email inválido, falhou checagem por expressão regular"; $PALANG['pFetchmail_welcome'] = 'Configuração de recuperação de mensagens para: '; $PALANG['pFetchmail_new_entry'] = 'Criar Novo Registro'; $PALANG['pFetchmail_database_save_error'] = 'Registro não pôde ser gravado no banco de dados!'; $PALANG['pFetchmail_database_save_success'] = 'Registro gravado no banco de dados.'; $PALANG['pFetchmail_error_invalid_id'] = 'Nenhum registro com ID %s foi encontrado!'; $PALANG['pFetchmail_invalid_mailbox'] = 'Conta de email inválida!'; $PALANG['pFetchmail_server_missing'] = 'Favor fornecer o nome do servidor remoto!'; $PALANG['pFetchmail_user_missing'] = 'Favor fornecer o nome de usuário da conta remota!'; $PALANG['pFetchmail_password_missing'] = 'Favor fornecer a senha da conta remota!'; $PALANG['pFetchmail_field_id'] = 'ID'; $PALANG['pFetchmail_field_mailbox'] = 'Conta'; $PALANG['pFetchmail_field_src_server'] = 'Servidor'; $PALANG['pFetchmail_field_src_auth'] = 'Autenticação'; $PALANG['pFetchmail_field_src_user'] = 'Usuário'; $PALANG['pFetchmail_field_src_password'] = 'Senha'; $PALANG['pFetchmail_field_src_folder'] = 'Diretório'; $PALANG['pFetchmail_field_poll_time'] = 'Checar'; $PALANG['pFetchmail_field_fetchall'] = 'Recuperar todas'; $PALANG['pFetchmail_field_keep'] = 'Manter'; $PALANG['pFetchmail_field_protocol'] = 'Protocolo'; $PALANG['pFetchmail_field_usessl'] = 'SSL habilitado'; $PALANG['pFetchmail_field_extra_options'] = 'Opções extra'; $PALANG['pFetchmail_field_mda'] = 'MDA'; $PALANG['pFetchmail_field_date'] = 'Data'; $PALANG['pFetchmail_field_returned_text'] = 'Texto retornado'; $PALANG['pFetchmail_desc_id'] = 'ID do registro'; $PALANG['pFetchmail_desc_mailbox'] = 'Conta de email local'; $PALANG['pFetchmail_desc_src_server'] = 'Servidor remoto'; $PALANG['pFetchmail_desc_src_auth'] = 'Quase sempre \'password\''; # Translators: Please do NOT translate 'password' here $PALANG['pFetchmail_desc_src_user'] = 'Usuário remoto'; $PALANG['pFetchmail_desc_src_password'] = 'Senha remota'; $PALANG['pFetchmail_desc_src_folder'] = 'Diretório remoto'; $PALANG['pFetchmail_desc_poll_time'] = 'Checar a cada ... minutos'; $PALANG['pFetchmail_desc_fetchall'] = 'Recuperar mensagens novas e antigas (lidas)'; $PALANG['pFetchmail_desc_keep'] = 'Manter mensagens recuperadas no servidor remoto'; $PALANG['pFetchmail_desc_protocol'] = 'Protocolo a ser usado'; $PALANG['pFetchmail_desc_usessl'] = 'Criptografado com SSL'; $PALANG['pFetchmail_desc_extra_options'] = 'Opções extra do fetchmail'; $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; $PALANG['pFetchmail_desc_date'] = 'Data da última checagem/mudança de configuração'; $PALANG['pFetchmail_desc_returned_text'] = 'Mensagem de texto da última checagem'; $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/cn.lang0000664000175000017620000006325111636730120017476 0ustar davidpalepurple // $PALANG['YES'] = '是'; $PALANG['NO'] = '否'; $PALANG['edit'] = '编辑'; $PALANG['del'] = '删除'; $PALANG['exit'] = 'Exit'; # XXX $PALANG['cancel'] = 'Cancel'; # XXX $PALANG['save'] = 'Save'; # XXX $PALANG['confirm'] = '是否确定删除?\n'; $PALANG['confirm_domain'] = '你是否确定要删除该域中的所有记录? 删除后不可恢复!\n'; $PALANG['check_update'] = '检查新版本'; $PALANG['invalid_parameter'] = 'Invalid parameter!'; # XXX $PALANG['pFooter_logged_as'] = 'Logged as %s'; # XXX $PALANG['pLogin_welcome'] = '邮件管理员请从这里登录以管理你的域名.'; $PALANG['pLogin_username'] = '帐号 (邮件地址)'; $PALANG['pLogin_password'] = '密码'; $PALANG['pLogin_button'] = '登录'; $PALANG['pLogin_failed'] = 'Your email address or password are not correct.'; # XXX $PALANG['pLogin_login_users'] = '普通用户点击这里进入用户控制面板.'; $PALANG['pMenu_main'] = 'Main'; # XXX $PALANG['pMenu_overview'] = '概览'; $PALANG['pMenu_create_alias'] = '新建别名'; $PALANG['pMenu_create_alias_domain'] = 'Add Alias Domain'; # XXX $PALANG['pMenu_create_mailbox'] = '新建邮箱'; $PALANG['pMenu_fetchmail'] = 'Fetch Email'; # XXX $PALANG['pMenu_sendmail'] = '发送邮件'; $PALANG['pMenu_password'] = '修改密码'; $PALANG['pMenu_viewlog'] = '查看日志'; $PALANG['pMenu_logout'] = '退出'; $PALANG['pMain_welcome'] = '欢迎来到Postfix Admin!'; $PALANG['pMain_overview'] = '显示你的邮件别名和邮箱. 你可以在这儿进行编辑/删除操作.'; $PALANG['pMain_create_alias'] = '在您的域中新建一个别名.'; $PALANG['pMain_create_mailbox'] = '在您的域中新建一个邮箱.'; $PALANG['pMain_sendmail'] = '发一封邮件到你新建的一个邮箱中.'; $PALANG['pMain_password'] = '修改你的管理员密码.'; $PALANG['pMain_viewlog'] = '查看日志文件.'; $PALANG['pMain_logout'] = '退出系统'; $PALANG['pOverview_disabled'] = 'Disabled'; # XXX $PALANG['pOverview_unlimited'] = 'Unlimited'; # XXX $PALANG['pOverview_title'] = ':: 域'; $PALANG['pOverview_up_arrow'] = '返回顶端'; $PALANG['pOverview_right_arrow'] = '下一页'; $PALANG['pOverview_left_arrow'] = '上一页'; $PALANG['pOverview_alias_domain_title'] = ':: Domain Aliases'; # XXX $PALANG['pOverview_alias_title'] = ':: 别名'; $PALANG['pOverview_mailbox_title'] = ':: 邮箱'; $PALANG['pOverview_button'] = '执行'; $PALANG['pOverview_welcome'] = '浏览 '; $PALANG['pOverview_alias_domain_aliases'] = 'Alias Domains'; # XXX $PALANG['pOverview_alias_domain_target'] = '%s is an Alias Domain for:'; # XXX $PALANG['pOverview_alias_alias_count'] = '别名'; $PALANG['pOverview_alias_mailbox_count'] = '邮箱'; $PALANG['pOverview_alias_address'] = '前往'; $PALANG['pOverview_alias_goto'] = '转到'; $PALANG['pOverview_alias_modified'] = '最后修改日期'; $PALANG['pOverview_alias_domain_modified'] = 'Last Modified'; # XXX $PALANG['pOverview_alias_active'] = 'Active'; # XXX $PALANG['pOverview_alias_domain_active'] = 'Active'; # XXX $PALANG['pOverview_alias_edit'] = 'Alias'; # XXX $PALANG['and_x_more'] = '[and %s more...]'; # XXX $PALANG['pOverview_mailbox_username'] = '邮件地址'; $PALANG['pOverview_mailbox_name'] = '姓名'; $PALANG['pOverview_mailbox_quota'] = '限制 (MB)'; $PALANG['pOverview_mailbox_modified'] = '最后修改日期'; $PALANG['pOverview_mailbox_active'] = '活动'; $PALANG['pOverview_vacation_edit'] = 'VACATION IS ON'; # XXX $PALANG['pOverview_vacation_option'] = 'Set Vacation'; # XXX $PALANG['pOverview_get_domain'] = '域'; $PALANG['pOverview_get_aliases'] = '别名'; $PALANG['pOverview_get_alias_domains'] = 'Domain Aliases'; # XXX $PALANG['pOverview_get_mailboxes'] = '邮箱'; $PALANG['pOverview_get_quota'] = '邮箱限制 (MB)'; $PALANG['pOverview_get_modified'] = '最后修改日期'; $PALANG['pDelete_delete_error'] = '不能删除本记录'; $PALANG['pDelete_delete_success'] = '%s deleted.'; # XXX $PALANG['pDelete_postdelete_error'] = 'Unable to remove mailbox '; # XXX $PALANG['pDelete_domain_error'] = '你没有该域的管理权限'; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = 'Unable to delete alias '; # XXX $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = '在你的域中新建一个别名.'; $PALANG['pCreate_alias_address'] = '别名'; $PALANG['pCreate_alias_address_text_error1'] = '
该别名非法!'; $PALANG['pCreate_alias_address_text_error2'] = '
邮件地址已经存在, 请重新选择!'; $PALANG['pCreate_alias_address_text_error3'] = '
你的别名已经达到上限!'; $PALANG['pCreate_alias_goto'] = '转到'; $PALANG['pCreate_alias_active'] = 'Active'; # XXX $PALANG['pCreate_alias_button'] = '新建别名'; $PALANG['pCreate_alias_goto_text'] = '邮件接收地址.'; $PALANG['pCreate_alias_goto_text_error'] = '邮件接收地址.
接收地址不正确!'; $PALANG['pCreate_alias_result_error'] = '不能将别名添加到别名表中!'; $PALANG['pCreate_alias_result_success'] = '添加别名成功!'; $PALANG['pCreate_alias_catchall_text'] = '要将所有的邮件全部转发请使用"*"作为别名.
域到域的转发请使用"*@domain.tld".'; $PALANG['pEdit_alias_welcome'] = '编辑你域名中的别名.
每行一条记录.'; $PALANG['pEdit_alias_address'] = '别名'; $PALANG['pEdit_alias_address_error'] = '不能定位别名!'; $PALANG['pEdit_alias_goto'] = '转到'; $PALANG['pEdit_alias_active'] = 'Active'; # XXX $PALANG['pEdit_alias_goto_text_error1'] = '你没有填写收信人'; $PALANG['pEdit_alias_goto_text_error2'] = '邮件地址非法: '; $PALANG['pEdit_alias_domain_error'] = '你没有该域的管理权限: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Deliver to the local mailbox.'; # XXX $PALANG['pEdit_alias_forward_only'] = 'Forward to given email addresses only.'; # XXX $PALANG['pEdit_alias_button'] = '编辑别名'; $PALANG['pEdit_alias_result_error'] = '不能修改该别名!'; $PALANG['pCreate_mailbox_welcome'] = '在你的域中新建一个本地邮箱.'; $PALANG['pCreate_mailbox_username'] = '用户名'; $PALANG['pCreate_mailbox_username_text_error1'] = '
邮件非法!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
邮件地址已经存在,请重新选择!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
邮箱地址已经达到上限!'; $PALANG['pCreate_mailbox_password'] = '密码'; $PALANG['pCreate_mailbox_password2'] = '密码 (再次输入)'; $PALANG['pCreate_mailbox_password_text'] = 'POP3/IMAP 密码'; $PALANG['pCreate_mailbox_password_text_error'] = 'POP3/IMAP 密码
你输入的密码不相同!
或者为空!
'; $PALANG['pCreate_mailbox_name'] = '名字'; $PALANG['pCreate_mailbox_name_text'] = '全名'; $PALANG['pCreate_mailbox_quota'] = '限制'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
你输入的容量限制超出范围!'; $PALANG['pCreate_mailbox_active'] = '活动'; $PALANG['pCreate_mailbox_mail'] = '新建邮箱'; $PALANG['pCreate_mailbox_button'] = '增加邮箱'; $PALANG['pCreate_mailbox_result_error'] = '不能将邮箱增加到邮箱表中!'; $PALANG['pCreate_mailbox_result_success'] = '增加邮箱成功!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'The mailbox has been added to the mailbox table, but none (or only some) of the predefined sub-folders could be created'; # XXX $PALANG['pEdit_mailbox_welcome'] = '编辑你域中的邮箱.'; $PALANG['pEdit_mailbox_username'] = '用户名'; $PALANG['pEdit_mailbox_username_error'] = '不能定们邮箱!'; $PALANG['pEdit_mailbox_password'] = '新密码'; $PALANG['pEdit_mailbox_password2'] = '新密码 (验证)'; $PALANG['pEdit_mailbox_password_text_error'] = '你输入的两个新密码不相同!'; $PALANG['pEdit_mailbox_name'] = '姓名'; $PALANG['pEdit_mailbox_name_text'] = 'Full name'; # XXX $PALANG['pEdit_mailbox_quota'] = '限制'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
你输入的容量限制超出范围!'; $PALANG['pEdit_mailbox_domain_error'] = '你没有该域的管理权限: '; $PALANG['pEdit_mailbox_button'] = '编辑邮箱'; $PALANG['pEdit_mailbox_result_error'] = '不能编辑该邮箱!'; $PALANG['pPassword_welcome'] = '更改你的登录密码.'; $PALANG['pPassword_admin'] = '帐号'; $PALANG['pPassword_admin_text_error'] = '你所提供的登录帐号不正确!'; $PALANG['pPassword_password_current'] = '当前密码'; $PALANG['pPassword_password_current_text_error'] = '你没有填写当前密码!'; $PALANG['pPassword_password'] = '新密码'; $PALANG['pPassword_password2'] = '新密码 (验证)'; $PALANG['pPassword_password_text_error'] = '你两次输入的新密码不相同!
或者为空!
'; $PALANG['pPassword_button'] = '更改密码'; $PALANG['pPassword_result_error'] = '更改密码失败!'; $PALANG['pPassword_result_success'] = '更改密码成功!'; $PALANG['pEdit_vacation_set'] = 'Change / Set away message'; # XXX $PALANG['pEdit_vacation_remove'] = 'Remove away message'; # XXX $PALANG['pVacation_result_error'] = 'Unable to update auto response settings!'; # XXX $PALANG['pVacation_result_removed'] = 'Auto response has been removed!'; # XXX $PALANG['pVacation_result_added'] = 'Auto response has been enabled!'; # XXX $PALANG['pViewlog_welcome'] = '查看最新的10项操作日志 域名: '; $PALANG['pViewlog_timestamp'] = '时间'; $PALANG['pViewlog_username'] = '管理员'; $PALANG['pViewlog_domain'] = '域'; $PALANG['pViewlog_action'] = '操作'; $PALANG['pViewlog_data'] = '内容'; $PALANG['pViewlog_action_create_mailbox'] = 'create mailbox'; # XXX $PALANG['pViewlog_action_delete_mailbox'] = 'delete mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox'] = 'edit mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox_state'] = 'edit mailbox active'; # XXX $PALANG['pViewlog_action_create_alias'] = 'create alias'; # XXX $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'delete alias'; # XXX $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'edit alias'; # XXX $PALANG['pViewlog_action_edit_alias_state'] = 'edit alias active'; # XXX $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'change password'; # XXX $PALANG['pViewlog_button'] = '执行'; $PALANG['pViewlog_result_error'] = '未找到相关的日志!'; $PALANG['pSendmail_welcome'] = '发送邮件.'; $PALANG['pSendmail_admin'] = '发件人'; $PALANG['pSendmail_to'] = '收件人'; $PALANG['pSendmail_to_text_error'] = '收件人为空或者收件人地址不正确!'; $PALANG['pSendmail_subject'] = '主题'; $PALANG['pSendmail_subject_text'] = '欢迎'; $PALANG['pSendmail_body'] = '内容'; $PALANG['pSendmail_button'] = '发送'; $PALANG['pSendmail_result_error'] = '建立邮箱失败!'; # XXX text change - new: Unable to send email! $PALANG['pSendmail_result_success'] = '建立邮箱成功!'; # XXX text change - new: Email sent! $PALANG['pAdminMenu_list_admin'] = '管理员清单'; $PALANG['pAdminMenu_list_domain'] = '域名清单'; $PALANG['pAdminMenu_list_virtual'] = '虚拟用户清单'; $PALANG['pAdminMenu_viewlog'] = '查看日志'; $PALANG['pAdminMenu_backup'] = '备份'; $PALANG['pAdminMenu_create_domain_admins'] = '域管理员'; $PALANG['pAdminMenu_create_admin'] = '新建管理员'; $PALANG['pAdminMenu_create_domain'] = '新建域'; $PALANG['pAdminMenu_create_alias'] = '新建别名'; $PALANG['pAdminMenu_create_mailbox'] = '新建邮箱'; $PALANG['pAdminList_admin_domain'] = '域'; $PALANG['pAdminList_admin_username'] = '管理员'; $PALANG['pAdminList_admin_count'] = '管理域数量'; $PALANG['pAdminList_admin_modified'] = '最后修改日期'; $PALANG['pAdminList_admin_active'] = '活动'; $PALANG['pAdminList_domain_domain'] = '域'; $PALANG['pAdminList_domain_description'] = '描述'; $PALANG['pAdminList_domain_aliases'] = '别名数'; $PALANG['pAdminList_domain_mailboxes'] = '邮箱数'; $PALANG['pAdminList_domain_maxquota'] = '最大容量限制 (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; # XXX $PALANG['pAdminList_domain_modified'] = '最后修改日期'; $PALANG['pAdminList_domain_active'] = '活动'; $PALANG['pAdminList_virtual_button'] = '执行'; $PALANG['pAdminList_virtual_welcome'] = '域概览 域名: '; $PALANG['pAdminList_virtual_alias_alias_count'] = '别名数量'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = '邮箱数'; $PALANG['pAdminList_virtual_alias_address'] = '前往'; $PALANG['pAdminList_virtual_alias_goto'] = '转到'; $PALANG['pAdminList_virtual_alias_modified'] = '最后修改日期'; $PALANG['pAdminList_virtual_mailbox_username'] = '邮箱'; $PALANG['pAdminList_virtual_mailbox_name'] = '姓名'; $PALANG['pAdminList_virtual_mailbox_quota'] = '限制 (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = '最后修改日期'; $PALANG['pAdminList_virtual_mailbox_active'] = '活动'; $PALANG['pAdminCreate_domain_welcome'] = '新建域'; $PALANG['pAdminCreate_domain_domain'] = '域名'; $PALANG['pAdminCreate_domain_domain_text_error'] = '该域已经存在!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'The domain is invalid!'; # XXX $PALANG['pAdminCreate_domain_description'] = '描述'; $PALANG['pAdminCreate_domain_aliases'] = '别名数'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = 禁用 | 0 = 无限制'; $PALANG['pAdminCreate_domain_mailboxes'] = '邮箱数'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = 禁用 | 0 = 无限制'; $PALANG['pAdminCreate_domain_maxquota'] = '最大容量限制'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = 禁用 | 0 = 无限制'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Define transport'; # XXX $PALANG['pAdminCreate_domain_defaultaliases'] = '增加默认别名'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = '备份邮件服务器'; $PALANG['pAdminCreate_domain_button'] = '新增'; $PALANG['pAdminCreate_domain_result_error'] = '新增域失败!'; $PALANG['pAdminCreate_domain_result_success'] = '新增域成功!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Unable to remove domain!'; # XXX $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = '修改域'; $PALANG['pAdminEdit_domain_domain'] = '域名'; $PALANG['pAdminEdit_domain_description'] = '描述'; $PALANG['pAdminEdit_domain_aliases'] = '别名数'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = 禁止 | 0 = 无限制'; $PALANG['pAdminEdit_domain_mailboxes'] = '邮箱数'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = 禁止 | 0 = 无限制'; $PALANG['pAdminEdit_domain_maxquota'] = '最大容量限制'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = 禁止 | 0 = 无限制'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminEdit_domain_transport_text'] = 'Define transport'; # XXX $PALANG['pAdminEdit_domain_backupmx'] = '备份邮件服务器'; $PALANG['pAdminEdit_domain_active'] = '活动'; $PALANG['pAdminEdit_domain_button'] = '修改'; $PALANG['pAdminEdit_domain_result_error'] = '修改域失败!'; $PALANG['pAdminCreate_admin_welcome'] = '新增域管理员'; $PALANG['pAdminCreate_admin_username'] = '管理员'; $PALANG['pAdminCreate_admin_username_text'] = '邮件地址'; $PALANG['pAdminCreate_admin_username_text_error1'] = '邮件地址
管理员名不是一个合法的邮件地址!'; $PALANG['pAdminCreate_admin_username_text_error2'] = '邮件地址
管理员已经存在或者管理员名非法!'; $PALANG['pAdminCreate_admin_password'] = '密码'; $PALANG['pAdminCreate_admin_password2'] = '密码 (验证)'; $PALANG['pAdminCreate_admin_password_text_error'] = '新所输入的两次新密码不相同!
或者为空!
'; $PALANG['pAdminCreate_admin_button'] = '新增'; $PALANG['pAdminCreate_admin_result_error'] = '新增管理员失败!'; $PALANG['pAdminCreate_admin_result_success'] = '新增管理员成功!'; $PALANG['pAdminCreate_admin_address'] = '域'; $PALANG['pAdminEdit_admin_welcome'] = '修改域管理员'; $PALANG['pAdminEdit_admin_username'] = '管理员'; $PALANG['pAdminEdit_admin_password'] = '密码'; $PALANG['pAdminEdit_admin_password2'] = '密码 (验证)'; $PALANG['pAdminEdit_admin_password_text_error'] = '你两次输入的新密码不相同!
或者为空!
'; $PALANG['pAdminEdit_admin_active'] = '活动'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super admin'; # XXX $PALANG['pAdminEdit_admin_button'] = '修改'; $PALANG['pAdminEdit_admin_result_error'] = '编辑域管理员失败!'; $PALANG['pAdminEdit_admin_result_success'] = '编辑域管理员成功!'; $PALANG['pUsersLogin_welcome'] = '邮件用户从这里登录管理你的密码和别名.'; $PALANG['pUsersLogin_username'] = '帐号 (邮箱地址)'; $PALANG['pUsersLogin_password'] = '密码'; $PALANG['pUsersLogin_button'] = '登录'; $PALANG['pUsersLogin_username_incorrect'] = '登录失败. 请确认你是使用你的邮箱地址登录!'; $PALANG['pUsersLogin_password_incorrect'] = '登录密码不正确!'; $PALANG['pUsersMenu_vacation'] = '自动回复'; $PALANG['pUsersMenu_edit_alias'] = '修改转发'; $PALANG['pUsersMenu_password'] = '修改密码'; $PALANG['pUsersMain_vacation'] = '设置外出信息或自动回复.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' is ON, click \'' . $PALANG['pUsersMenu_vacation'] . '\' to ' . $PALANG['edit'] . '/remove'; # XXX $PALANG['pUsersMain_edit_alias'] = '修改邮箱转发.'; $PALANG['pUsersMain_password'] = '修改当前密码.'; $PALANG['pUsersVacation_welcome'] = '自动回复.'; $PALANG['pUsersVacation_welcome_text'] = '你已经设置了自动回复!'; $PALANG['pUsersVacation_subject'] = '主题'; $PALANG['pUsersVacation_subject_text'] = '我现在无法回信'; $PALANG['pUsersVacation_body'] = '内容'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << 这段时间内暂时无法回信. 如果你有急事请与 联系. EOM; $PALANG['pUsersVacation_button_away'] = '开启自动回复'; $PALANG['pUsersVacation_button_back'] = '关闭自动回复'; $PALANG['pUsersVacation_result_error'] = '更新自动回复失败!'; $PALANG['pUsersVacation_result_success'] = '你的自动回复已经关闭!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = '新建邮箱'; $PALANG['pCreate_dbLog_createalias'] = '新建别名'; $PALANG['pDelete_dbLog_deletealias'] = '删除别名'; $PALANG['pDelete_dbLog_deletemailbox'] = '邮件邮箱'; $PALANG['pEdit_dbLog_editactive'] = '改变活动状态'; $PALANG['pEdit_dbLog_editalias'] = '编辑别名'; $PALANG['pEdit_dbLog_editmailbox'] = '编辑邮箱'; $PALANG['pSearch'] = 'search'; # XXX $PALANG['pSearch_welcome'] = '搜索: '; $PALANG['pReturn_to'] = 'Return to'; # XXX $PALANG['pBroadcast_title'] = 'Send broadcast message'; # XXX $PALANG['pBroadcast_from'] = 'From'; # XXX $PALANG['pBroadcast_name'] = 'Your name'; # XXX $PALANG['pBroadcast_subject'] = 'Subject'; # XXX $PALANG['pBroadcast_message'] = 'Message'; # XXX $PALANG['pBroadcast_send'] = 'Send message'; # XXX $PALANG['pBroadcast_success'] = 'Your broadcast message was sent.'; # XXX $PALANG['pAdminMenu_broadcast_message'] = 'Broadcast message'; # XXX $PALANG['pBroadcast_error_empty'] = 'The fields Name, Subject and Message should\'t be empty !'; # XXX $PALANG['pStatus_undeliverable'] = 'maybe UNDELIVERABLE '; # XXX $PALANG['pStatus_custom'] = 'Delivers to '; # XXX $PALANG['pStatus_popimap'] = 'POP/IMAP '; # XXX $PALANG['pPasswordTooShort'] = "Password is too short - requires %s characters"; # XXX $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Fetch mail for:'; # XXX $PALANG['pFetchmail_new_entry'] = 'New entry'; # XXX $PALANG['pFetchmail_database_save_error'] = 'Could not save this entry in the database!'; # XXX $PALANG['pFetchmail_database_save_success'] = 'Entry saved in database.'; # XXX $PALANG['pFetchmail_error_invalid_id'] = 'No entry with ID %s found!'; # XXX $PALANG['pFetchmail_invalid_mailbox'] = 'Invalid mailbox!'; # XXX $PALANG['pFetchmail_server_missing'] = 'Please enter the remote server name!'; # XXX $PALANG['pFetchmail_user_missing'] = 'Please enter the remote username!'; # XXX $PALANG['pFetchmail_password_missing'] = 'Please enter the remote password!'; # XXX $PALANG['pFetchmail_field_id'] = 'ID'; # XXX $PALANG['pFetchmail_field_mailbox'] = 'Mailbox'; # XXX $PALANG['pFetchmail_field_src_server'] = 'Server'; # XXX $PALANG['pFetchmail_field_src_auth'] = 'Auth Type'; # XXX $PALANG['pFetchmail_field_src_user'] = 'User'; # XXX $PALANG['pFetchmail_field_src_password'] = 'Password'; # XXX $PALANG['pFetchmail_field_src_folder'] = 'Folder'; # XXX $PALANG['pFetchmail_field_poll_time'] = 'Poll'; # XXX $PALANG['pFetchmail_field_fetchall'] = 'Fetch All'; # XXX $PALANG['pFetchmail_field_keep'] = 'Keep'; # XXX $PALANG['pFetchmail_field_protocol'] = 'Protocol'; # XXX $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra Options'; # XXX $PALANG['pFetchmail_field_mda'] = 'MDA'; # XXX $PALANG['pFetchmail_field_date'] = 'Date'; # XXX $PALANG['pFetchmail_field_returned_text'] = 'Returned Text'; # XXX $PALANG['pFetchmail_desc_id'] = 'Record ID'; # XXX $PALANG['pFetchmail_desc_mailbox'] = 'Local mailbox'; # XXX $PALANG['pFetchmail_desc_src_server'] = 'Remote Server'; # XXX $PALANG['pFetchmail_desc_src_auth'] = 'Mostly \'password\''; # Translators: Please do NOT translate 'password' here # XXX $PALANG['pFetchmail_desc_src_user'] = 'Remote User'; # XXX $PALANG['pFetchmail_desc_src_password'] = 'Remote Password'; # XXX $PALANG['pFetchmail_desc_src_folder'] = 'Remote Folder'; # XXX $PALANG['pFetchmail_desc_poll_time'] = 'Poll every ... minutes'; # XXX $PALANG['pFetchmail_desc_fetchall'] = 'Retrieve both old (seen) and new messages'; # XXX $PALANG['pFetchmail_desc_keep'] = 'Keep retrieved messages on the remote mailserver'; # XXX $PALANG['pFetchmail_desc_protocol'] = 'Protocol to use'; # XXX $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Extra fetchmail Options'; # XXX $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; # XXX $PALANG['pFetchmail_desc_date'] = 'Date of last polling/configuration change'; # XXX $PALANG['pFetchmail_desc_returned_text'] = 'Text message from last polling'; # XXX $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/fr.lang0000664000175000017620000006631011636730120017504 0ustar davidpalepurpleImpossible d\'effacer cette entrée '; $PALANG['pDelete_delete_success'] = '%s supprimé.'; $PALANG['pDelete_postdelete_error'] = 'Impossible d\'effacer ce compte courriel'; $PALANG['pDelete_domain_error'] = 'Ce domaine n\'est pas le votre '; $PALANG['pDelete_domain_alias_error'] = 'Ce domaine n\'est pas le votre '; $PALANG['pDelete_alias_error'] = 'Impossible d\'effacer cet alias '; $PALANG['pCreate_alias_domain_welcome'] = 'Les adresses mirroirs de l\'un de vos domaines vers un autre.'; $PALANG['pCreate_alias_domain_alias'] = 'Alias Domaine'; $PALANG['pCreate_alias_domain_alias_text'] = 'Le domaine dans lequel les courriels viennent.'; $PALANG['pCreate_alias_domain_target'] = 'Domaine Cible'; $PALANG['pCreate_alias_domain_target_text'] = 'Le domaine o les mails doivent aller.'; $PALANG['pCreate_alias_domain_active'] = 'Activé'; $PALANG['pCreate_alias_domain_button'] = 'Ajouter un Alias de Domaine'; $PALANG['pCreate_alias_domain_error1'] = 'Vous n\'etes pas autorisé a créer la configuration choisie.'; $PALANG['pCreate_alias_domain_error2'] = 'La configuration choisie est invalide, merci d\'en choisir une autre!'; $PALANG['pCreate_alias_domain_error3'] = 'Insertion dans la base de donnée échouée.'; $PALANG['pCreate_alias_domain_error4'] = 'Tous les domaines sont déj liés un alias.'; $PALANG['pCreate_alias_domain_success'] = 'L\'alias de domaine est déj prsent dans la table de domaine!'; $PALANG['pCreate_alias_welcome'] = 'Créer un nouvel alias pour votre domaine.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
Cet ALIAS n\'est pas valide!'; $PALANG['pCreate_alias_address_text_error2'] = '
Ce compte courriel existe déjà, choisissez un autre libellé !'; $PALANG['pCreate_alias_address_text_error3'] = '
Vous avez atteint votre limite d\'alias créés !'; $PALANG['pCreate_alias_goto'] = 'À'; $PALANG['pCreate_alias_active'] = 'Activé'; $PALANG['pCreate_alias_button'] = 'Ajouter un alias'; $PALANG['pCreate_alias_goto_text'] = 'Destinataires des courriels.'; $PALANG['pCreate_alias_goto_text_error'] = 'Destinataires des courriels.
le champ À contient des erreurs!'; $PALANG['pCreate_alias_result_error'] = 'Impossible d\'ajouter cet alias dans la table !'; $PALANG['pCreate_alias_result_success'] = 'L\'alias a été ajouté !'; $PALANG['pCreate_alias_catchall_text'] = 'Pour ajouter un alias global, utilisez "*".
Pour un transfert de domaine à domaine, utilisez "*@domain.tld" dans le champs A.'; $PALANG['pEdit_alias_welcome'] = 'Modifier un alias dans votre domaine.
Une entrée par ligne.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Impossible de localiser l\'alias!'; $PALANG['pEdit_alias_goto'] = 'À'; $PALANG['pEdit_alias_active'] = 'Activé'; $PALANG['pEdit_alias_goto_text_error1'] = 'Vous devez entrer quelques choses dans le champ À'; $PALANG['pEdit_alias_goto_text_error2'] = 'L\'adresse courriel que vous avez entré est invalide: '; $PALANG['pEdit_alias_domain_error'] = 'Ce domaine n\'est pas le votre: '; $PALANG['pEdit_alias_domain_result_error'] = 'Impossible de modifier cet alias de domaine!'; $PALANG['pEdit_alias_forward_and_store'] = 'Transferer une copie.'; $PALANG['pEdit_alias_forward_only'] = 'Transferer les messages sans conserver de copie.'; $PALANG['pEdit_alias_button'] = 'Modifier cet alias'; $PALANG['pEdit_alias_result_error'] = 'Impossible de modifier cet alias!'; $PALANG['pCreate_mailbox_welcome'] = 'Ajouter un nouveau compte courriel à votre domaine.'; $PALANG['pCreate_mailbox_username'] = 'Nom d\'utilisateur'; $PALANG['pCreate_mailbox_username_text_error1'] = '
L\'adresse courriel est invalide!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Ce compte courriel existe deja ! Entrez une autre adresse courriel !'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Vous avez atteint le nombre maximum de compte courriel !'; $PALANG['pCreate_mailbox_password'] = 'Mot de passe'; $PALANG['pCreate_mailbox_password2'] = 'Mot de passe (confirmation)'; $PALANG['pCreate_mailbox_password_text'] = 'Mot de passe pour compte POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Mot de passe pour compte POP3/IMAP
Les mots de passe ne correspondent pas !
ou sont vide !
'; $PALANG['pCreate_mailbox_name'] = 'Nom'; $PALANG['pCreate_mailbox_name_text'] = 'Nom complet'; $PALANG['pCreate_mailbox_quota'] = 'Limite'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
La limite que vous avez specifie est trop haute!'; $PALANG['pCreate_mailbox_active'] = 'Actif'; $PALANG['pCreate_mailbox_mail'] = 'Envoyer le message de bienvenue'; $PALANG['pCreate_mailbox_button'] = 'Ajouter le compte courriel'; $PALANG['pCreate_mailbox_result_error'] = 'Impossible d\'ajouter un compte courriel dans la table!'; $PALANG['pCreate_mailbox_result_success'] = 'Le compte courriel a été ajouté!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'Le compte courriel a été ajouté à la table, mais un ou plusieurs dossiers prédéfinis n\'ont pu être créés !'; $PALANG['pEdit_mailbox_welcome'] = 'Modifier un compte courriel.'; $PALANG['pEdit_mailbox_username'] = 'Nom d\'utilisateur'; $PALANG['pEdit_mailbox_username_error'] = 'Impossible de localiser le compte courriel!'; $PALANG['pEdit_mailbox_password'] = 'Nouveau mot de passe'; $PALANG['pEdit_mailbox_password2'] = 'Nouveau mot de passe (confirmation)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Le mot de passe entré ne correspond pas!'; $PALANG['pEdit_mailbox_name'] = 'Nom'; $PALANG['pEdit_mailbox_name_text'] = 'Nom complet'; $PALANG['pEdit_mailbox_quota'] = 'Limite'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
La limite fournit est trop haute!'; $PALANG['pEdit_mailbox_domain_error'] = 'Ce domaine n\'est pas le votre: '; $PALANG['pEdit_mailbox_button'] = 'Modifier un compte courriel'; $PALANG['pEdit_mailbox_result_error'] = 'Impossible de modifier le compte courriel !'; $PALANG['pPassword_welcome'] = 'Changer votre mot de passe.'; $PALANG['pPassword_admin'] = 'Entrer'; $PALANG['pPassword_admin_text_error'] = 'Les informations entrées ne correspondent pas a un compte courriel!'; $PALANG['pPassword_password_current'] = 'Mot de passe actuel'; $PALANG['pPassword_password_current_text_error'] = 'Vous n\'avez pas fournit le mot de passe actuel !'; $PALANG['pPassword_password'] = 'Nouveau mot de passe'; $PALANG['pPassword_password2'] = 'Nouveau mot de passe (confirmation)'; $PALANG['pPassword_password_text_error'] = 'Le mot de passe fournit ne correspond pas!
Ou est vide!
'; $PALANG['pPassword_button'] = 'Changer le mot de passe'; $PALANG['pPassword_result_error'] = 'Impossible de changer votre mot de passe!'; $PALANG['pPassword_result_success'] = 'Votre mot de passe a été change!'; $PALANG['pEdit_vacation_set'] = 'Modifier le message'; $PALANG['pEdit_vacation_remove'] = 'Effacer le message'; $PALANG['pVacation_result_error'] = 'Impossible de mettre à jour les réglages du répondeur!'; $PALANG['pVacation_result_removed'] = 'Le répondeur a été désactivé!'; $PALANG['pVacation_result_added'] = 'Le répondeur a été activé!'; $PALANG['pViewlog_welcome'] = 'Visualiser les 10 dernières action pour '; $PALANG['pViewlog_timestamp'] = 'Date/Heure'; $PALANG['pViewlog_username'] = 'Administrateur'; $PALANG['pViewlog_domain'] = 'Domaine'; $PALANG['pViewlog_action'] = 'Action'; $PALANG['pViewlog_data'] = 'Information'; $PALANG['pViewlog_action_create_mailbox'] = 'créer un compte courriel'; $PALANG['pViewlog_action_delete_mailbox'] = 'supprimer un compte courriel'; $PALANG['pViewlog_action_edit_mailbox'] = 'éditer un compte courriel'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'activer un compte courriel'; $PALANG['pViewlog_action_create_alias'] = 'créer un alias'; $PALANG['pViewlog_action_create_alias_domain'] = 'créer un alias de domaine'; $PALANG['pViewlog_action_delete_alias'] = 'supprimer un alias'; $PALANG['pViewlog_action_delete_alias_domain'] = 'supprimer un alias de domaine'; $PALANG['pViewlog_action_edit_alias'] = 'éditer un alias'; $PALANG['pViewlog_action_edit_alias_state'] = 'activer un alias'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'editer alias de domaine actif'; $PALANG['pViewlog_action_edit_password'] = 'changer le mot de passe'; $PALANG['pViewlog_button'] = 'Aller'; $PALANG['pViewlog_result_error'] = 'Impossible de trouver le journal des événements!'; $PALANG['pSendmail_welcome'] = 'Envoyer un courriel.'; $PALANG['pSendmail_admin'] = 'De'; $PALANG['pSendmail_to'] = 'À'; $PALANG['pSendmail_to_text_error'] = 'À est vide ou ce n\'est pas une adresse courriel valide!'; $PALANG['pSendmail_subject'] = 'Sujet'; $PALANG['pSendmail_subject_text'] = 'Bienvenue'; $PALANG['pSendmail_body'] = 'Message'; $PALANG['pSendmail_button'] = 'Envoyer le message'; $PALANG['pSendmail_result_error'] = 'Erreur lors de l\'envoit du message!'; $PALANG['pSendmail_result_success'] = 'Le message a été envoyé!'; $PALANG['pAdminMenu_list_admin'] = 'Liste Administrateurs'; $PALANG['pAdminMenu_list_domain'] = 'Liste Domaines'; $PALANG['pAdminMenu_list_virtual'] = 'Liste Virtuels'; $PALANG['pAdminMenu_viewlog'] = 'Visualiser événements'; $PALANG['pAdminMenu_backup'] = 'Sauvegarde'; $PALANG['pAdminMenu_create_domain_admins'] = 'Administrateurs de domaines'; $PALANG['pAdminMenu_create_admin'] = 'Nouvel administrateur'; $PALANG['pAdminMenu_create_domain'] = 'Nouveau domaine'; $PALANG['pAdminMenu_create_alias'] = 'Ajouter un Alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Ajouter un compte courriel'; $PALANG['pAdminList_admin_domain'] = 'Domaine'; $PALANG['pAdminList_admin_username'] = 'Administrateur'; $PALANG['pAdminList_admin_count'] = 'Domaines'; $PALANG['pAdminList_admin_modified'] = 'Dernière modification'; $PALANG['pAdminList_admin_active'] = 'Actif'; $PALANG['pAdminList_domain_domain'] = 'Domaine'; $PALANG['pAdminList_domain_description'] = 'Description'; $PALANG['pAdminList_domain_aliases'] = 'Alias'; $PALANG['pAdminList_domain_mailboxes'] = 'Comptes courriels'; $PALANG['pAdminList_domain_maxquota'] = 'Limite maximum (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; $PALANG['pAdminList_domain_backupmx'] = 'MX Backup'; $PALANG['pAdminList_domain_modified'] = 'Dernière modification'; $PALANG['pAdminList_domain_active'] = 'Actif'; $PALANG['pAdminList_virtual_button'] = 'Aller'; $PALANG['pAdminList_virtual_welcome'] = 'Vue générale pour '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Alias'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Comptes courriels'; $PALANG['pAdminList_virtual_alias_address'] = 'De'; $PALANG['pAdminList_virtual_alias_goto'] = 'À'; $PALANG['pAdminList_virtual_alias_modified'] = 'Dernière modification'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Adresse courriel'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Nom'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Limite (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Dernière modification'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Actif'; $PALANG['pAdminCreate_domain_welcome'] = 'Ajouter un nouveau domaine'; $PALANG['pAdminCreate_domain_domain'] = 'Domaine'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Le domaine existe déjà!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'Le domaine est non valide!'; $PALANG['pAdminCreate_domain_description'] = 'Description'; $PALANG['pAdminCreate_domain_aliases'] = 'Alias'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = désactivé | 0 = illimité'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Comptes courriels'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = désactivé | 0 = illimité'; $PALANG['pAdminCreate_domain_maxquota'] = 'Limite maximum'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = désactivé | 0 = illimité'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Definir le transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Ajouter les alias par défaut'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'Le serveur est un "backup MX"'; $PALANG['pAdminCreate_domain_button'] = 'Ajouter un domaine'; $PALANG['pAdminCreate_domain_result_error'] = 'Impossible d\'ajouter le domaine!'; $PALANG['pAdminCreate_domain_result_success'] = 'Le domaine a été ajouté!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Impossible de supprimer le domain!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Impossible de supprimé cet alias de domaine!'; $PALANG['pAdminEdit_domain_welcome'] = 'Modifier un domaine'; $PALANG['pAdminEdit_domain_domain'] = 'Domaine'; $PALANG['pAdminEdit_domain_description'] = 'Description'; $PALANG['pAdminEdit_domain_aliases'] = 'Alias'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = désactivé | 0 = illimité'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Comptes courriels'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = désactivé | 0 = illimité'; $PALANG['pAdminEdit_domain_maxquota'] = 'Limite maximum'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = désactivé | 0 = illimité'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Definir le transport'; $PALANG['pAdminEdit_domain_backupmx'] = 'Le serveur est un "backup MX"'; $PALANG['pAdminEdit_domain_active'] = 'Actif'; $PALANG['pAdminEdit_domain_button'] = 'Modifier un domaine'; $PALANG['pAdminEdit_domain_result_error'] = 'Impossible de modifier le domain!'; $PALANG['pAdminCreate_admin_welcome'] = 'Ajouter un nouvel administrateur de domaine'; $PALANG['pAdminCreate_admin_username'] = 'Administrateur'; $PALANG['pAdminCreate_admin_username_text'] = 'adresse courriel'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Ce n\'est pas une adresse courriel administrateur valide!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Cet adresse courriel administrateur existe déjà ou n\'est pas valide'; $PALANG['pAdminCreate_admin_password'] = 'Mot de passe'; $PALANG['pAdminCreate_admin_password2'] = 'Mot de passe (confirmation)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Le mot de passe fournit ne correspond pas
ou est vide!
'; $PALANG['pAdminCreate_admin_button'] = 'Ajouter un administrateur'; $PALANG['pAdminCreate_admin_result_error'] = 'Impossible d\'ajouter un administrateur!'; $PALANG['pAdminCreate_admin_result_success'] = 'L\'administrateur a été ajouté!'; $PALANG['pAdminCreate_admin_address'] = 'Domaine'; $PALANG['pAdminEdit_admin_welcome'] = 'Modifier un domaine'; $PALANG['pAdminEdit_admin_username'] = 'Administrateur'; $PALANG['pAdminEdit_admin_password'] = 'Mot de passe'; $PALANG['pAdminEdit_admin_password2'] = 'Mot de passe(confirmation)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Le mot de passe fournit ne correspond pas
ou est vide!
'; $PALANG['pAdminEdit_admin_active'] = 'Actif'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super administrateur'; $PALANG['pAdminEdit_admin_button'] = 'Modifier l\administrateur'; $PALANG['pAdminEdit_admin_result_error'] = 'Impossible de modifier l\'administrateur !'; $PALANG['pAdminEdit_admin_result_success'] = 'L\'administrateur a été ajouté!'; $PALANG['pUsersLogin_welcome'] = 'Entrer votre adresse courriel pour modifier votre mot de passe et vos transferts.'; $PALANG['pUsersLogin_username'] = 'Adresse courriel'; $PALANG['pUsersLogin_password'] = 'Mot de passe'; $PALANG['pUsersLogin_button'] = 'Entrer'; $PALANG['pUsersLogin_username_incorrect'] = 'L\'adresse courriel est invalide. Assurez-vous d\'avoir correctement saisie votre adresse courriel!'; $PALANG['pUsersLogin_password_incorrect'] = 'Votre mot de passe est invalide!'; $PALANG['pUsersMenu_vacation'] = 'Réponse Automatique'; $PALANG['pUsersMenu_edit_alias'] = 'Modifier votre transfert'; $PALANG['pUsersMenu_password'] = 'Modifier votre mot de passe'; $PALANG['pUsersMain_vacation'] = 'Configurer votre répondeur automatique.'; $PALANG['pUsersMain_vacationSet'] = 'La ' . $PALANG['pUsersMenu_vacation'] . ' est activée, cliquer \'' . $PALANG['pUsersMenu_vacation'] . '\' pour ' . $PALANG['edit'] . '/effacer'; $PALANG['pUsersMain_edit_alias'] = 'Modifier vos transferts de courriel.'; $PALANG['pUsersMain_password'] = 'Changer votre mot de passe.'; $PALANG['pUsersVacation_welcome'] = 'Répondeur Automatique.'; $PALANG['pUsersVacation_welcome_text'] = 'Votre repondeur automatique est déjà configuré!'; $PALANG['pUsersVacation_subject'] = 'Sujet'; $PALANG['pUsersVacation_subject_text'] = 'En dehors du bureau'; $PALANG['pUsersVacation_body'] = 'Message'; $PALANG['pUsersVacation_body_text'] = << jusqu\'au . Pour toute urgence, merci de contacter . EOM; $PALANG['pUsersVacation_button_away'] = 'Absence'; $PALANG['pUsersVacation_button_back'] = 'De retour'; $PALANG['pUsersVacation_result_error'] = 'Impossible de mettre à jour vos paramètres de réponse automatique!'; $PALANG['pUsersVacation_result_success'] = 'Votre réponse automatique a été enlevée!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'Création de compte'; $PALANG['pCreate_dbLog_createalias'] = 'Création d\'alias'; $PALANG['pDelete_dbLog_deletealias'] = 'Suppression d\'alias'; $PALANG['pDelete_dbLog_deletemailbox'] = 'Suppression de compte'; $PALANG['pEdit_dbLog_editactive'] = 'Changement du statut d\'activation'; $PALANG['pEdit_dbLog_editalias'] = 'Modificaton d\'alias'; $PALANG['pEdit_dbLog_editmailbox'] = 'Modification de compte'; $PALANG['pSearch'] = 'Rechercher'; $PALANG['pSearch_welcome'] = 'Recherche : '; $PALANG['pReturn_to'] = 'Réponse à'; $PALANG['pBroadcast_title'] = 'Envoyer un message général'; $PALANG['pBroadcast_from'] = 'De'; $PALANG['pBroadcast_name'] = 'Votre nom'; $PALANG['pBroadcast_subject'] = 'Sujet'; $PALANG['pBroadcast_message'] = 'Message'; $PALANG['pBroadcast_send'] = 'Envoyer le message'; $PALANG['pBroadcast_success'] = 'Votre message général a été envoyé.'; $PALANG['pAdminMenu_broadcast_message'] = 'message général'; $PALANG['pBroadcast_error_empty'] = 'Les champs Nom, Sujet et Message ne peuvent pas être vides!'; $PALANG['pStatus_undeliverable'] = 'Non délivrable '; $PALANG['pStatus_custom'] = 'Délivré à '; $PALANG['pStatus_popimap'] = 'POP/IMAP '; $PALANG['pPasswordTooShort'] = "Mot de passe trop court. - %s caractères minimum"; $PALANG['pInvalidDomainRegex'] = "Nom de Domaine Invalide %s, vérification regexp impossible"; $PALANG['pInvalidDomainDNS'] = "Domaine Invalide %s, et/ou non resolvable via les DNS"; $PALANG['pInvalidMailRegex'] = "Adresse email invalide, vérification regexp impossible"; $PALANG['pFetchmail_welcome'] = 'Récupérer le courrier pour :'; $PALANG['pFetchmail_new_entry'] = 'Nouvelle entrée'; $PALANG['pFetchmail_database_save_error'] = 'Impossible d\'enregistrer cette entrée dans la base!'; $PALANG['pFetchmail_database_save_success'] = 'Entrée enregistrée dans la base.'; $PALANG['pFetchmail_error_invalid_id'] = 'Aucune entrée trouvée avec l\'ID %s!'; $PALANG['pFetchmail_invalid_mailbox'] = 'Compte courriel incorrect!'; $PALANG['pFetchmail_server_missing'] = 'Merci d\'entrer le nom du serveur distant!'; $PALANG['pFetchmail_user_missing'] = 'Merci d\'entrer le nom de l\'utilisateur distant!'; $PALANG['pFetchmail_password_missing'] = 'Merci d\'entrer le mot de passe distant!'; $PALANG['pFetchmail_field_id'] = 'ID'; $PALANG['pFetchmail_field_mailbox'] = 'Compte courriel'; $PALANG['pFetchmail_field_src_server'] = 'Serveur'; $PALANG['pFetchmail_field_src_auth'] = 'Type Auth'; $PALANG['pFetchmail_field_src_user'] = 'Utilisateur'; $PALANG['pFetchmail_field_src_password'] = 'Mot de passe'; $PALANG['pFetchmail_field_src_folder'] = 'Dossier'; $PALANG['pFetchmail_field_poll_time'] = 'Fréquence'; $PALANG['pFetchmail_field_fetchall'] = 'Tout récupérer'; $PALANG['pFetchmail_field_keep'] = 'Conserver'; $PALANG['pFetchmail_field_protocol'] = 'Protocole'; $PALANG['pFetchmail_field_usessl'] = 'SSL activé'; $PALANG['pFetchmail_field_extra_options'] = 'Options supplémentaires'; $PALANG['pFetchmail_field_mda'] = 'MDA'; $PALANG['pFetchmail_field_date'] = 'Date'; $PALANG['pFetchmail_field_returned_text'] = 'Message retour'; $PALANG['pFetchmail_desc_id'] = 'Identifiant'; $PALANG['pFetchmail_desc_mailbox'] = 'Compte courriel local'; $PALANG['pFetchmail_desc_src_server'] = 'Serveur distant'; $PALANG['pFetchmail_desc_src_auth'] = 'Surtout \'password\''; # Translators: Please do NOT translate 'password' here $PALANG['pFetchmail_desc_src_user'] = 'Utilisateur distant'; $PALANG['pFetchmail_desc_src_password'] = 'Mot de passe distant'; $PALANG['pFetchmail_desc_src_folder'] = 'Dossier distant'; $PALANG['pFetchmail_desc_poll_time'] = 'Vérifier toutes les ... minutes'; $PALANG['pFetchmail_desc_fetchall'] = 'Récupérer tous les messages, nouveaux et déjà lus'; $PALANG['pFetchmail_desc_keep'] = 'Conserver une copie des messages sur le serveur'; $PALANG['pFetchmail_desc_protocol'] = 'Protocole à utiliser'; $PALANG['pFetchmail_desc_usessl'] = 'Encryption SSL'; $PALANG['pFetchmail_desc_extra_options'] = 'Options supplémentaires de Fetchmail'; $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; $PALANG['pFetchmail_desc_date'] = 'Date dernière vérification/changement configuration'; $PALANG['pFetchmail_desc_returned_text'] = 'Message dernière vérification'; $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/sv.lang0000664000175000017620000006371111636730120017527 0ustar davidpalepurple // updated by Bjorne // updated by Jan Örnstedt (ornstedt @sf) // updated by Bachman Kharazmi bachman@tor.lindesign.se $PALANG['YES'] = 'JA'; $PALANG['NO'] = 'NEJ'; $PALANG['edit'] = 'ändra'; $PALANG['del'] = 'radera'; $PALANG['exit'] = 'Avbryt'; $PALANG['cancel'] = 'Avbryt'; $PALANG['save'] = 'Spara'; $PALANG['confirm'] = 'Är du säker på att du vill radera denna?\n'; $PALANG['confirm_domain'] = 'Vill du verkligen radera all data för denna domän? Kan ej ångras!\n'; $PALANG['check_update'] = 'Senaste versionen?'; $PALANG['invalid_parameter'] = 'Felaktig parameter!'; $PALANG['pFooter_logged_as'] = 'Inloggad som %s'; $PALANG['pLogin_welcome'] = 'Mail administratörer loggar in här för att sköta er domän.'; $PALANG['pLogin_username'] = 'Login (epost)'; $PALANG['pLogin_password'] = 'Lösenord'; $PALANG['pLogin_button'] = 'Login'; $PALANG['pLogin_failed'] = 'Your email address or password are not correct.'; # XXX $PALANG['pLogin_login_users'] = 'Användare klickar här för att logga in på användardelen.'; $PALANG['pMenu_main'] = 'Huvudmeny'; $PALANG['pMenu_overview'] = 'Sammanfattning'; $PALANG['pMenu_create_alias'] = 'Lägg till alias'; $PALANG['pMenu_create_alias_domain'] = 'Add Alias Domain'; # XXX $PALANG['pMenu_create_mailbox'] = 'Lägg till brevlåda'; $PALANG['pMenu_fetchmail'] = 'Hämta mail'; $PALANG['pMenu_sendmail'] = 'Skicka mail'; $PALANG['pMenu_password'] = 'Lösenord'; $PALANG['pMenu_viewlog'] = 'Visa logg'; $PALANG['pMenu_logout'] = 'Logga ut'; $PALANG['pMain_welcome'] = 'Välkommen till Postfix Admin!'; $PALANG['pMain_overview'] = 'Lista dina alias och brevlådan. Du kan ändra / radera dem här.'; $PALANG['pMain_create_alias'] = 'Skapa nytt alias i din domän.'; $PALANG['pMain_create_mailbox'] = 'Skapa ny brevlåda i din domän.'; $PALANG['pMain_sendmail'] = 'Skicka ett mail till en av mailadresserna.'; $PALANG['pMain_password'] = 'Ändra lösenord för adminkontot.'; $PALANG['pMain_viewlog'] = 'Visa loggfiler.'; $PALANG['pMain_logout'] = 'Logga ut från systemet'; $PALANG['pOverview_disabled'] = 'Avstängd'; $PALANG['pOverview_unlimited'] = 'Obegränsat'; $PALANG['pOverview_title'] = ':: Deklarerade domäner'; $PALANG['pOverview_up_arrow'] = 'Tillbaka till början'; $PALANG['pOverview_right_arrow'] = 'Nästa sida'; $PALANG['pOverview_left_arrow'] = 'Föregående sida'; $PALANG['pOverview_alias_domain_title'] = ':: Domain Aliases'; # XXX $PALANG['pOverview_alias_title'] = ':: Alias'; $PALANG['pOverview_mailbox_title'] = ':: Brevlådor'; $PALANG['pOverview_button'] = 'Visa'; $PALANG['pOverview_welcome'] = 'Sammanfattning för '; $PALANG['pOverview_alias_domain_aliases'] = 'Alias Domains'; # XXX $PALANG['pOverview_alias_domain_target'] = '%s is an Alias Domain for:'; # XXX $PALANG['pOverview_alias_alias_count'] = 'Alias'; $PALANG['pOverview_alias_mailbox_count'] = 'Brevlådor'; $PALANG['pOverview_alias_address'] = 'Från'; $PALANG['pOverview_alias_goto'] = 'Till'; $PALANG['pOverview_alias_modified'] = 'Senast Ändrad'; $PALANG['pOverview_alias_domain_modified'] = 'Last Modified'; # XXX $PALANG['pOverview_alias_active'] = 'Aktiv'; $PALANG['pOverview_alias_domain_active'] = 'Active'; # XXX $PALANG['pOverview_alias_edit'] = 'Alias'; $PALANG['and_x_more'] = '[och %s mer...]'; $PALANG['pOverview_mailbox_username'] = 'Epost'; $PALANG['pOverview_mailbox_name'] = 'Namn'; $PALANG['pOverview_mailbox_quota'] = 'Quota (MB)'; $PALANG['pOverview_mailbox_modified'] = 'Senast Ändrad'; $PALANG['pOverview_mailbox_active'] = 'Aktiv'; $PALANG['pOverview_vacation_edit'] = 'LEDIGHET ÄR AKTIVERAT'; $PALANG['pOverview_vacation_option'] = 'Aktivera ledighet'; $PALANG['pOverview_get_domain'] = 'Domän'; $PALANG['pOverview_get_aliases'] = 'Alias'; $PALANG['pOverview_get_alias_domains'] = 'Domain Aliases'; # XXX $PALANG['pOverview_get_mailboxes'] = 'Brevlåda'; $PALANG['pOverview_get_quota'] = 'Kvot för brevlåda (MB)'; $PALANG['pOverview_get_modified'] = 'Senast Ändrad'; $PALANG['pDelete_delete_error'] = 'Kan inte radera data för '; $PALANG['pDelete_delete_success'] = '%s borttagen.'; $PALANG['pDelete_postdelete_error'] = 'Kunde inte tabort brevlåda '; $PALANG['pDelete_domain_error'] = 'Detta är inte din domän '; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = 'Kunde inte tabort alias '; $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = 'Skapa nytt alias för din domän.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
Detta ALIAS är inte giltigt!'; $PALANG['pCreate_alias_address_text_error2'] = '
Denna epostadress existerar redan, välj en annan epostadress!'; $PALANG['pCreate_alias_address_text_error3'] = '
Du har redan högsta tillåtna antal alias definierade!'; $PALANG['pCreate_alias_goto'] = 'Till'; $PALANG['pCreate_alias_active'] = 'Aktiv'; $PALANG['pCreate_alias_button'] = 'Lägg till alias'; $PALANG['pCreate_alias_goto_text'] = 'Vart skall mailen skickas.'; $PALANG['pCreate_alias_goto_text_error'] = 'Vart mailen skall skickas.
TILL data är felaktigt!'; $PALANG['pCreate_alias_result_error'] = 'Kan inte lägga till detta alias i aliastabellen!'; $PALANG['pCreate_alias_result_success'] = 'Aliaset har lagts till i aliastabellen!'; $PALANG['pCreate_alias_catchall_text'] = 'För att skapa en catch-all ange ett "*" som alias.
För domän till domän forwarding använd "*@domän.tld" som till.'; $PALANG['pEdit_alias_welcome'] = 'Ändra ett alias för din domän.
Ett alias per rad.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Kan inte hitta detta alias!'; $PALANG['pEdit_alias_goto'] = 'Till'; $PALANG['pEdit_alias_active'] = 'Aktiv'; $PALANG['pEdit_alias_goto_text_error1'] = 'Du angav inget i Till'; $PALANG['pEdit_alias_goto_text_error2'] = 'Epost adressen du angivit är felaktig: '; $PALANG['pEdit_alias_domain_error'] = 'Detta är inte din domän: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Leverera till lokal brevlåda.'; $PALANG['pEdit_alias_forward_only'] = 'Vidarebefodra till angiven epost endast.'; $PALANG['pEdit_alias_button'] = 'Ändra alias'; $PALANG['pEdit_alias_result_error'] = 'Kan inte modifiera detta alias!'; $PALANG['pCreate_mailbox_welcome'] = 'Skapa ett nytt lokalt brevlåda i din domän.'; $PALANG['pCreate_mailbox_username'] = 'Epostadress'; $PALANG['pCreate_mailbox_username_text_error1'] = '
EPOSTADRESSEN är inte korrekt!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Denna epostadress finns redan, ange en annan adress!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Du har redan skapat max tillåtet antal brevlådan!'; $PALANG['pCreate_mailbox_password'] = 'Lösenord'; $PALANG['pCreate_mailbox_password2'] = 'Lösenord (igen)'; $PALANG['pCreate_mailbox_password_text'] = 'Lösenord för POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Lösenord för POP3/IMAP
Lösenorden du angivit är olika!
Eller tomma!
'; $PALANG['pCreate_mailbox_name'] = 'Namn'; $PALANG['pCreate_mailbox_name_text'] = 'Fullständigt namn'; $PALANG['pCreate_mailbox_quota'] = 'Quota'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Quotan du angivit är för stor!'; $PALANG['pCreate_mailbox_active'] = 'Aktiv'; $PALANG['pCreate_mailbox_mail'] = 'Skicka välkomstbrev'; $PALANG['pCreate_mailbox_button'] = 'Lägg till brevlåda'; $PALANG['pCreate_mailbox_result_error'] = 'Kan ej lägga till brevlådat i tabellen för konton!'; $PALANG['pCreate_mailbox_result_success'] = 'Mailkontot har lagts till!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'Brevlådan har lagts till i tabellen mailbox, men inga (eller få) av de fördefinierade underkatalogerna kunde skapas'; $PALANG['pEdit_mailbox_welcome'] = 'Ändra ett brevlåda i din domän.'; $PALANG['pEdit_mailbox_username'] = 'Epostadress'; $PALANG['pEdit_mailbox_username_error'] = 'Kan inte hitta den adressen!'; $PALANG['pEdit_mailbox_password'] = 'Nytt Lösenord'; $PALANG['pEdit_mailbox_password2'] = 'Nytt Lösenord (igen)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Lösenorden du angav är olika!'; $PALANG['pEdit_mailbox_name'] = 'Namn'; $PALANG['pEdit_mailbox_name_text'] = 'Fullständigt namn'; $PALANG['pEdit_mailbox_quota'] = 'Quota'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Quotagränsen du angett är för stor!'; $PALANG['pEdit_mailbox_domain_error'] = 'Detta är inte din domän: '; $PALANG['pEdit_mailbox_button'] = 'Ändra brevlåda'; $PALANG['pEdit_mailbox_result_error'] = 'Kan inte ändra lösenordet!'; $PALANG['pPassword_welcome'] = 'Ändra ditt lösenord.'; $PALANG['pPassword_admin'] = 'Login'; $PALANG['pPassword_admin_text_error'] = 'Det LOGIN du angivit har ingen mailbox kopplad till sig!'; $PALANG['pPassword_password_current'] = 'Nuvarande Lösenord'; $PALANG['pPassword_password_current_text_error'] = 'Du angav ej korrekt lösenord!'; $PALANG['pPassword_password'] = 'Nytt Lösenord'; $PALANG['pPassword_password2'] = 'Nytt Lösenord (igen)'; $PALANG['pPassword_password_text_error'] = 'Lösenorden du angav var olika!
Eller är tomma!
'; $PALANG['pPassword_button'] = 'Ändra Lösenord'; $PALANG['pPassword_result_error'] = 'Kan inte ändra ditt lösenord!'; $PALANG['pPassword_result_success'] = 'Ditt lösenord har ändrats!'; $PALANG['pEdit_vacation_set'] = 'Ändra / Aktivera meddelande för ledighet'; $PALANG['pEdit_vacation_remove'] = 'Tabort meddelande för ledighet'; $PALANG['pVacation_result_error'] = 'Kunde inte uppdatera autosvar inställningar!'; $PALANG['pVacation_result_removed'] = 'Autosvar meddelande har tagits bort!'; $PALANG['pVacation_result_added'] = 'Autosvar meddelande har aktiverats!'; $PALANG['pViewlog_welcome'] = 'Visa dom senaste 10 åtgärderna för '; $PALANG['pViewlog_timestamp'] = 'Tidpunkt'; $PALANG['pViewlog_username'] = 'Admin'; $PALANG['pViewlog_domain'] = 'Domän'; $PALANG['pViewlog_action'] = 'Åtgärd'; $PALANG['pViewlog_data'] = 'Data'; $PALANG['pViewlog_action_create_mailbox'] = 'skapa brevlåda'; $PALANG['pViewlog_action_delete_mailbox'] = 'radera brevlåda'; $PALANG['pViewlog_action_edit_mailbox'] = 'ändra brevlåda'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'ändra brevlåde status'; $PALANG['pViewlog_action_create_alias'] = 'skapa alias'; $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'radera alias'; $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'ändra alias'; $PALANG['pViewlog_action_edit_alias_state'] = 'ändra alias status'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'ändra lösenord'; $PALANG['pViewlog_button'] = 'Kör'; $PALANG['pViewlog_result_error'] = 'Kan inte hitta loggarna!'; $PALANG['pSendmail_welcome'] = 'Skicka ett mail.'; $PALANG['pSendmail_admin'] = 'Från'; $PALANG['pSendmail_to'] = 'Till'; $PALANG['pSendmail_to_text_error'] = 'Till är en ogiltig mailadress eller tomt.!'; $PALANG['pSendmail_subject'] = 'Ämne'; $PALANG['pSendmail_subject_text'] = 'Välkommen'; $PALANG['pSendmail_body'] = 'Meddelande'; $PALANG['pSendmail_button'] = 'Skicka'; $PALANG['pSendmail_result_error'] = 'Mailet kunde inte skickas!'; $PALANG['pSendmail_result_success'] = 'Mailet har skickats!'; $PALANG['pAdminMenu_list_admin'] = 'Administratörer'; $PALANG['pAdminMenu_list_domain'] = 'Domäner'; $PALANG['pAdminMenu_list_virtual'] = 'Epostadresser'; $PALANG['pAdminMenu_viewlog'] = 'Visa loggfil'; $PALANG['pAdminMenu_backup'] = 'Backup'; $PALANG['pAdminMenu_create_domain_admins'] = 'Domän admins'; $PALANG['pAdminMenu_create_admin'] = 'Ny admin'; $PALANG['pAdminMenu_create_domain'] = 'Ny domän'; $PALANG['pAdminMenu_create_alias'] = 'Lägg till alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Lägg till brevlåda'; $PALANG['pAdminList_admin_domain'] = 'Domän'; $PALANG['pAdminList_admin_username'] = 'Admin'; $PALANG['pAdminList_admin_count'] = 'Domäner'; $PALANG['pAdminList_admin_modified'] = 'Senast ändrad'; $PALANG['pAdminList_admin_active'] = 'Aktiv'; $PALANG['pAdminList_domain_domain'] = 'Domän'; $PALANG['pAdminList_domain_description'] = 'Beskrivning'; $PALANG['pAdminList_domain_aliases'] = 'Alias'; $PALANG['pAdminList_domain_mailboxes'] = 'Brevlåda'; $PALANG['pAdminList_domain_maxquota'] = 'Max Quota (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; $PALANG['pAdminList_domain_modified'] = 'Senast modifierad'; $PALANG['pAdminList_domain_active'] = 'Aktiv'; $PALANG['pAdminList_virtual_button'] = 'Kör'; $PALANG['pAdminList_virtual_welcome'] = 'Sammanfattning för '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Alias'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Mailboxar'; $PALANG['pAdminList_virtual_alias_address'] = 'Från'; $PALANG['pAdminList_virtual_alias_goto'] = 'Till'; $PALANG['pAdminList_virtual_alias_modified'] = 'Senast ändrad'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Epostadress'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Namn'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Quota (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Senast ändrad'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Aktiv'; $PALANG['pAdminCreate_domain_welcome'] = 'Lägg till ny domän'; $PALANG['pAdminCreate_domain_domain'] = 'Domän'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Den domänen finns redan!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'Domänen är ogiltig!'; $PALANG['pAdminCreate_domain_description'] = 'Beskrivning'; $PALANG['pAdminCreate_domain_aliases'] = 'Alias'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = avaktivera | 0 = obegränsat'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Brevlåda'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = avaktivera | 0 = obegränsat'; $PALANG['pAdminCreate_domain_maxquota'] = 'Max Quota'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = avaktivera | 0 = obegränsat'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Definiera transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Skapa standard alias'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'Mailserver är backup MX'; $PALANG['pAdminCreate_domain_button'] = 'Lägg till domän'; $PALANG['pAdminCreate_domain_result_error'] = 'Kan inte skapa domänen!'; $PALANG['pAdminCreate_domain_result_success'] = 'Domänen har skapats!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Kunde inte tabort domän!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = 'Ändra en domän'; $PALANG['pAdminEdit_domain_domain'] = 'Domän'; $PALANG['pAdminEdit_domain_description'] = 'Beskrivning'; $PALANG['pAdminEdit_domain_aliases'] = 'Alias'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = avaktivera | 0 = obegränsat'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Brevlåda'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = avaktivera | 0 = obegränsat'; $PALANG['pAdminEdit_domain_maxquota'] = 'Max Quota'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = avaktivera | 0 = obegränsat'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Definiera transport'; $PALANG['pAdminEdit_domain_backupmx'] = 'Mail server is backup MX'; $PALANG['pAdminEdit_domain_active'] = 'Aktiv'; $PALANG['pAdminEdit_domain_button'] = 'Ändra domän'; $PALANG['pAdminEdit_domain_result_error'] = 'Kan inte modifiera domänen!'; $PALANG['pAdminCreate_admin_welcome'] = 'Lägg till ny domänadmin'; $PALANG['pAdminCreate_admin_username'] = 'Admin'; $PALANG['pAdminCreate_admin_username_text'] = 'Epostadress'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Epostadress
Admin är inte en giltig epostadress!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Epostadress
Denna admin finns redan eller är inte giltig'; $PALANG['pAdminCreate_admin_password'] = 'Lösenord'; $PALANG['pAdminCreate_admin_password2'] = 'Lösenord (igen)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Lösenorden du angav är olika!
Eller är tomma!
'; $PALANG['pAdminCreate_admin_button'] = 'Lägg till admin'; $PALANG['pAdminCreate_admin_result_error'] = 'Kan inte lägga till admin!'; $PALANG['pAdminCreate_admin_result_success'] = 'Admin har lagts till!'; $PALANG['pAdminCreate_admin_address'] = 'Domän'; $PALANG['pAdminEdit_admin_welcome'] = 'Ändra en domänadmin'; $PALANG['pAdminEdit_admin_username'] = 'Admin'; $PALANG['pAdminEdit_admin_password'] = 'Lösenord'; $PALANG['pAdminEdit_admin_password2'] = 'Lösenord (igen)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Lösenorden du angav är olika!
Eller är tomma!
'; $PALANG['pAdminEdit_admin_active'] = 'Aktiv'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super administratör'; $PALANG['pAdminEdit_admin_button'] = 'Ändra admin'; $PALANG['pAdminEdit_admin_result_error'] = 'Kan inte ändra admin!'; $PALANG['pAdminEdit_admin_result_success'] = 'Admin har ändrats!'; $PALANG['pUsersLogin_welcome'] = 'Mailbox användare logga in här för att ändra ert lösenord och alias.'; $PALANG['pUsersLogin_username'] = 'Login (epostadress)'; $PALANG['pUsersLogin_password'] = 'Lösenord'; $PALANG['pUsersLogin_button'] = 'Login'; $PALANG['pUsersLogin_username_incorrect'] = 'Ditt login är felaktigt. Logga in med din epostadress!'; $PALANG['pUsersLogin_password_incorrect'] = 'Ditt lösenord är felaktigt!'; $PALANG['pUsersMenu_vacation'] = 'Autosvar'; $PALANG['pUsersMenu_edit_alias'] = 'Ändra din forwardadress'; $PALANG['pUsersMenu_password'] = 'Ändra Lösenord'; $PALANG['pUsersMain_vacation'] = 'Ställ in ett "out of office" meddelande eller autosvar för din epost.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' är AKTIVERAT, klicka \'' . $PALANG['pUsersMenu_vacation'] . '\' för att ' . $PALANG['edit'] . '/tabort'; $PALANG['pUsersMain_edit_alias'] = 'Ändra din epost forwardadress.'; $PALANG['pUsersMain_password'] = 'Ändra ditt nuvarande lösenord.'; $PALANG['pUsersVacation_welcome'] = 'Autosvar.'; $PALANG['pUsersVacation_welcome_text'] = 'Du har redan ett autosvar meddelande definierat!'; $PALANG['pUsersVacation_subject'] = 'Ärende'; $PALANG['pUsersVacation_subject_text'] = 'Out of Office'; $PALANG['pUsersVacation_body'] = 'Text'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << till . För brådskande ärenden kan ni kontakta . EOM; $PALANG['pUsersVacation_button_away'] = 'Försvinner'; $PALANG['pUsersVacation_button_back'] = 'Kommer tillbaka'; $PALANG['pUsersVacation_result_error'] = 'Kan inte uppdatera dina autosvar inställningar!'; $PALANG['pUsersVacation_result_success'] = 'Ditt autosvar har taqits bort!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'skapa brevlåda'; $PALANG['pCreate_dbLog_createalias'] = 'skapa alias'; $PALANG['pDelete_dbLog_deletealias'] = 'radera alias'; $PALANG['pDelete_dbLog_deletemailbox'] = 'radera brevlåda'; $PALANG['pEdit_dbLog_editactive'] = 'ändra aktiv status'; $PALANG['pEdit_dbLog_editalias'] = 'ändra alias'; $PALANG['pEdit_dbLog_editmailbox'] = 'ändra brevlåda'; $PALANG['pSearch'] = 'sök'; $PALANG['pSearch_welcome'] = 'Söker efter: '; $PALANG['pReturn_to'] = 'Återvänd till'; $PALANG['pBroadcast_title'] = 'Grupputskick till alla'; $PALANG['pBroadcast_from'] = 'Från'; $PALANG['pBroadcast_name'] = 'Ditt namn'; $PALANG['pBroadcast_subject'] = 'Ämne'; $PALANG['pBroadcast_message'] = 'Meddelande'; $PALANG['pBroadcast_send'] = 'Skicka'; $PALANG['pBroadcast_success'] = 'Ditt grupputskick har sänts.'; $PALANG['pAdminMenu_broadcast_message'] = 'Grupputskick'; $PALANG['pBroadcast_error_empty'] = 'Fälten namn, ämne och meddelande skall inte vara tomma!'; $PALANG['pStatus_undeliverable'] = 'kanske misslyckades leverera '; $PALANG['pStatus_custom'] = 'Levereras till '; $PALANG['pStatus_popimap'] = 'POP/IMAP '; $PALANG['pPasswordTooShort'] = "För kort lösenord - ett lösenord på %s tecken krävs"; $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Hämta mail för:'; $PALANG['pFetchmail_new_entry'] = 'Ny anteckning'; $PALANG['pFetchmail_database_save_error'] = 'Misslyckades med att spara anteckningen i databasen!'; $PALANG['pFetchmail_database_save_success'] = 'Anteckning sparad i databasen.'; $PALANG['pFetchmail_error_invalid_id'] = 'Ingen anteckning med ID %s hittades!'; $PALANG['pFetchmail_invalid_mailbox'] = 'Felaktig brevlåda!'; $PALANG['pFetchmail_server_missing'] = 'Var snäll och fyll i namnet till värddatorn!'; $PALANG['pFetchmail_user_missing'] = 'Var snäll och fyll i användarnamnet till värddatorn!'; $PALANG['pFetchmail_password_missing'] = 'Var snäll och fyll i lösenordet till värddatorn!'; $PALANG['pFetchmail_field_id'] = 'ID'; $PALANG['pFetchmail_field_mailbox'] = 'Mailkonto'; $PALANG['pFetchmail_field_src_server'] = 'Värddator'; $PALANG['pFetchmail_field_src_auth'] = 'Autentiseringstyp'; $PALANG['pFetchmail_field_src_user'] = 'Användarnamn'; $PALANG['pFetchmail_field_src_password'] = 'Lösenord'; $PALANG['pFetchmail_field_src_folder'] = 'Katalog'; $PALANG['pFetchmail_field_poll_time'] = 'Kontrollera'; $PALANG['pFetchmail_field_fetchall'] = 'Hämta samtliga'; $PALANG['pFetchmail_field_keep'] = 'Behåll'; $PALANG['pFetchmail_field_protocol'] = 'Protokoll'; $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra inställningsmöjligheter'; $PALANG['pFetchmail_field_mda'] = 'MDA'; $PALANG['pFetchmail_field_date'] = 'Datum'; $PALANG['pFetchmail_field_returned_text'] = 'Retur text'; $PALANG['pFetchmail_desc_id'] = 'Händelse ID'; $PALANG['pFetchmail_desc_mailbox'] = 'Lokal brevlåda'; $PALANG['pFetchmail_desc_src_server'] = 'Värddator'; $PALANG['pFetchmail_desc_src_auth'] = 'Oftast \'password\''; $PALANG['pFetchmail_desc_src_user'] = 'Användarnamn'; $PALANG['pFetchmail_desc_src_password'] = 'Lösenord'; $PALANG['pFetchmail_desc_src_folder'] = 'Katalog'; $PALANG['pFetchmail_desc_poll_time'] = 'Kontrollera varje ... minut'; $PALANG['pFetchmail_desc_fetchall'] = 'Hämta både gamla lästa (visade) brev och nya'; $PALANG['pFetchmail_desc_keep'] = 'Behåll hämtade brev på mailservern'; $PALANG['pFetchmail_desc_protocol'] = 'Använd följande protokoll'; $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Extra fetchmail inställningar'; $PALANG['pFetchmail_desc_mda'] = 'Mailserveragent (MDA)'; $PALANG['pFetchmail_desc_date'] = 'Datum för senaste kontroll/konfigurationsändring'; $PALANG['pFetchmail_desc_returned_text'] = 'Textmeddelande från senaste kontroll'; $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/hr.lang0000664000175000017620000006555311636730120017516 0ustar davidpalepurple // $PALANG['YES'] = 'DA'; $PALANG['NO'] = 'NE'; $PALANG['edit'] = 'uredi'; $PALANG['del'] = 'briši'; $PALANG['exit'] = 'Exit'; # XXX $PALANG['cancel'] = 'Cancel'; # XXX $PALANG['save'] = 'Save'; # XXX $PALANG['confirm'] = 'Da li ste sigurni da želite ovo pobrisati?\n'; $PALANG['confirm_domain'] = 'Da li ste sigurni da želite pobrisati sve zapise za tu domenu? Zapisi ce biti zauvijek pobrisani!\n'; $PALANG['check_update'] = 'Provjeri da li postoji novija inačica'; $PALANG['invalid_parameter'] = 'Invalid parameter!'; # XXX $PALANG['pFooter_logged_as'] = 'Logged as %s'; # XXX $PALANG['pLogin_welcome'] = 'Administratori prijavite se ovdje.'; $PALANG['pLogin_username'] = 'Korisničko ime (adresa e-pošte)'; $PALANG['pLogin_password'] = 'Lozinka'; $PALANG['pLogin_button'] = 'Prijavi'; $PALANG['pLogin_failed'] = 'Your email address or password are not correct.'; # XXX $PALANG['pLogin_login_users'] = 'Korisnici kliknite ovdje za prijavu u korisničku sekciju.'; $PALANG['pMenu_main'] = 'Main'; # XXX $PALANG['pMenu_overview'] = 'Pregled'; $PALANG['pMenu_create_alias'] = 'Dodaj alias'; $PALANG['pMenu_create_alias_domain'] = 'Add Alias Domain'; # XXX $PALANG['pMenu_create_mailbox'] = 'Dodaj poštanski ormarić'; $PALANG['pMenu_fetchmail'] = 'Fetch Email'; # XXX $PALANG['pMenu_sendmail'] = 'Pošlji e-poštu'; $PALANG['pMenu_password'] = 'Lozinka'; $PALANG['pMenu_viewlog'] = 'Pregledaj zapis'; $PALANG['pMenu_logout'] = 'Odjava'; $PALANG['pMain_welcome'] = 'Dobrodošli u Postfix Admin!'; $PALANG['pMain_overview'] = 'Izlistaj aliase i poštanske ormariće. Tu ih možete uređivati/brisati.'; $PALANG['pMain_create_alias'] = 'Stvori novi alias za domenu.'; $PALANG['pMain_create_mailbox'] = 'Stvori novi poštanski ormarić za domenu.'; $PALANG['pMain_sendmail'] = 'Pošali e-poštu u jedan od novostvorenih poštanskih ormarića.'; $PALANG['pMain_password'] = 'Promijeni Administratorsku lozinku.'; $PALANG['pMain_viewlog'] = 'Pogledaj datoteke sa zapisima.'; $PALANG['pMain_logout'] = 'Odjava iz sistema'; $PALANG['pOverview_disabled'] = 'Onesposobljen'; $PALANG['pOverview_unlimited'] = 'Bezgraničan'; $PALANG['pOverview_title'] = ':: Definirane domene'; $PALANG['pOverview_up_arrow'] = 'Na vrh'; $PALANG['pOverview_right_arrow'] = 'Slijedeća stranica'; $PALANG['pOverview_left_arrow'] = 'Prijašnja stranica'; $PALANG['pOverview_alias_domain_title'] = ':: Domain Aliases'; # XXX $PALANG['pOverview_alias_title'] = ':: Alias'; $PALANG['pOverview_mailbox_title'] = ':: Poštanski ormarići'; $PALANG['pOverview_button'] = 'Idi'; $PALANG['pOverview_welcome'] = 'Pregled za '; $PALANG['pOverview_alias_domain_aliases'] = 'Alias Domains'; # XXX $PALANG['pOverview_alias_domain_target'] = '%s is an Alias Domain for:'; # XXX $PALANG['pOverview_alias_alias_count'] = 'Aliasi'; $PALANG['pOverview_alias_mailbox_count'] = 'Poštanski ormarići'; $PALANG['pOverview_alias_address'] = 'Od'; $PALANG['pOverview_alias_goto'] = 'Za'; $PALANG['pOverview_alias_modified'] = 'Zadnja promjena'; $PALANG['pOverview_alias_domain_modified'] = 'Last Modified'; # XXX $PALANG['pOverview_alias_active'] = 'Active'; # XXX $PALANG['pOverview_alias_domain_active'] = 'Active'; # XXX $PALANG['pOverview_alias_edit'] = 'Alias'; # XXX $PALANG['and_x_more'] = '[and %s more...]'; # XXX $PALANG['pOverview_mailbox_username'] = 'E-pošta'; $PALANG['pOverview_mailbox_name'] = 'Ime'; $PALANG['pOverview_mailbox_quota'] = 'Kvota (MB)'; $PALANG['pOverview_mailbox_modified'] = 'Zadnja promjena'; $PALANG['pOverview_mailbox_active'] = 'Aktivan'; $PALANG['pOverview_vacation_edit'] = 'VACATION IS ON'; # XXX $PALANG['pOverview_vacation_option'] = 'Set Vacation'; # XXX $PALANG['pOverview_get_domain'] = 'Domena'; $PALANG['pOverview_get_aliases'] = 'Aliasi'; $PALANG['pOverview_get_alias_domains'] = 'Domain Aliases'; # XXX $PALANG['pOverview_get_mailboxes'] = 'Poštanski ormarići'; $PALANG['pOverview_get_quota'] = 'Kvota za poštanske ormariće (MB)'; $PALANG['pOverview_get_modified'] = 'Zadnja promjena'; $PALANG['pDelete_delete_error'] = 'Unos nije bilo moguče izbrisati '; $PALANG['pDelete_delete_success'] = '%s deleted.'; # XXX $PALANG['pDelete_postdelete_error'] = 'Unable to remove mailbox '; # XXX $PALANG['pDelete_domain_error'] = 'Izabrana domena nije pod vašim nadzorom '; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = 'Unable to delete alias '; # XXX $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = 'Stvori novi alias za domenu.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
ALIAS nije valjan!'; $PALANG['pCreate_alias_address_text_error2'] = '
Ova adresa e-pošte već postoji, molimo izaberite drugu!'; $PALANG['pCreate_alias_address_text_error3'] = '
Postigli ste maksimalan broj vaših aliasa!'; $PALANG['pCreate_alias_goto'] = 'Za'; $PALANG['pCreate_alias_active'] = 'Active'; # XXX $PALANG['pCreate_alias_button'] = 'Dodaj alias'; $PALANG['pCreate_alias_goto_text'] = 'Kuda poslati e-poštu.'; $PALANG['pCreate_alias_goto_text_error'] = 'Gdje e-pošta mora doći.
Unos "Za" je nepravilan!'; $PALANG['pCreate_alias_result_error'] = 'Nije bilo moguće dodati alias u tablicu aliasa!'; $PALANG['pCreate_alias_result_success'] = 'Alias je dodan u tablicu aliasa!'; $PALANG['pCreate_alias_catchall_text'] = 'Ukoliko želite stvoriti "sveprimajući" alias, upotrijebite "*" umjesto aliasa.
Za preusmjeravanje iz domene na domenu, upotrijebite "*@domena.tld" u "Za" polju.'; $PALANG['pEdit_alias_welcome'] = 'Uredi alias za domenu.
Jedan unos po liniji.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Alias nije bilo moguče naći!'; $PALANG['pEdit_alias_goto'] = 'Za'; $PALANG['pEdit_alias_active'] = 'Active'; # XXX $PALANG['pEdit_alias_goto_text_error1'] = 'U polje "Za" niste unijeli ništa!'; $PALANG['pEdit_alias_goto_text_error2'] = 'Adresa e-pošte, koju ste unijeli nije pravilna: '; $PALANG['pEdit_alias_domain_error'] = 'Izbrana domena nije pod vašim nadzorom: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Deliver to the local mailbox.'; # XXX $PALANG['pEdit_alias_forward_only'] = 'Forward to given email addresses only.'; # XXX $PALANG['pEdit_alias_button'] = 'Uredi alias'; $PALANG['pEdit_alias_result_error'] = 'Alias nije bilo moguče promjeniti!'; $PALANG['pCreate_mailbox_welcome'] = 'Stvori novi poštanski ormarić za izbranu domenu.'; $PALANG['pCreate_mailbox_username'] = 'Korisničko ime'; $PALANG['pCreate_mailbox_username_text_error1'] = '
Adresa e-pošte nije pravilna!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Ova adresa e-pošte već postoji, molimo izaberite drugu!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Dostigli ste vaš limit poštanskih ormarića!'; $PALANG['pCreate_mailbox_password'] = 'Lozinka'; $PALANG['pCreate_mailbox_password2'] = 'Lozinka (ponovi)'; $PALANG['pCreate_mailbox_password_text'] = 'Lozinka za POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Lozinka za POP3/IMAP
Unešene lozinke se ne podudaraju
ili su prazne!
'; $PALANG['pCreate_mailbox_name'] = 'Ime'; $PALANG['pCreate_mailbox_name_text'] = 'Puno ime'; $PALANG['pCreate_mailbox_quota'] = 'Kvota'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Unešena kvota je prevelika!'; $PALANG['pCreate_mailbox_active'] = 'Aktivan'; $PALANG['pCreate_mailbox_mail'] = 'Stvori poštanski ormarić'; $PALANG['pCreate_mailbox_button'] = 'Dodaj poštanski ormarić'; $PALANG['pCreate_mailbox_result_error'] = 'Poštanski ormarić nije moguče stvoriti!'; $PALANG['pCreate_mailbox_result_success'] = 'Poštanski ormarić je uspješno stvoren!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'The mailbox has been added to the mailbox table, but none (or only some) of the predefined sub-folders could be created'; # XXX $PALANG['pEdit_mailbox_welcome'] = 'Uredi poštanski ormarić za domenu.'; $PALANG['pEdit_mailbox_username'] = 'Korisničko ime'; $PALANG['pEdit_mailbox_username_error'] = 'Poštanski ormarić nije bilo moguče naći!'; $PALANG['pEdit_mailbox_password'] = 'Nova lozinka'; $PALANG['pEdit_mailbox_password2'] = 'Nova lozinka (ponovi)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Unešene lozinke se ne podudaraju!'; $PALANG['pEdit_mailbox_name'] = 'Ime'; $PALANG['pEdit_mailbox_name_text'] = 'Full name'; # XXX $PALANG['pEdit_mailbox_quota'] = 'Kvota'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Unešena kvota je prevelika!'; $PALANG['pEdit_mailbox_domain_error'] = 'Izbrana domena nije pod vašim nadzorom: '; $PALANG['pEdit_mailbox_button'] = 'Uredi poštanski ormarić'; $PALANG['pEdit_mailbox_result_error'] = 'Poštanski ormarić nije bilo moguče promjeniti!'; $PALANG['pPassword_welcome'] = 'Promijeni lozinku.'; $PALANG['pPassword_admin'] = 'Korisnicko ime'; $PALANG['pPassword_admin_text_error'] = 'Korisničko ime se ne podudara sa poštanskim ormarićem!'; $PALANG['pPassword_password_current'] = 'Trenutačna lozinka'; $PALANG['pPassword_password_current_text_error'] = 'Morate unijeti trenutačnu lozinku!'; $PALANG['pPassword_password'] = 'Nova lozinka'; $PALANG['pPassword_password2'] = 'Nova lozinka (ponovi)'; $PALANG['pPassword_password_text_error'] = 'Unešene lozinke se ne podudaraju
ili su prazne!
'; $PALANG['pPassword_button'] = 'Promijeni lozinku'; $PALANG['pPassword_result_error'] = 'Lozinku nije bilo moguče promijeniti!'; $PALANG['pPassword_result_success'] = 'Lozinka je uspješno promijenjena!'; $PALANG['pEdit_vacation_set'] = 'Change / Set away message'; # XXX $PALANG['pEdit_vacation_remove'] = 'Remove away message'; # XXX $PALANG['pVacation_result_error'] = 'Unable to update auto response settings!'; # XXX $PALANG['pVacation_result_removed'] = 'Auto response has been removed!'; # XXX $PALANG['pVacation_result_added'] = 'Auto response has been enabled!'; # XXX $PALANG['pViewlog_welcome'] = 'Pogledaj zadnjih 10 akcija za '; $PALANG['pViewlog_timestamp'] = 'Vrijeme'; $PALANG['pViewlog_username'] = 'Administrator'; $PALANG['pViewlog_domain'] = 'Domena'; $PALANG['pViewlog_action'] = 'Akcija'; $PALANG['pViewlog_data'] = 'Podaci'; $PALANG['pViewlog_action_create_mailbox'] = 'create mailbox'; # XXX $PALANG['pViewlog_action_delete_mailbox'] = 'delete mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox'] = 'edit mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox_state'] = 'edit mailbox active'; # XXX $PALANG['pViewlog_action_create_alias'] = 'create alias'; # XXX $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'delete alias'; # XXX $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'edit alias'; # XXX $PALANG['pViewlog_action_edit_alias_state'] = 'edit alias active'; # XXX $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'change password'; # XXX $PALANG['pViewlog_button'] = 'Idi'; $PALANG['pViewlog_result_error'] = 'Zapise nije bilo moguče naći!'; $PALANG['pSendmail_welcome'] = 'Pošlji e-poštu.'; $PALANG['pSendmail_admin'] = 'Od'; $PALANG['pSendmail_to'] = 'Za'; $PALANG['pSendmail_to_text_error'] = 'Polje "Za" ne sadrži valjanu adresu e-pošte!'; $PALANG['pSendmail_subject'] = 'Subjekt'; $PALANG['pSendmail_subject_text'] = 'Dobrodošli!'; $PALANG['pSendmail_body'] = 'Tekst'; $PALANG['pSendmail_button'] = 'Pošalji poruku'; $PALANG['pSendmail_result_error'] = 'Poštanski ormarić nije bilo moguče stvoriti!'; # XXX text change - new: Unable to send email! $PALANG['pSendmail_result_success'] = 'Poštanski ormarić je uspješno stvoren!'; # XXX text change - new: Email sent! $PALANG['pAdminMenu_list_admin'] = 'Lista administratora'; $PALANG['pAdminMenu_list_domain'] = 'Lista domena'; $PALANG['pAdminMenu_list_virtual'] = 'Lista aliasa in poštanskih ormarića'; $PALANG['pAdminMenu_viewlog'] = 'Pregled zapisa'; $PALANG['pAdminMenu_backup'] = 'Arhiviraj'; $PALANG['pAdminMenu_create_domain_admins'] = 'Domenski administratori'; $PALANG['pAdminMenu_create_admin'] = 'Novi administrator'; $PALANG['pAdminMenu_create_domain'] = 'Nova domena'; $PALANG['pAdminMenu_create_alias'] = 'Dodaj alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Dodaj poštanski ormarić'; $PALANG['pAdminList_admin_domain'] = 'Domena'; $PALANG['pAdminList_admin_username'] = 'Administrator'; $PALANG['pAdminList_admin_count'] = 'Domene'; $PALANG['pAdminList_admin_modified'] = 'Zadnja promjena'; $PALANG['pAdminList_admin_active'] = 'Aktivan'; $PALANG['pAdminList_domain_domain'] = 'Domena'; $PALANG['pAdminList_domain_description'] = 'Opis'; $PALANG['pAdminList_domain_aliases'] = 'Aliasi'; $PALANG['pAdminList_domain_mailboxes'] = 'Poštanski ormarići'; $PALANG['pAdminList_domain_maxquota'] = 'Maksimalna kvota (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; # XXX $PALANG['pAdminList_domain_modified'] = 'Zadnja promjena'; $PALANG['pAdminList_domain_active'] = 'Aktivan'; $PALANG['pAdminList_virtual_button'] = 'Idi'; $PALANG['pAdminList_virtual_welcome'] = 'Pregled za: '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Aliasi'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Poštanski ormarići'; $PALANG['pAdminList_virtual_alias_address'] = 'Od'; $PALANG['pAdminList_virtual_alias_goto'] = 'Za'; $PALANG['pAdminList_virtual_alias_modified'] = 'Zadnja promjena'; $PALANG['pAdminList_virtual_mailbox_username'] = 'E-pošta'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Ime'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Kvota (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Zadnja promjena'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Aktivan'; $PALANG['pAdminCreate_domain_welcome'] = 'Dodaj novu domenu'; $PALANG['pAdminCreate_domain_domain'] = 'Domena'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Unešena domena već postoji!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'The domain is invalid!'; # XXX $PALANG['pAdminCreate_domain_description'] = 'Opis'; $PALANG['pAdminCreate_domain_aliases'] = 'Aliasi'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = onemogući | 0 = bezgranično'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Poštanski ormarići'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = onemoguči | 0 = bezgranično'; $PALANG['pAdminCreate_domain_maxquota'] = 'Maksimalna kvota'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = onemogući | 0 = bezgranično'; $PALANG['pAdminCreate_domain_transport'] = 'Prijenos'; $PALANG['pAdminCreate_domain_transport_text'] = 'Definiraj prijenos'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Dodaj default aliase'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; # XXX $PALANG['pAdminCreate_domain_backupmx'] = 'Poslužitelj e-pošte je sekundarni MX'; $PALANG['pAdminCreate_domain_button'] = 'Dodaj domenu'; $PALANG['pAdminCreate_domain_result_error'] = 'Domenu nije bilo moguče dodati!'; $PALANG['pAdminCreate_domain_result_success'] = 'Domena je bila uspješno dodana!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Unable to remove domain!'; # XXX $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = 'Uredi domenu'; $PALANG['pAdminEdit_domain_domain'] = 'Domena'; $PALANG['pAdminEdit_domain_description'] = 'Opis'; $PALANG['pAdminEdit_domain_aliases'] = 'Aliasi'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = onemogući | 0 = bezgranično'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Poštanski ormarići'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = onemogući | 0 = bezgranično'; $PALANG['pAdminEdit_domain_maxquota'] = 'Maksimalna kvota'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = onemogući | 0 = bezgranično'; $PALANG['pAdminEdit_domain_transport'] = 'Prijenos'; $PALANG['pAdminEdit_domain_transport_text'] = 'Definiraj prijenos'; $PALANG['pAdminEdit_domain_backupmx'] = 'Poslužitelj e-pošte je sekundarni MX'; $PALANG['pAdminEdit_domain_active'] = 'Aktivan'; $PALANG['pAdminEdit_domain_button'] = 'Uredi domenu'; $PALANG['pAdminEdit_domain_result_error'] = 'Domenu nije bilo moguće premeniti!'; $PALANG['pAdminCreate_admin_welcome'] = 'Dodaj administratora domene'; $PALANG['pAdminCreate_admin_username'] = 'Administrator'; $PALANG['pAdminCreate_admin_username_text'] = 'Adresa e-pošte'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Adresa e-pošte
Administrator nije valjana adresa e-pošte!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Adresa e-pošte
Adminstrator već postoji ili nije valjan'; $PALANG['pAdminCreate_admin_password'] = 'Lozinka'; $PALANG['pAdminCreate_admin_password2'] = 'Lozinka (ponovi)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Unešene lozinke se ne podudaraju
ili su prazne!
'; $PALANG['pAdminCreate_admin_button'] = 'Dodaj administratora'; $PALANG['pAdminCreate_admin_result_error'] = 'Administratora nije bilo moguće dodati!'; $PALANG['pAdminCreate_admin_result_success'] = 'Admininstrator je uspješno dodan'; $PALANG['pAdminCreate_admin_address'] = 'Domena'; $PALANG['pAdminEdit_admin_welcome'] = 'Uredi administratora domene'; $PALANG['pAdminEdit_admin_username'] = 'Administrator'; $PALANG['pAdminEdit_admin_password'] = 'Lozinka'; $PALANG['pAdminEdit_admin_password2'] = 'Lozinka (ponovi)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Unešene lozinke se ne podudaraju
ili su prazne!
'; $PALANG['pAdminEdit_admin_active'] = 'Aktivan'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super admin'; # XXX $PALANG['pAdminEdit_admin_button'] = 'Uredi Administratora'; $PALANG['pAdminEdit_admin_result_error'] = 'Administratora nije bilo moguće promjeniti!'; $PALANG['pAdminEdit_admin_result_success'] = 'Admininstrator je uspješno promjenjen!'; $PALANG['pUsersLogin_welcome'] = 'Korisnici poštanskih ormarića ukoliko želite promjeniti lozinku ili aliase.'; $PALANG['pUsersLogin_username'] = 'Prijava (adresa e-pošte)'; $PALANG['pUsersLogin_password'] = 'Lozinka'; $PALANG['pUsersLogin_button'] = 'Prijava'; $PALANG['pUsersLogin_username_incorrect'] = 'Korisničko ime nije pravilno! Morate upotrijebiti adresu vaše e-pošte!'; $PALANG['pUsersLogin_password_incorrect'] = 'Lozinka nije pravilna!'; $PALANG['pUsersMenu_vacation'] = 'Obavijest o odsutnosti'; $PALANG['pUsersMenu_edit_alias'] = 'Promijeni preusmjerenje'; $PALANG['pUsersMenu_password'] = 'Promijeni lozinku'; $PALANG['pUsersMain_vacation'] = 'Promijenite obvijest o odsutnosti.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' is ON, click \'' . $PALANG['pUsersMenu_vacation'] . '\' to ' . $PALANG['edit'] . '/remove'; # XXX $PALANG['pUsersMain_edit_alias'] = 'Promijenite preusmjerenje na drugu adresu e-pošte.'; $PALANG['pUsersMain_password'] = 'Promijenite lozinku.'; $PALANG['pUsersVacation_welcome'] = 'Ovdje možete promijeniti obvijest o odsutnosti.'; $PALANG['pUsersVacation_welcome_text'] = 'Obvijest o odsutnosti je već postavljena!'; $PALANG['pUsersVacation_subject'] = 'Subjekt'; $PALANG['pUsersVacation_subject_text'] = 'Odsutnost'; $PALANG['pUsersVacation_body'] = 'Tekst'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << do sam odsutan. Za hitne stvari molim vas da kontaktirate . EOM; $PALANG['pUsersVacation_button_away'] = 'Uključi odsutnost'; $PALANG['pUsersVacation_button_back'] = 'Isključi odsutnost'; $PALANG['pUsersVacation_result_error'] = 'Nemoguće promijeniti vaše postavke o odsutnosti!'; $PALANG['pUsersVacation_result_success'] = 'Obvijest o odsutnosti je uklonjena!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'stvori poštanski ormarić'; $PALANG['pCreate_dbLog_createalias'] = 'stvori alias'; $PALANG['pDelete_dbLog_deletealias'] = 'pobriši alias'; $PALANG['pDelete_dbLog_deletemailbox'] = 'pobriši poštanski ormarić'; $PALANG['pEdit_dbLog_editactive'] = 'promijeni stanje aktivnosti'; $PALANG['pEdit_dbLog_editalias'] = 'uredi alias'; $PALANG['pEdit_dbLog_editmailbox'] = 'uredi poštanski oramrić'; $PALANG['pSearch'] = 'traži'; $PALANG['pSearch_welcome'] = 'Traži: '; $PALANG['pReturn_to'] = 'Return to'; # XXX $PALANG['pBroadcast_title'] = 'Send broadcast message'; # XXX $PALANG['pBroadcast_from'] = 'From'; # XXX $PALANG['pBroadcast_name'] = 'Your name'; # XXX $PALANG['pBroadcast_subject'] = 'Subject'; # XXX $PALANG['pBroadcast_message'] = 'Message'; # XXX $PALANG['pBroadcast_send'] = 'Send message'; # XXX $PALANG['pBroadcast_success'] = 'Your broadcast message was sent.'; # XXX $PALANG['pAdminMenu_broadcast_message'] = 'Broadcast message'; # XXX $PALANG['pBroadcast_error_empty'] = 'The fields Name, Subject and Message should\'t be empty !'; # XXX $PALANG['pStatus_undeliverable'] = 'maybe UNDELIVERABLE '; # XXX $PALANG['pStatus_custom'] = 'Delivers to '; # XXX $PALANG['pStatus_popimap'] = 'POP/IMAP '; # XXX $PALANG['pPasswordTooShort'] = "Password is too short - requires %s characters"; # XXX $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Fetch mail for:'; # XXX $PALANG['pFetchmail_new_entry'] = 'New entry'; # XXX $PALANG['pFetchmail_database_save_error'] = 'Could not save this entry in the database!'; # XXX $PALANG['pFetchmail_database_save_success'] = 'Entry saved in database.'; # XXX $PALANG['pFetchmail_error_invalid_id'] = 'No entry with ID %s found!'; # XXX $PALANG['pFetchmail_invalid_mailbox'] = 'Invalid mailbox!'; # XXX $PALANG['pFetchmail_server_missing'] = 'Please enter the remote server name!'; # XXX $PALANG['pFetchmail_user_missing'] = 'Please enter the remote username!'; # XXX $PALANG['pFetchmail_password_missing'] = 'Please enter the remote password!'; # XXX $PALANG['pFetchmail_field_id'] = 'ID'; # XXX $PALANG['pFetchmail_field_mailbox'] = 'Mailbox'; # XXX $PALANG['pFetchmail_field_src_server'] = 'Server'; # XXX $PALANG['pFetchmail_field_src_auth'] = 'Auth Type'; # XXX $PALANG['pFetchmail_field_src_user'] = 'User'; # XXX $PALANG['pFetchmail_field_src_password'] = 'Password'; # XXX $PALANG['pFetchmail_field_src_folder'] = 'Folder'; # XXX $PALANG['pFetchmail_field_poll_time'] = 'Poll'; # XXX $PALANG['pFetchmail_field_fetchall'] = 'Fetch All'; # XXX $PALANG['pFetchmail_field_keep'] = 'Keep'; # XXX $PALANG['pFetchmail_field_protocol'] = 'Protocol'; # XXX $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra Options'; # XXX $PALANG['pFetchmail_field_mda'] = 'MDA'; # XXX $PALANG['pFetchmail_field_date'] = 'Date'; # XXX $PALANG['pFetchmail_field_returned_text'] = 'Returned Text'; # XXX $PALANG['pFetchmail_desc_id'] = 'Record ID'; # XXX $PALANG['pFetchmail_desc_mailbox'] = 'Local mailbox'; # XXX $PALANG['pFetchmail_desc_src_server'] = 'Remote Server'; # XXX $PALANG['pFetchmail_desc_src_auth'] = 'Mostly \'password\''; # Translators: Please do NOT translate 'password' here # XXX $PALANG['pFetchmail_desc_src_user'] = 'Remote User'; # XXX $PALANG['pFetchmail_desc_src_password'] = 'Remote Password'; # XXX $PALANG['pFetchmail_desc_src_folder'] = 'Remote Folder'; # XXX $PALANG['pFetchmail_desc_poll_time'] = 'Poll every ... minutes'; # XXX $PALANG['pFetchmail_desc_fetchall'] = 'Retrieve both old (seen) and new messages'; # XXX $PALANG['pFetchmail_desc_keep'] = 'Keep retrieved messages on the remote mailserver'; # XXX $PALANG['pFetchmail_desc_protocol'] = 'Protocol to use'; # XXX $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Extra fetchmail Options'; # XXX $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; # XXX $PALANG['pFetchmail_desc_date'] = 'Date of last polling/configuration change'; # XXX $PALANG['pFetchmail_desc_returned_text'] = 'Text message from last polling'; # XXX $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/pl.lang0000664000175000017620000006404311636730120017511 0ustar davidpalepurple // updated by Lukasz Wasikowski // updated by Michal Wojcik // $PALANG['YES'] = 'Tak'; $PALANG['NO'] = 'Nie'; $PALANG['edit'] = 'Edytuj'; $PALANG['del'] = 'Usuń'; $PALANG['exit'] = 'Wyjdź'; $PALANG['cancel'] = 'Anuluj'; $PALANG['save'] = 'Zapisz'; $PALANG['confirm'] = 'Jesteś przekonany, że chcesz to usunąć?\n'; $PALANG['confirm_domain'] = 'Czy rzeczywiście chcesz usunąć wszystkie wpisy dla tej domeny? To jest proces nieodwracalny!\n'; $PALANG['check_update'] = 'Sprawdź aktualizację'; $PALANG['invalid_parameter'] = 'Błędny parametr!'; $PALANG['pFooter_logged_as'] = 'Zalogowano jako %s'; $PALANG['pLogin_welcome'] = 'Sekcja przeznaczona dla administratorów domen.'; $PALANG['pLogin_username'] = 'Login (email)'; $PALANG['pLogin_password'] = 'Hasło'; $PALANG['pLogin_button'] = 'Zaloguj'; $PALANG['pLogin_failed'] = 'Twój adres Email lub hasło jest niepoprawne.'; $PALANG['pLogin_login_users'] = 'Sekcja przeznaczona dla użytkowników.'; $PALANG['pMenu_main'] = 'Strona główna'; $PALANG['pMenu_overview'] = 'Dane zbiorcze'; $PALANG['pMenu_create_alias'] = 'Dodaj alias'; $PALANG['pMenu_create_alias_domain'] = 'Dodaj alias domeny'; $PALANG['pMenu_create_mailbox'] = 'Dodaj konto'; $PALANG['pMenu_fetchmail'] = 'Pobierz Email'; $PALANG['pMenu_sendmail'] = 'Wyślij Email'; $PALANG['pMenu_password'] = 'Hasło'; $PALANG['pMenu_viewlog'] = 'Logi'; $PALANG['pMenu_logout'] = 'Wyloguj'; $PALANG['pMain_welcome'] = 'Witamy w Postfix Adminie!'; $PALANG['pMain_overview'] = 'Lista Twoich aliasów i kont pocztowych. Możesz je tutaj edytować / usuwać.'; $PALANG['pMain_create_alias'] = 'Utwórz nowy alias dla Twojej domeny.'; $PALANG['pMain_create_mailbox'] = 'Utwórz nowe konto pocztowe dla Twojej domeny.'; $PALANG['pMain_sendmail'] = 'Wyślij wiadomość do nowo utworzonego konta pocztowego.'; $PALANG['pMain_password'] = 'Zmieć hasło swojego konta administracyjnego.'; $PALANG['pMain_viewlog'] = 'Pokaż pliki logów.'; $PALANG['pMain_logout'] = 'Zakończ pracę z systemem'; $PALANG['pOverview_disabled'] = 'Wyłączony'; $PALANG['pOverview_unlimited'] = 'Bez limitu'; $PALANG['pOverview_title'] = ':: Zdefiniowane domeny'; $PALANG['pOverview_up_arrow'] = 'Do góry'; $PALANG['pOverview_right_arrow'] = 'Następna strona'; $PALANG['pOverview_left_arrow'] = 'Poprzednia strona'; $PALANG['pOverview_alias_domain_title'] = ':: Aliasy domen'; $PALANG['pOverview_alias_title'] = ':: Aliasy'; $PALANG['pOverview_mailbox_title'] = ':: Konta pocztowe'; $PALANG['pOverview_button'] = 'Idź'; $PALANG['pOverview_welcome'] = 'Dane zbiorcze dla domeny '; $PALANG['pOverview_alias_domain_aliases'] = 'Domeny aliasowe'; $PALANG['pOverview_alias_domain_target'] = '%s jest domeną aliasową dla:'; $PALANG['pOverview_alias_alias_count'] = 'Alias'; $PALANG['pOverview_alias_mailbox_count'] = 'Konta'; $PALANG['pOverview_alias_address'] = 'Od'; $PALANG['pOverview_alias_goto'] = 'Do'; $PALANG['pOverview_alias_modified'] = 'Ostatnio zmodyfikowany'; $PALANG['pOverview_alias_domain_modified'] = 'Ostatnio zmodyfikowane'; $PALANG['pOverview_alias_active'] = 'Aktywny'; $PALANG['pOverview_alias_domain_active'] = 'Aktywny'; $PALANG['pOverview_alias_edit'] = 'Alias'; $PALANG['and_x_more'] = '[i %s wiecej...]'; $PALANG['pOverview_mailbox_username'] = 'Email'; $PALANG['pOverview_mailbox_name'] = 'Nazwa'; $PALANG['pOverview_mailbox_quota'] = 'Udział (MB)'; $PALANG['pOverview_mailbox_modified'] = 'Ostatnio zmodyfikowany'; $PALANG['pOverview_mailbox_active'] = 'Aktywny'; $PALANG['pOverview_vacation_edit'] = 'Auto odpowiedź'; $PALANG['pOverview_vacation_option'] = 'Ustaw automatyczną odpowiedź'; $PALANG['pOverview_get_domain'] = 'Domena'; $PALANG['pOverview_get_aliases'] = 'Aliasy'; $PALANG['pOverview_get_alias_domains'] = 'Aliasy domenowe'; $PALANG['pOverview_get_mailboxes'] = 'Konta'; $PALANG['pOverview_get_quota'] = 'Udział (MB)'; $PALANG['pOverview_get_modified'] = 'Ostatnio zmodyfikowany'; $PALANG['pDelete_delete_error'] = 'Nie można usunąć tego wpisu '; $PALANG['pDelete_delete_success'] = '%s usunięty.'; $PALANG['pDelete_postdelete_error'] = 'Nie można usunąć konta '; $PALANG['pDelete_domain_error'] = 'Ta domena nie należy do Ciebie '; $PALANG['pDelete_domain_alias_error'] = 'Ten alias domeny nie należy do Ciebie '; $PALANG['pDelete_alias_error'] = 'Nie można usunąć aliasu '; $PALANG['pCreate_alias_domain_welcome'] = 'Duplikuj adresy z jednej Twojej domeny do innej.'; $PALANG['pCreate_alias_domain_alias'] = 'Domena aliasowana/źródłowa'; $PALANG['pCreate_alias_domain_alias_text'] = 'Domena do której przychodzą maile.'; $PALANG['pCreate_alias_domain_target'] = 'Domena docelowa'; $PALANG['pCreate_alias_domain_target_text'] = 'Domena do której powinny przychodzić maile.'; $PALANG['pCreate_alias_domain_active'] = 'Aktywny'; $PALANG['pCreate_alias_domain_button'] = 'Dodaj alias domeny'; $PALANG['pCreate_alias_domain_error1'] = 'Nie masz uprawnień do tworzenia takiej konfiguracji.'; $PALANG['pCreate_alias_domain_error2'] = 'Wybrana konfiguracja jest nieprawidłowa, proszę wybrać inną!'; $PALANG['pCreate_alias_domain_error3'] = 'Dodanie do bazy nie powiodło się.'; $PALANG['pCreate_alias_domain_error4'] = 'Wszystkie domeny są już aliasowane.'; $PALANG['pCreate_alias_domain_success'] = 'Alias domeny został dodany do tabeli aliasów domen!'; $PALANG['pCreate_alias_welcome'] = 'Utwórz nowy alias dla Twojej domeny.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
Alias jest niepoprawny!'; $PALANG['pCreate_alias_address_text_error2'] = '
Taki adres email juz istnieje, proszę wybrać inny!'; $PALANG['pCreate_alias_address_text_error3'] = '
Twój limit aliasów został osiągniety!'; $PALANG['pCreate_alias_goto'] = 'Do'; $PALANG['pCreate_alias_active'] = 'Aktywny'; $PALANG['pCreate_alias_button'] = 'Dodaj alias'; $PALANG['pCreate_alias_goto_text'] = 'Gdzie ten mail powinien być wysłany.'; $PALANG['pCreate_alias_goto_text_error'] = 'Gdzie ten mail powinien dotrzeć.
Pole TO jest niepoprawne!'; $PALANG['pCreate_alias_result_error'] = 'Nie można dodać aliasu do tabeli aliasów!'; $PALANG['pCreate_alias_result_success'] = 'Alias został dodany do tabeli aliasów!'; $PALANG['pCreate_alias_catchall_text'] = 'Aby utworzyć domyślne konto dla domeny (catch-all) podaj "*" (gwiazdkę) jako alias.
Jeśli chcesz przekazywać całość poczty do innej domeny, wpisz jako alias "*@domena.tld".'; $PALANG['pEdit_alias_welcome'] = 'Edytuj alias dla Twojej domeny.
Jeden wpis na linię.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Nie można zokalizować aliasu!'; $PALANG['pEdit_alias_goto'] = 'Do'; $PALANG['pEdit_alias_active'] = 'Aktywny'; $PALANG['pEdit_alias_goto_text_error1'] = 'Nie podałeś adresu odbiorcy (pole "To")'; $PALANG['pEdit_alias_goto_text_error2'] = 'Wpisany adres email jest niepoprawny: '; $PALANG['pEdit_alias_domain_error'] = 'Ta domena nie należy do Ciebie: '; $PALANG['pEdit_alias_domain_result_error'] = 'Nie można zmodyfikować aliasu domeny!'; $PALANG['pEdit_alias_forward_and_store'] = 'Dostarczaj do mojej skrzynki.'; $PALANG['pEdit_alias_forward_only'] = 'Prześlij jedynie na podane adresy.'; $PALANG['pEdit_alias_button'] = 'Edytuj alias'; $PALANG['pEdit_alias_result_error'] = 'Nie można zmodyfikować aliasu!'; $PALANG['pCreate_mailbox_welcome'] = 'Utwórz lokalne konto pocztowe dla Twojej domeny.'; $PALANG['pCreate_mailbox_username'] = 'Nazwa użytkownika'; $PALANG['pCreate_mailbox_username_text_error1'] = '
Adres EMAIL jest niepoprawny!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Taki adres email już istnieje, proszę wybrać inny!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Twój limit kont pocztowych został osiągniety!'; $PALANG['pCreate_mailbox_password'] = 'Hasło'; $PALANG['pCreate_mailbox_password2'] = 'Hasło (ponownie)'; $PALANG['pCreate_mailbox_password_text'] = 'Hasło do POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Hasło do POP3/IMAP
Wpisane hasło nie pasuje!
Lub jest puste!
'; $PALANG['pCreate_mailbox_name'] = 'Nazwa'; $PALANG['pCreate_mailbox_name_text'] = 'Pełna nazwa'; $PALANG['pCreate_mailbox_quota'] = 'Udział'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Podany udział jest za wysoki!'; $PALANG['pCreate_mailbox_active'] = 'Aktywny'; $PALANG['pCreate_mailbox_mail'] = 'Utwórz konto'; $PALANG['pCreate_mailbox_button'] = 'Dodaj konto'; $PALANG['pCreate_mailbox_result_error'] = 'Nie można dodać konta do tabeli kont!'; $PALANG['pCreate_mailbox_result_success'] = 'Konto zostało dodane do tabeli kont!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'Konto zostało dodane do tabeli kont, ale żadne (lub tylko niektóre) z predefiniowanych folderów nie zostały utworzone'; $PALANG['pEdit_mailbox_welcome'] = 'Edytuj konto w Twojej domenie.'; $PALANG['pEdit_mailbox_username'] = 'Nazwa użytkownika'; $PALANG['pEdit_mailbox_username_error'] = 'Nie można zlokalizować konta!'; $PALANG['pEdit_mailbox_password'] = 'Nowe hasło'; $PALANG['pEdit_mailbox_password2'] = 'Nowe hasło (ponownie)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Wpisane hasło nie pasuje!'; $PALANG['pEdit_mailbox_name'] = 'Nazwa'; $PALANG['pEdit_mailbox_name_text'] = 'Pełna nazwa'; $PALANG['pEdit_mailbox_quota'] = 'Udział'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Podany udział jest za wysoki!'; $PALANG['pEdit_mailbox_domain_error'] = 'Ta domena nie należy do Ciebie: '; $PALANG['pEdit_mailbox_button'] = 'Edytuj konto'; $PALANG['pEdit_mailbox_result_error'] = 'Nie można zmienić parametrów!'; $PALANG['pPassword_welcome'] = 'Zmień Swoje hasło.'; $PALANG['pPassword_admin'] = 'Login'; $PALANG['pPassword_admin_text_error'] = 'Podany LOGIN nie pasuje!'; $PALANG['pPassword_password_current'] = 'Aktualne hasło'; $PALANG['pPassword_password_current_text_error'] = 'Nieprawidłowe aktualne hasło!'; $PALANG['pPassword_password'] = 'Nowe hasło'; $PALANG['pPassword_password2'] = 'Nowe hasło (ponownie)'; $PALANG['pPassword_password_text_error'] = 'Podane hasło nie pasuje!
Lub jest puste!
'; $PALANG['pPassword_button'] = 'Zmień hasło'; $PALANG['pPassword_result_error'] = 'Nie można zmienić Twojego hasła!'; $PALANG['pPassword_result_success'] = 'Twoje hasło zostało zmienione!'; $PALANG['pEdit_vacation_set'] = 'Zmień / Ustaw wiadomość automatycznej odpowiedzi'; $PALANG['pEdit_vacation_remove'] = 'Usuń wiadomość automatycznej odpowiedzi'; $PALANG['pVacation_result_error'] = 'Nie można ustawić wiadomości automatycznej odpowiedzi!'; $PALANG['pVacation_result_removed'] = 'Auto odpowiedź została usunięta!'; $PALANG['pVacation_result_added'] = 'Auto odpowiedź została dodana!'; $PALANG['pViewlog_welcome'] = 'Pokaż 10 ostatnich działań dla '; $PALANG['pViewlog_timestamp'] = 'Data'; $PALANG['pViewlog_username'] = 'Administrator'; $PALANG['pViewlog_domain'] = 'Domena'; $PALANG['pViewlog_action'] = 'Działanie'; $PALANG['pViewlog_data'] = 'Dane'; $PALANG['pViewlog_action_create_mailbox'] = 'utworzenie konta'; $PALANG['pViewlog_action_delete_mailbox'] = 'usunięcie konta'; $PALANG['pViewlog_action_edit_mailbox'] = 'edycja konta'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'edycja statusu konta'; $PALANG['pViewlog_action_create_alias'] = 'utworzenie aliasu'; $PALANG['pViewlog_action_create_alias_domain'] = 'utworzenie aliasu domeny'; $PALANG['pViewlog_action_delete_alias'] = 'usunięcie aliasu'; $PALANG['pViewlog_action_delete_alias_domain'] = 'usunięcie aliasu domeny'; $PALANG['pViewlog_action_edit_alias'] = 'edycja aliasu'; $PALANG['pViewlog_action_edit_alias_state'] = 'edycja statusu aliasu'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edycja statusu aliasu domeny'; $PALANG['pViewlog_action_edit_password'] = 'zmień hasło'; $PALANG['pViewlog_button'] = 'Idź'; $PALANG['pViewlog_result_error'] = 'Nie można odszukać logów!'; $PALANG['pSendmail_welcome'] = 'Wyślij wiadomość.'; $PALANG['pSendmail_admin'] = 'Od'; $PALANG['pSendmail_to'] = 'Do'; $PALANG['pSendmail_to_text_error'] = 'Podany adres jest niepoprawny, bądź pole "Do" jest puste!'; $PALANG['pSendmail_subject'] = 'Temat'; $PALANG['pSendmail_subject_text'] = 'Witamy'; $PALANG['pSendmail_body'] = 'Tekst'; $PALANG['pSendmail_button'] = 'Wyślij wiadomość'; $PALANG['pSendmail_result_error'] = 'Nie można wysłać emaila!'; $PALANG['pSendmail_result_success'] = 'Email wysłany!'; $PALANG['pAdminMenu_list_admin'] = 'Lista administratorów'; $PALANG['pAdminMenu_list_domain'] = 'Lista domen'; $PALANG['pAdminMenu_list_virtual'] = 'Lista zbiorcza'; $PALANG['pAdminMenu_viewlog'] = 'Logi'; $PALANG['pAdminMenu_backup'] = 'Kopia bezpieczeństwa'; $PALANG['pAdminMenu_create_domain_admins'] = 'Administratorzy domeny'; $PALANG['pAdminMenu_create_admin'] = 'Nowy administrator'; $PALANG['pAdminMenu_create_domain'] = 'Nowa domena'; $PALANG['pAdminMenu_create_alias'] = 'Dodaj alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Dodaj konto'; $PALANG['pAdminList_admin_domain'] = 'Domena'; $PALANG['pAdminList_admin_username'] = 'Admin'; $PALANG['pAdminList_admin_count'] = 'Domeny'; $PALANG['pAdminList_admin_modified'] = 'Ostatnio zmodyfikowane'; $PALANG['pAdminList_admin_active'] = 'Aktywny'; $PALANG['pAdminList_domain_domain'] = 'Domena'; $PALANG['pAdminList_domain_description'] = 'Opis'; $PALANG['pAdminList_domain_aliases'] = 'Aliasy'; $PALANG['pAdminList_domain_mailboxes'] = 'Konta'; $PALANG['pAdminList_domain_maxquota'] = 'Max udział (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; $PALANG['pAdminList_domain_backupmx'] = 'Zapasowy MX'; $PALANG['pAdminList_domain_modified'] = 'Ostatnio zmodyfikowane'; $PALANG['pAdminList_domain_active'] = 'Aktywne'; $PALANG['pAdminList_virtual_button'] = 'Idź'; $PALANG['pAdminList_virtual_welcome'] = 'Podsumowanie dla '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Aliasy'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Konta'; $PALANG['pAdminList_virtual_alias_address'] = 'Od'; $PALANG['pAdminList_virtual_alias_goto'] = 'Do'; $PALANG['pAdminList_virtual_alias_modified'] = 'Ostatnio zmodyfikowane'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Email'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Nazwa'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Udział (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Ostatnio zmodyfikowane'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Aktywne'; $PALANG['pAdminCreate_domain_welcome'] = 'Dodaj nową domenę'; $PALANG['pAdminCreate_domain_domain'] = 'Domena'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Podana domena już istnieje!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'Podana domena jest nieprawidłowa!'; $PALANG['pAdminCreate_domain_description'] = 'Opis'; $PALANG['pAdminCreate_domain_aliases'] = 'Aliasy'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = wyłączone | 0 = bez limitów'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Konta'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = wyłączone | 0 = bez limitów'; $PALANG['pAdminCreate_domain_maxquota'] = 'Max udział'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = wyłączone | 0 = bez limitów'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Zdefiniuj transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Dodaj domyślne aliasy mailowe'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'Serwer pocztowy jest zapasowym MX'; $PALANG['pAdminCreate_domain_button'] = 'Dodaj domenę'; $PALANG['pAdminCreate_domain_result_error'] = 'Nie można dodać domeny!'; $PALANG['pAdminCreate_domain_result_success'] = 'Domena została dodana!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Nie można usunąć domeny!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Nie można usunąć aliasu domeny!'; $PALANG['pAdminEdit_domain_welcome'] = 'Edytuj domenę'; $PALANG['pAdminEdit_domain_domain'] = 'Domena'; $PALANG['pAdminEdit_domain_description'] = 'Opis'; $PALANG['pAdminEdit_domain_aliases'] = 'Aliasy'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = wyłączone | 0 = bez limitów'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Konta'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = wyłączone | 0 = bez limitów'; $PALANG['pAdminEdit_domain_maxquota'] = 'Max udział'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = wyłączone | 0 = bez limitów'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Zdefiniuj transport'; $PALANG['pAdminEdit_domain_backupmx'] = 'Serwer pocztowy jest zapasowym MX'; $PALANG['pAdminEdit_domain_active'] = 'Aktywne'; $PALANG['pAdminEdit_domain_button'] = 'Edytuj domenę'; $PALANG['pAdminEdit_domain_result_error'] = 'Nie można zmodyfikować domeny!'; $PALANG['pAdminCreate_admin_welcome'] = 'Dodaj konto administratora'; $PALANG['pAdminCreate_admin_username'] = 'Administrator'; $PALANG['pAdminCreate_admin_username_text'] = 'Adres email'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Adres email
Administartor nie jest poprawnym adresem email!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Adres email
Administrator już istnieje lub jest niepoprawny'; $PALANG['pAdminCreate_admin_password'] = 'Hasło'; $PALANG['pAdminCreate_admin_password2'] = 'Hasło (ponownie)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Podane hasło nie pasuje!
Lub jest puste!
'; $PALANG['pAdminCreate_admin_button'] = 'Dodaj administratora'; $PALANG['pAdminCreate_admin_result_error'] = 'Nie można dodać administratora!'; $PALANG['pAdminCreate_admin_result_success'] = 'Administrator został dodany!'; $PALANG['pAdminCreate_admin_address'] = 'Domena'; $PALANG['pAdminEdit_admin_welcome'] = 'Edytuj administratora domeny'; $PALANG['pAdminEdit_admin_username'] = 'Administrator'; $PALANG['pAdminEdit_admin_password'] = 'Hasło'; $PALANG['pAdminEdit_admin_password2'] = 'Hasło (ponownie)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Podane hasło nie pasuje!
Lub jest puste!
'; $PALANG['pAdminEdit_admin_active'] = 'Aktywny'; $PALANG['pAdminEdit_admin_super_admin'] = 'Główny administrator'; $PALANG['pAdminEdit_admin_button'] = 'Edytuj administratora'; $PALANG['pAdminEdit_admin_result_error'] = 'Nie można zmodyfikować administratora!'; $PALANG['pAdminEdit_admin_result_success'] = 'Administrator został zmodyfikowany!'; $PALANG['pUsersLogin_welcome'] = 'Zaloguj się żeby zmienić hasło albo dodać aliasy.'; $PALANG['pUsersLogin_username'] = 'Użytkownik (email)'; $PALANG['pUsersLogin_password'] = 'Hasło'; $PALANG['pUsersLogin_button'] = 'Zaloguj'; $PALANG['pUsersLogin_username_incorrect'] = 'Podana nazwa użytkownika jest nieprawidłowa! '; $PALANG['pUsersLogin_password_incorrect'] = 'Podane hasło jest nieprawidłowe!'; $PALANG['pUsersMenu_vacation'] = 'Auto odpowiedź'; $PALANG['pUsersMenu_edit_alias'] = 'Zmień przekierowania'; $PALANG['pUsersMenu_password'] = 'Zmień hasło'; $PALANG['pUsersMain_vacation'] = 'Ustaw automatyczną odpowiedź.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' jest WŁACZONA, kliknij \'' . $PALANG['pUsersMenu_vacation'] . '\' aby ' . 'edytować/usunąć'; $PALANG['pUsersMain_edit_alias'] = 'Zmień przekierowania wiadomości.'; $PALANG['pUsersMain_password'] = 'Zmień aktualne hasło.'; $PALANG['pUsersVacation_welcome'] = 'Automatyczną odpowiedź.'; $PALANG['pUsersVacation_welcome_text'] = 'Masz już skonfigurowaną automatyczną odpowiedź!'; $PALANG['pUsersVacation_subject'] = 'Temat'; $PALANG['pUsersVacation_subject_text'] = 'Poza biurem'; $PALANG['pUsersVacation_body'] = 'Wiadomość'; $PALANG['pUsersVacation_body_text'] = << do . W pilnych sprawach proszę się kontaktować z . EOM; $PALANG['pUsersVacation_button_away'] = 'Nieobecny/a'; $PALANG['pUsersVacation_button_back'] = 'Zaraz wracam'; $PALANG['pUsersVacation_result_error'] = 'Nie mogę zaktualizować ustawień Twojej automatycznej odpowiedzi!'; $PALANG['pUsersVacation_result_success'] = 'Twoja automatyczna odpowiedź została usunięta!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'utwórz konto'; $PALANG['pCreate_dbLog_createalias'] = 'utwórz alias'; $PALANG['pDelete_dbLog_deletealias'] = 'usuń alias'; $PALANG['pDelete_dbLog_deletemailbox'] = 'usuń konto'; $PALANG['pEdit_dbLog_editactive'] = 'zmień aktywny stan'; $PALANG['pEdit_dbLog_editalias'] = 'edytuj alias'; $PALANG['pEdit_dbLog_editmailbox'] = 'edytuj konto'; $PALANG['pSearch'] = 'szukaj'; $PALANG['pSearch_welcome'] = 'Wyszukuję: '; $PALANG['pReturn_to'] = 'Powrót do'; $PALANG['pBroadcast_title'] = 'Wyślij wiadomość do wszystkich'; $PALANG['pBroadcast_from'] = 'Od'; $PALANG['pBroadcast_name'] = 'Nazwa'; $PALANG['pBroadcast_subject'] = 'Temat'; $PALANG['pBroadcast_message'] = 'Wiadomość'; $PALANG['pBroadcast_send'] = 'Wyślij wiadomość'; $PALANG['pBroadcast_success'] = 'Wiadomość do wszystkich została wysłana.'; $PALANG['pAdminMenu_broadcast_message'] = 'Wiadomość do wszystkich'; $PALANG['pBroadcast_error_empty'] = 'Pola Nazwa, Temat i Wiadomość nie powinny być puste !'; $PALANG['pStatus_undeliverable'] = 'może być NIEDOSTARCZALNA '; $PALANG['pStatus_custom'] = 'Dostarczyć do '; $PALANG['pStatus_popimap'] = 'POP/IMAP '; $PALANG['pPasswordTooShort'] = 'Hasło jest za krótkie - musi mieć minimum %s znaków'; $PALANG['pInvalidDomainRegex'] = 'Nieprawidłowa nazwa domeny %s'; $PALANG['pInvalidDomainDNS'] = 'Nieprawidłowa domena %s, nie wykrywana w DNS'; $PALANG['pInvalidMailRegex'] = 'Nieprawidłowy adres email'; $PALANG['pFetchmail_welcome'] = 'Pobierz pocztę dla:'; $PALANG['pFetchmail_new_entry'] = 'Nowy wpis'; $PALANG['pFetchmail_database_save_error'] = 'Wpis nie może być zapisany w bazie danych!'; $PALANG['pFetchmail_database_save_success'] = 'Wpis został zapisany w bazie danych.'; $PALANG['pFetchmail_error_invalid_id'] = 'Nie znaleziono wpisu z ID %s !'; $PALANG['pFetchmail_invalid_mailbox'] = 'Błędne konto!'; $PALANG['pFetchmail_server_missing'] = 'Podaj nazwę zdalnego serwera!'; $PALANG['pFetchmail_user_missing'] = 'Podaj nazwę zdalnego użytkownika!'; $PALANG['pFetchmail_password_missing'] = 'Podaj hasło zdalnego użytkownika!'; $PALANG['pFetchmail_field_id'] = 'ID'; $PALANG['pFetchmail_field_mailbox'] = 'Konto'; $PALANG['pFetchmail_field_src_server'] = 'Serwer'; $PALANG['pFetchmail_field_src_auth'] = 'Uwierzytelnianie'; $PALANG['pFetchmail_field_src_user'] = 'Użytkownik'; $PALANG['pFetchmail_field_src_password'] = 'Hasło'; $PALANG['pFetchmail_field_src_folder'] = 'Folder'; $PALANG['pFetchmail_field_poll_time'] = 'Sprawdzaj'; $PALANG['pFetchmail_field_fetchall'] = 'Pobierz wszystkie'; $PALANG['pFetchmail_field_keep'] = 'Pozostaw'; $PALANG['pFetchmail_field_protocol'] = 'Protokół'; $PALANG['pFetchmail_field_usessl'] = 'Aktywne SSL'; $PALANG['pFetchmail_field_extra_options'] = 'Dodatkowe opcje'; $PALANG['pFetchmail_field_mda'] = 'MDA'; $PALANG['pFetchmail_field_date'] = 'Data'; $PALANG['pFetchmail_field_returned_text'] = 'Zwrócony tekst'; $PALANG['pFetchmail_desc_id'] = 'ID rekordu'; $PALANG['pFetchmail_desc_mailbox'] = 'Konto lokalne'; $PALANG['pFetchmail_desc_src_server'] = 'Zdalny serwer'; $PALANG['pFetchmail_desc_src_auth'] = 'Najczęściej \'password\''; # Translators, do not translate 'password' here! $PALANG['pFetchmail_desc_src_user'] = 'Zdalny użytkownik'; $PALANG['pFetchmail_desc_src_password'] = 'Hasło zdalnego użytkownika'; $PALANG['pFetchmail_desc_src_folder'] = 'Zdalny Folder'; $PALANG['pFetchmail_desc_poll_time'] = 'Pobierz co ... minut'; $PALANG['pFetchmail_desc_fetchall'] = 'Pobierz zarówno stare (przeczytane) jak i nowe wiadomości'; $PALANG['pFetchmail_desc_keep'] = 'Pozostaw wiadomości na serwerze'; $PALANG['pFetchmail_desc_protocol'] = 'Protokół'; $PALANG['pFetchmail_desc_usessl'] = 'szyfrowanie SSL'; $PALANG['pFetchmail_desc_extra_options'] = 'Dodatkowe opcje dla fetchmail'; $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; $PALANG['pFetchmail_desc_date'] = 'Data ostatniego sprawdzenia/zmiany konfiguracji'; $PALANG['pFetchmail_desc_returned_text'] = 'Wiadomość tekstowa z ostatniego sprawdzenia'; $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/language.php0000664000175000017620000000324311010237045020514 0ustar davidpalepurple 'native language name - language name in english' 'bg' => 'Български - Bulgarian', 'ca' => 'Català - Catalan', 'cn' => '中文 - Chinese simplified (gb2312)', 'tw' => '中文 - Chinese traditional', 'cs' => 'Česky - Czech', 'da' => 'Dansk - Danish', 'de' => 'Deutsch - German', 'en' => 'English', 'es' => 'Español - Spanish', 'et' => 'Eesti - Estonian', 'eu' => 'Euskara - Basque', 'fi' => 'Suomi - Finnish', 'fo' => 'Faroese', 'fr' => 'Français - French', 'hr' => 'Hrvatski - Croatian', 'hu' => 'Magyar - Hungarian', 'is' => 'Icelandic', 'it' => 'Italiano - Italian', 'ja' => '日本語 - Japanese', 'lt' => 'Lietuvių - Lithuanian', 'mk' => 'Macedonian - Macedonian', 'nl' => 'Nederlands - Dutch', 'nb' => 'Norsk (bokmål) - Norwegian (bokmål)', 'nn' => 'Norsk (nynorsk) - Norwegian (nynorsk)', 'pl' => 'Polski - Polish', 'pt-br' => 'Português - Brazilian portuguese', 'ru' => 'Русский - Russian', 'sk' => 'Slovenčina - Slovak', 'sl' => 'Slovenščina - Slovenian', 'sv' => 'Svenska - Swedish', 'tr' => 'Türkçe - Turkish', ); /* vim: set expandtab ft=php softtabstop=4 tabstop=4 shiftwidth=4: */ ?> postfixadmin-2.3.7/languages/cs.lang0000664000175000017620000006540711636730120017510 0ustar davidpalepurpleNelze smazat položku '; $PALANG['pDelete_delete_success'] = '%s odstraněn.'; $PALANG['pDelete_postdelete_error'] = 'Nelze odstranit schránku '; $PALANG['pDelete_domain_error'] = 'Tato doména není vaše '; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = 'Nelze odstranit přesměrování '; $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = 'Vytvořit nové přesměrování ve Vaší doméně.'; $PALANG['pCreate_alias_address'] = 'Přesměrování'; $PALANG['pCreate_alias_address_text_error1'] = '
Adresa neni platná!'; $PALANG['pCreate_alias_address_text_error2'] = '
Taková emailová adresa již existuje!'; $PALANG['pCreate_alias_address_text_error3'] = '
Dosáhli jste limitu, nemůžete vytvářet další aliasy!'; $PALANG['pCreate_alias_goto'] = 'Cíl'; $PALANG['pCreate_alias_active'] = 'Aktivní'; $PALANG['pCreate_alias_button'] = 'Přidat'; $PALANG['pCreate_alias_goto_text'] = 'Kam má pošta chodit.'; $PALANG['pCreate_alias_goto_text_error'] = 'Kam má pošta chodit.
Cíl není platný!'; $PALANG['pCreate_alias_result_error'] = 'Nepodařilo se přidat přesměrování do tabulky aliasů!'; $PALANG['pCreate_alias_result_success'] = 'Přesměrování bylo uspěšně přidáno do tabulky aliasů!'; $PALANG['pCreate_alias_catchall_text'] = 'Pro vytvoření doménového koše použijte * jako alias.
Pro alias doména -> doména použijte *@domain.tld jako cíl.'; $PALANG['pEdit_alias_welcome'] = 'Upravit přesměrování.
Jeden záznam na řádku.'; $PALANG['pEdit_alias_address'] = 'Přesměrování'; $PALANG['pEdit_alias_address_error'] = 'Nelze najít alias!'; $PALANG['pEdit_alias_goto'] = 'Cíl'; $PALANG['pEdit_alias_active'] = 'Aktivní'; $PALANG['pEdit_alias_goto_text_error1'] = 'Nezadali jste cíl'; $PALANG['pEdit_alias_goto_text_error2'] = 'Emailová adresa kterou jste zadali není platná: '; $PALANG['pEdit_alias_domain_error'] = 'Tato doména není vaše: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Doručovat i do schránky.'; $PALANG['pEdit_alias_forward_only'] = 'Přesměrovat pouze na dané adresy.'; $PALANG['pEdit_alias_button'] = 'Upravit'; $PALANG['pEdit_alias_result_error'] = 'Nepodařilo se upravit přesměrování!'; $PALANG['pCreate_mailbox_welcome'] = 'Vytvořit novou lokální schránku v doméně.'; $PALANG['pCreate_mailbox_username'] = 'Uživatelské jméno'; $PALANG['pCreate_mailbox_username_text_error1'] = '
Adresa neni platná!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Taková emailová adresa již¸ existuje!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Dosáhli jste limitu, nemů¸ete vytvářet další schránky!'; $PALANG['pCreate_mailbox_password'] = 'Heslo'; $PALANG['pCreate_mailbox_password2'] = 'Heslo (znovu)'; $PALANG['pCreate_mailbox_password_text'] = 'Heslo pro POP3/IMAP/SMTP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Heslo pro POP3/IMAP/SMTP
Zadaná hesla jsou rozdílná nebo prázdná!'; $PALANG['pCreate_mailbox_name'] = 'Jméno'; $PALANG['pCreate_mailbox_name_text'] = 'Celé jméno'; $PALANG['pCreate_mailbox_quota'] = 'Místo'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Zadané místo je příliš velké!'; $PALANG['pCreate_mailbox_active'] = 'Aktivní'; $PALANG['pCreate_mailbox_mail'] = 'Vytvořit schránku na disku (odešle uvítací email)'; $PALANG['pCreate_mailbox_button'] = 'Přidat schránku'; $PALANG['pCreate_mailbox_result_error'] = 'Nepodařilo se přidat schránku do tabulky schránek!'; $PALANG['pCreate_mailbox_result_success'] = 'Schránka byla přidána do tabulky schránek!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'Schránka byla přidána do tabulky schránek, ale žádné (nebo pouze některé) ze předdefinovaných podsložek bylo možné vytovořit'; $PALANG['pEdit_mailbox_welcome'] = 'Upravit lokální chránku v doméně.'; $PALANG['pEdit_mailbox_username'] = 'Uživatelské jméno'; $PALANG['pEdit_mailbox_username_error'] = 'Nepodařilo se nalézt schránku!'; $PALANG['pEdit_mailbox_password'] = 'Nové heslo'; $PALANG['pEdit_mailbox_password2'] = 'Nové heslo (znovu)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Zadaná hesla se neshodují!'; $PALANG['pEdit_mailbox_name'] = 'Jméno'; $PALANG['pEdit_mailbox_name_text'] = 'Celé Jméno'; $PALANG['pEdit_mailbox_quota'] = 'Místo'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Zadané místo je příliš velké!'; $PALANG['pEdit_mailbox_domain_error'] = 'Tato doména není vaše: '; $PALANG['pEdit_mailbox_button'] = 'Upravit schránku'; $PALANG['pEdit_mailbox_result_error'] = 'Nepodařilo se upravit schránku!'; $PALANG['pPassword_welcome'] = 'Změnit heslo.'; $PALANG['pPassword_admin'] = 'Uživatelské jméno'; $PALANG['pPassword_admin_text_error'] = 'Uživatelské jméno se neshoduje s žádnou schránkou!'; $PALANG['pPassword_password_current'] = 'Současné heslo'; $PALANG['pPassword_password_current_text_error'] = 'Nezadal(a) jste současné heslo!'; $PALANG['pPassword_password'] = 'Nové heslo'; $PALANG['pPassword_password2'] = 'Nové heslo (znovu)'; $PALANG['pPassword_password_text_error'] = 'Zadaná hesla jsou rozdílná nebo prázdná!'; $PALANG['pPassword_button'] = 'Změnit heslo'; $PALANG['pPassword_result_error'] = 'Nepodařilo se změnit heslo!'; $PALANG['pPassword_result_success'] = 'Heslo bylo změněno!'; $PALANG['pEdit_vacation_set'] = 'Změnit / Nastavit zprávu o nepřítomnosti'; $PALANG['pEdit_vacation_remove'] = 'Ostranit zprávu o nepřítomnosti'; $PALANG['pVacation_result_error'] = 'Nebylo možné aktualizovat nastavení automatické odpověďi!'; $PALANG['pVacation_result_removed'] = 'Automatická odpověď byla odstraněna!'; $PALANG['pVacation_result_added'] = 'Automatická odpověd byla zapnuta!'; $PALANG['pViewlog_welcome'] = 'Prohlížet 10 posledních akcí pro '; $PALANG['pViewlog_timestamp'] = 'Časová značka'; $PALANG['pViewlog_username'] = 'Administrátor'; $PALANG['pViewlog_domain'] = 'Doména'; $PALANG['pViewlog_action'] = 'Akce'; $PALANG['pViewlog_data'] = 'Poznámka'; $PALANG['pViewlog_action_create_mailbox'] = 'vytrořena schránka'; $PALANG['pViewlog_action_delete_mailbox'] = 'smazána schránka'; $PALANG['pViewlog_action_edit_mailbox'] = 'úprava schránky'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'změna stavu schránky'; $PALANG['pViewlog_action_create_alias'] = 'vytvořeno přesměrování'; $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'smazáno přesměrování'; $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'úprava přesměrování'; $PALANG['pViewlog_action_edit_alias_state'] = 'změna stavu přesměrování'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'změna hesla'; $PALANG['pViewlog_button'] = 'Jít'; $PALANG['pViewlog_result_error'] = 'Nepodařilo se najít záznamy!'; $PALANG['pSendmail_welcome'] = 'Poslat email.'; $PALANG['pSendmail_admin'] = 'Od'; $PALANG['pSendmail_to'] = 'Komu'; $PALANG['pSendmail_to_text_error'] = 'V poli "Komu" není zadaná platná emailová adresa!'; $PALANG['pSendmail_subject'] = 'Předmět'; $PALANG['pSendmail_subject_text'] = 'Vítejte'; $PALANG['pSendmail_body'] = 'Obsah'; $PALANG['pSendmail_button'] = 'Poslat email'; $PALANG['pSendmail_result_error'] = 'Nepodařilo se odeslat email!'; $PALANG['pSendmail_result_success'] = 'Email odeslán!'; $PALANG['pAdminMenu_list_admin'] = 'Administrátoři domén'; $PALANG['pAdminMenu_list_domain'] = 'Domény'; $PALANG['pAdminMenu_list_virtual'] = 'Schránky'; $PALANG['pAdminMenu_viewlog'] = 'Prohlížet Log'; $PALANG['pAdminMenu_backup'] = 'Vytvořit zálohu'; $PALANG['pAdminMenu_create_domain_admins'] = 'Administrátoři'; // unused $PALANG['pAdminMenu_create_admin'] = 'Nový Administrátor'; $PALANG['pAdminMenu_create_domain'] = 'Nová Doména'; $PALANG['pAdminMenu_create_alias'] = 'Nové Přesměrování'; $PALANG['pAdminMenu_create_mailbox'] = 'Nová Schránka'; $PALANG['pAdminList_admin_domain'] = 'Doména'; $PALANG['pAdminList_admin_username'] = 'Administrátor'; $PALANG['pAdminList_admin_count'] = 'Domény'; $PALANG['pAdminList_admin_modified'] = 'Naposledy Změněno'; $PALANG['pAdminList_admin_active'] = 'Aktivní'; $PALANG['pAdminList_domain_domain'] = 'Doména'; $PALANG['pAdminList_domain_description'] = 'Popis'; $PALANG['pAdminList_domain_aliases'] = 'Přesměrování'; $PALANG['pAdminList_domain_mailboxes'] = 'Schránek'; $PALANG['pAdminList_domain_maxquota'] = 'Maximální místo (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; $PALANG['pAdminList_domain_backupmx'] = 'Záložní MX'; $PALANG['pAdminList_domain_modified'] = 'Naposledy Změněno'; $PALANG['pAdminList_domain_active'] = 'Aktivní'; $PALANG['pAdminList_virtual_button'] = 'Jít'; $PALANG['pAdminList_virtual_welcome'] = 'Přehled pro '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Přesměrování'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Schránek'; $PALANG['pAdminList_virtual_alias_address'] = 'Od'; $PALANG['pAdminList_virtual_alias_goto'] = 'Cíl'; $PALANG['pAdminList_virtual_alias_modified'] = 'Naposledy Změněno'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Název'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Celé Jméno'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Místo (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Naposledy Změněno'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Aktivní'; $PALANG['pAdminCreate_domain_welcome'] = 'Přidat Novou Doménu'; $PALANG['pAdminCreate_domain_domain'] = 'Doména'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Taková doména už existuje!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'Taková doména není platná!'; $PALANG['pAdminCreate_domain_description'] = 'Popis'; $PALANG['pAdminCreate_domain_aliases'] = 'Přesměrování'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = znepřístupnit | 0 = neomezeně'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Schránek'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = znepřístupnit | 0 = neomezeně'; $PALANG['pAdminCreate_domain_maxquota'] = 'Maximální místo'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = znepřístupnit | 0 = neomezeně'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Nastavit transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Přidat implicitní přesměrování'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'Tento server je záložní MX domény'; $PALANG['pAdminCreate_domain_button'] = 'Přidat doménu'; $PALANG['pAdminCreate_domain_result_error'] = 'Nepodařilo se přidat doménu!'; $PALANG['pAdminCreate_domain_result_success'] = 'Doména byla přidána!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Nepodařilo se odstranit doménu!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = 'Upravit doménu'; $PALANG['pAdminEdit_domain_domain'] = 'Doména'; $PALANG['pAdminEdit_domain_description'] = 'Popis'; $PALANG['pAdminEdit_domain_aliases'] = 'Přesměrování'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = znepřístupnit | 0 = neomezeně'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Schránek'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = znepřístupnit | 0 = neomezeně'; $PALANG['pAdminEdit_domain_maxquota'] = 'Maximální místo'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = znepřístupnit | 0 = neomezeně'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Nastavit transport'; $PALANG['pAdminEdit_domain_backupmx'] = 'Tento server je záložní MX domény'; $PALANG['pAdminEdit_domain_active'] = 'Aktivní'; $PALANG['pAdminEdit_domain_button'] = 'Upravit doménu'; $PALANG['pAdminEdit_domain_result_error'] = 'Nepodařilo se upravit doménu!'; $PALANG['pAdminCreate_admin_welcome'] = 'Přidat nového doménového administrátora'; $PALANG['pAdminCreate_admin_username'] = 'Uživatelské jméno'; $PALANG['pAdminCreate_admin_username_text'] = 'Emailová adresa'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Emailová adresa
Tato adresa není platná!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Emailová adresa
Taková adresa již existuje!'; $PALANG['pAdminCreate_admin_password'] = 'Heslo'; $PALANG['pAdminCreate_admin_password2'] = 'Heslo (znovu)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Zadaná hesla jsou rozdílná nebo prázdná!'; $PALANG['pAdminCreate_admin_button'] = 'Přidat administrátora'; $PALANG['pAdminCreate_admin_result_error'] = 'Nepodařilo se přidat administrátora!'; $PALANG['pAdminCreate_admin_result_success'] = 'Administrátor byl přidán!'; $PALANG['pAdminCreate_admin_address'] = 'Doména'; $PALANG['pAdminEdit_admin_welcome'] = 'Upravit doménového administrátora'; $PALANG['pAdminEdit_admin_username'] = 'Uživatelské jméno'; $PALANG['pAdminEdit_admin_password'] = 'Heslo'; $PALANG['pAdminEdit_admin_password2'] = 'Heslo (znovu)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Zadaná hesla jsou rozdílná nebo prázdná!'; $PALANG['pAdminEdit_admin_active'] = 'Administrátorský účet povolen'; $PALANG['pAdminEdit_admin_super_admin'] = 'Superuživatel'; $PALANG['pAdminEdit_admin_button'] = 'Upravit Administrátora'; $PALANG['pAdminEdit_admin_result_error'] = 'Nepodařilo se upravit administrátora!'; $PALANG['pAdminEdit_admin_result_success'] = 'Administrátor byl upraven!'; $PALANG['pUsersLogin_welcome'] = 'Zde se přihlašují uživatelé pro změnu hesla, přesměrování nebo automatické odpovědi.'; $PALANG['pUsersLogin_username'] = 'Uživatelské jméno (email)'; $PALANG['pUsersLogin_password'] = 'Heslo'; $PALANG['pUsersLogin_button'] = 'Přihlásit'; $PALANG['pUsersLogin_username_incorrect'] = 'Nesprávné uživatelské jmeno. Přihlašujte se svojí emailovou adresou!'; $PALANG['pUsersLogin_password_incorrect'] = 'Nesprávné heslo!'; $PALANG['pUsersMenu_vacation'] = 'Automatická Odpověď'; $PALANG['pUsersMenu_edit_alias'] = 'Změna Přesměrování'; $PALANG['pUsersMenu_password'] = 'Změna Hesla'; $PALANG['pUsersMain_vacation'] = 'Nastavit ,,jsem pryč`` nebo podobnou automatickou odpověď.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' je NASTAVENA, klikněte na \'' . $PALANG['pUsersMenu_vacation'] . '\' pro odstranění nebo změnu'; $PALANG['pUsersMain_edit_alias'] = 'Nastavit / změnít přesměrování'; $PALANG['pUsersMain_password'] = 'Změnit heslo'; $PALANG['pUsersVacation_welcome'] = 'Automatická odpověď'; $PALANG['pUsersVacation_welcome_text'] = 'Již máte nastavenou automatickou odpověď!'; $PALANG['pUsersVacation_subject'] = 'Předmět'; $PALANG['pUsersVacation_subject_text'] = 'Dovolená'; $PALANG['pUsersVacation_body'] = 'Obsah'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << od . S neodkladnými zprávami prosím kontaktujte . EOM; $PALANG['pUsersVacation_button_away'] = 'Odjet pryč'; $PALANG['pUsersVacation_button_back'] = 'Vrátit se'; $PALANG['pUsersVacation_result_error'] = 'Nepodařilo se upravit nastavení!'; $PALANG['pUsersVacation_result_success'] = 'Nastavení bylo upraveno!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'vytvořil schránku'; $PALANG['pCreate_dbLog_createalias'] = 'vytvořil alias'; $PALANG['pDelete_dbLog_deletealias'] = 'smazal alias'; $PALANG['pDelete_dbLog_deletemailbox'] = 'smazal schránku'; $PALANG['pEdit_dbLog_editactive'] = 'změnil aktivní stav'; $PALANG['pEdit_dbLog_editalias'] = 'editoval alias'; $PALANG['pEdit_dbLog_editmailbox'] = 'editoval schránku'; $PALANG['pSearch'] = 'vyhledat'; $PALANG['pSearch_welcome'] = 'Vyhledávání: '; $PALANG['pReturn_to'] = 'Odpovědět komu'; $PALANG['pBroadcast_title'] = 'Odeslat zprávu do všech schránek'; $PALANG['pBroadcast_from'] = 'Od'; $PALANG['pBroadcast_name'] = 'Vaše jméno'; $PALANG['pBroadcast_subject'] = 'Předmět'; $PALANG['pBroadcast_message'] = 'Zpráva'; $PALANG['pBroadcast_send'] = 'Odeslat zprávu'; $PALANG['pBroadcast_success'] = 'Zpráva pro všechny schránky byla odeslána.'; $PALANG['pAdminMenu_broadcast_message'] = 'Poslat email všem'; $PALANG['pBroadcast_error_empty'] = 'Pole Od, Předmět a Zpráva by neměly být prázdné !'; $PALANG['pStatus_undeliverable'] = 'možná NEDORUČITELNÉ '; $PALANG['pStatus_custom'] = 'Doručeno do '; $PALANG['pStatus_popimap'] = 'POP/IMAP '; $PALANG['pPasswordTooShort'] = "Heslo je příliš krátké - je vyžadováno minimálně %s znaků"; $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Stahovat poštu pro:'; $PALANG['pFetchmail_new_entry'] = 'Nová položka'; $PALANG['pFetchmail_database_save_error'] = 'Tuto položku není možné uložit do databáze!'; $PALANG['pFetchmail_database_save_success'] = 'Položka byla uložena do databáze.'; $PALANG['pFetchmail_error_invalid_id'] = 'Položka s ID %s nebyla nalezena!'; $PALANG['pFetchmail_invalid_mailbox'] = 'Nesprávná schránka!'; $PALANG['pFetchmail_server_missing'] = 'Prosím zadejte jméno serveru ze kterého stahovat poštu!'; $PALANG['pFetchmail_user_missing'] = 'Prosím zadejte přihlašovací jméno k serveru!'; $PALANG['pFetchmail_password_missing'] = 'Prosím zadejte heslo ke vzdálené schránce!'; $PALANG['pFetchmail_field_id'] = 'ID'; $PALANG['pFetchmail_field_mailbox'] = 'Schránka'; $PALANG['pFetchmail_field_src_server'] = 'Server'; $PALANG['pFetchmail_field_src_auth'] = 'Typ autentizace'; $PALANG['pFetchmail_field_src_user'] = 'Uživatel'; $PALANG['pFetchmail_field_src_password'] = 'Heslo'; $PALANG['pFetchmail_field_src_folder'] = 'Složka'; $PALANG['pFetchmail_field_poll_time'] = 'Interval'; $PALANG['pFetchmail_field_fetchall'] = 'Stahovat vše'; $PALANG['pFetchmail_field_keep'] = 'Nemazat'; $PALANG['pFetchmail_field_protocol'] = 'Protokol'; $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra Parametry'; $PALANG['pFetchmail_field_mda'] = 'MDA'; $PALANG['pFetchmail_field_date'] = 'Datum'; $PALANG['pFetchmail_field_returned_text'] = 'Výstupní Text'; $PALANG['pFetchmail_desc_id'] = 'ID záznamu'; $PALANG['pFetchmail_desc_mailbox'] = 'Místní schránka'; $PALANG['pFetchmail_desc_src_server'] = 'Vzdálený Server'; $PALANG['pFetchmail_desc_src_auth'] = 'Většinou \'password\''; # Translators: Please do NOT translate 'password' here $PALANG['pFetchmail_desc_src_user'] = 'Vzdálený Uživatel'; $PALANG['pFetchmail_desc_src_password'] = 'Heslo Vzdáleného Uživatele'; $PALANG['pFetchmail_desc_src_folder'] = 'Vzdálená Složka'; $PALANG['pFetchmail_desc_poll_time'] = 'Stahovat každých ... minut'; $PALANG['pFetchmail_desc_fetchall'] = 'Získávat všechny staré (přečtené) i nové zprávy'; $PALANG['pFetchmail_desc_keep'] = 'Ponechávat stažené zprávy na vzdáleném mailserveru'; $PALANG['pFetchmail_desc_protocol'] = 'Použitý protokol'; $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Extra parametry pro fetchmail'; $PALANG['pFetchmail_desc_mda'] = 'Program pro doručení pošty do schránky (MDA)'; $PALANG['pFetchmail_desc_date'] = 'Datum posledního stažení pošty/změny konfigurace'; $PALANG['pFetchmail_desc_returned_text'] = 'Výstupní textový záznam posledního stahování pošty'; $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/en.lang0000664000175000017620000006225411636730120017502 0ustar davidpalepurple // $PALANG['YES'] = 'YES'; $PALANG['NO'] = 'NO'; $PALANG['edit'] = 'edit'; $PALANG['del'] = 'del'; $PALANG['exit'] = 'Exit'; $PALANG['cancel'] = 'Cancel'; $PALANG['save'] = 'Save'; $PALANG['confirm'] = 'Are you sure you want to delete this?\n'; $PALANG['confirm_domain'] = 'Do you really want to delete all records for this domain? This can not be undone!\n'; $PALANG['check_update'] = 'Check for update'; $PALANG['invalid_parameter'] = 'Invalid parameter!'; $PALANG['pFooter_logged_as'] = 'Logged in as %s'; $PALANG['pLogin_welcome'] = 'Mail admins login here to administer your domain.'; $PALANG['pLogin_username'] = 'Login (email)'; $PALANG['pLogin_password'] = 'Password'; $PALANG['pLogin_button'] = 'Login'; $PALANG['pLogin_failed'] = 'Your email address or password are not correct.'; $PALANG['pLogin_login_users'] = 'Users click here to login to the user section.'; $PALANG['pMenu_main'] = 'Main'; $PALANG['pMenu_overview'] = 'Overview'; $PALANG['pMenu_create_alias'] = 'Add Alias'; $PALANG['pMenu_create_alias_domain'] = 'Add Alias Domain'; $PALANG['pMenu_create_mailbox'] = 'Add Mailbox'; $PALANG['pMenu_fetchmail'] = 'Fetch Email'; $PALANG['pMenu_sendmail'] = 'Send Email'; $PALANG['pMenu_password'] = 'Password'; $PALANG['pMenu_viewlog'] = 'View Log'; $PALANG['pMenu_logout'] = 'Logout'; $PALANG['pMain_welcome'] = 'Welcome to Postfix Admin!'; $PALANG['pMain_overview'] = 'List your aliases and mailboxes. You can edit / delete them from here.'; $PALANG['pMain_create_alias'] = 'Create a new alias for your domain.'; $PALANG['pMain_create_mailbox'] = 'Create a new mailbox for your domain.'; $PALANG['pMain_sendmail'] = 'Send an email to one of your newly created mailboxes.'; $PALANG['pMain_password'] = 'Change the password for your admin account.'; $PALANG['pMain_viewlog'] = 'View the log files.'; $PALANG['pMain_logout'] = 'Logout from the system'; $PALANG['pOverview_disabled'] = 'Disabled'; $PALANG['pOverview_unlimited'] = 'Unlimited'; $PALANG['pOverview_title'] = ':: Defined Domains'; $PALANG['pOverview_up_arrow'] = 'Go Top'; $PALANG['pOverview_right_arrow'] = 'Next Page'; $PALANG['pOverview_left_arrow'] = 'Previous Page'; $PALANG['pOverview_alias_domain_title'] = ':: Domain Aliases'; $PALANG['pOverview_alias_title'] = ':: Aliases'; $PALANG['pOverview_mailbox_title'] = ':: Mailboxes'; $PALANG['pOverview_button'] = 'Go'; $PALANG['pOverview_welcome'] = 'Overview for '; $PALANG['pOverview_alias_domain_aliases'] = 'Alias Domains'; $PALANG['pOverview_alias_domain_target'] = '%s is an Alias Domain for:'; $PALANG['pOverview_alias_alias_count'] = 'Aliases'; $PALANG['pOverview_alias_mailbox_count'] = 'Mailboxes'; $PALANG['pOverview_alias_address'] = 'From'; $PALANG['pOverview_alias_goto'] = 'To'; $PALANG['pOverview_alias_modified'] = 'Last Modified'; $PALANG['pOverview_alias_domain_modified'] = 'Last Modified'; $PALANG['pOverview_alias_active'] = 'Active'; $PALANG['pOverview_alias_domain_active'] = 'Active'; $PALANG['pOverview_alias_edit'] = 'Alias'; $PALANG['and_x_more'] = '[and %s more...]'; $PALANG['pOverview_mailbox_username'] = 'Email'; $PALANG['pOverview_mailbox_name'] = 'Name'; $PALANG['pOverview_mailbox_quota'] = 'Quota (MB)'; $PALANG['pOverview_mailbox_modified'] = 'Last Modified'; $PALANG['pOverview_mailbox_active'] = 'Active'; $PALANG['pOverview_vacation_edit'] = 'VACATION IS ON'; $PALANG['pOverview_vacation_option'] = 'Set Vacation'; $PALANG['pOverview_get_domain'] = 'Domain'; $PALANG['pOverview_get_aliases'] = 'Aliases'; $PALANG['pOverview_get_alias_domains'] = 'Domain Aliases'; $PALANG['pOverview_get_mailboxes'] = 'Mailboxes'; $PALANG['pOverview_get_quota'] = 'Mailbox Quota (MB)'; $PALANG['pOverview_get_modified'] = 'Last Modified'; $PALANG['pDelete_delete_error'] = 'Unable to delete the entry '; $PALANG['pDelete_delete_success'] = '%s deleted.'; $PALANG['pDelete_postdelete_error'] = 'Unable to remove mailbox '; $PALANG['pDelete_domain_error'] = 'This domain is not yours '; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; $PALANG['pDelete_alias_error'] = 'Unable to delete alias '; $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; $PALANG['pCreate_alias_domain_active'] = 'Active'; $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; $PALANG['pCreate_alias_welcome'] = 'Create a new alias for your domain.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
The ALIAS is not valid!'; $PALANG['pCreate_alias_address_text_error2'] = '
This email address already exists, please choose a different one!'; $PALANG['pCreate_alias_address_text_error3'] = '
You have reached your limit to create aliases!'; $PALANG['pCreate_alias_goto'] = 'To'; $PALANG['pCreate_alias_active'] = 'Active'; $PALANG['pCreate_alias_button'] = 'Add Alias'; $PALANG['pCreate_alias_goto_text'] = 'Where the mail needs to be sent to.'; $PALANG['pCreate_alias_goto_text_error'] = 'Where the email needs to go.
The TO is not valid!'; $PALANG['pCreate_alias_result_error'] = 'Unable to add the alias to the alias table!'; $PALANG['pCreate_alias_result_success'] = 'The alias has been added to the alias table!'; $PALANG['pCreate_alias_catchall_text'] = 'To create a catch-all use an "*" as alias.'; # XXX don't propagate usage of *@target-domain.com for domain-aliasing any longer $PALANG['pEdit_alias_welcome'] = 'Edit an alias for your domain.
One entry per line.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Unable to locate alias!'; $PALANG['pEdit_alias_goto'] = 'To'; $PALANG['pEdit_alias_active'] = 'Active'; $PALANG['pEdit_alias_goto_text_error1'] = 'You didn\'t enter anything at To'; $PALANG['pEdit_alias_goto_text_error2'] = 'The email address that you have entered is not valid: '; $PALANG['pEdit_alias_domain_error'] = 'This domain is not yours: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; $PALANG['pEdit_alias_forward_and_store'] = 'Deliver to the local mailbox.'; $PALANG['pEdit_alias_forward_only'] = 'Forward to given email addresses only.'; $PALANG['pEdit_alias_button'] = 'Edit Alias'; $PALANG['pEdit_alias_result_error'] = 'Unable to modify the alias!'; $PALANG['pCreate_mailbox_welcome'] = 'Create a new mailbox for your domain.'; $PALANG['pCreate_mailbox_username'] = 'Username'; $PALANG['pCreate_mailbox_username_text_error1'] = '
The EMAIL is not valid!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
This email address already exists, please choose a different one!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
You have reached your limit to create mailboxes!'; $PALANG['pCreate_mailbox_password'] = 'Password'; $PALANG['pCreate_mailbox_password2'] = 'Password (again)'; $PALANG['pCreate_mailbox_password_text'] = 'Password for POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Password for POP3/IMAP
The passwords that you supplied don\'t match!
Or are empty!
'; $PALANG['pCreate_mailbox_name'] = 'Name'; $PALANG['pCreate_mailbox_name_text'] = 'Full name'; $PALANG['pCreate_mailbox_quota'] = 'Quota'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
The quota that you specified is to high!'; $PALANG['pCreate_mailbox_active'] = 'Active'; $PALANG['pCreate_mailbox_mail'] = 'Send Welcome mail'; $PALANG['pCreate_mailbox_button'] = 'Add Mailbox'; $PALANG['pCreate_mailbox_result_error'] = 'Unable to add the mailbox to the mailbox table!'; $PALANG['pCreate_mailbox_result_success'] = 'The mailbox has been added to the mailbox table!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'The mailbox has been added to the mailbox table, but none (or only some) of the predefined sub-folders could be created'; $PALANG['pEdit_mailbox_welcome'] = 'Edit a mailbox for your domain.'; $PALANG['pEdit_mailbox_username'] = 'Username'; $PALANG['pEdit_mailbox_username_error'] = 'Unable to locate mailbox!'; $PALANG['pEdit_mailbox_password'] = 'New Password'; $PALANG['pEdit_mailbox_password2'] = 'New Password (again)'; $PALANG['pEdit_mailbox_password_text_error'] = 'The passwords that you supplied don\'t match!'; $PALANG['pEdit_mailbox_name'] = 'Name'; $PALANG['pEdit_mailbox_name_text'] = 'Full name'; $PALANG['pEdit_mailbox_quota'] = 'Quota'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
The quota that you specified is to high!'; $PALANG['pEdit_mailbox_domain_error'] = 'This domain is not yours: '; $PALANG['pEdit_mailbox_button'] = 'Edit Mailbox'; $PALANG['pEdit_mailbox_result_error'] = 'Unable to modify the mailbox!'; $PALANG['pPassword_welcome'] = 'Change your login password.'; $PALANG['pPassword_admin'] = 'Login'; $PALANG['pPassword_admin_text_error'] = 'The LOGIN that you supplied doesn\'t match a mailbox!'; $PALANG['pPassword_password_current'] = 'Current Password'; $PALANG['pPassword_password_current_text_error'] = 'You didn\'t supply your current password!'; $PALANG['pPassword_password'] = 'New Password'; $PALANG['pPassword_password2'] = 'New Password (again)'; $PALANG['pPassword_password_text_error'] = 'The passwords that you supplied don\'t match!
Or are empty!
'; $PALANG['pPassword_button'] = 'Change Password'; $PALANG['pPassword_result_error'] = 'Unable to change your password!'; $PALANG['pPassword_result_success'] = 'Your password has been changed!'; $PALANG['pEdit_vacation_set'] = 'Change / Set away message'; $PALANG['pEdit_vacation_remove'] = 'Remove away message'; $PALANG['pVacation_result_error'] = 'Unable to update auto response settings!'; $PALANG['pVacation_result_removed'] = 'Auto response has been removed!'; $PALANG['pVacation_result_added'] = 'Auto response has been enabled!'; $PALANG['pViewlog_welcome'] = 'View the last 10 actions for '; $PALANG['pViewlog_timestamp'] = 'Timestamp'; $PALANG['pViewlog_username'] = 'Admin'; $PALANG['pViewlog_domain'] = 'Domain'; $PALANG['pViewlog_action'] = 'Action'; $PALANG['pViewlog_data'] = 'Data'; $PALANG['pViewlog_action_create_mailbox'] = 'create mailbox'; $PALANG['pViewlog_action_delete_mailbox'] = 'delete mailbox'; $PALANG['pViewlog_action_edit_mailbox'] = 'edit mailbox'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'edit mailbox active'; $PALANG['pViewlog_action_create_alias'] = 'create alias'; $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; $PALANG['pViewlog_action_delete_alias'] = 'delete alias'; $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; $PALANG['pViewlog_action_edit_alias'] = 'edit alias'; $PALANG['pViewlog_action_edit_alias_state'] = 'edit alias active'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; $PALANG['pViewlog_action_edit_password'] = 'change password'; $PALANG['pViewlog_button'] = 'Go'; $PALANG['pViewlog_result_error'] = 'Unable to find the logs!'; $PALANG['pSendmail_welcome'] = 'Send an email.'; $PALANG['pSendmail_admin'] = 'From'; $PALANG['pSendmail_to'] = 'To'; $PALANG['pSendmail_to_text_error'] = 'To is empty or is not a valid email address!'; $PALANG['pSendmail_subject'] = 'Subject'; $PALANG['pSendmail_subject_text'] = 'Welcome'; $PALANG['pSendmail_body'] = 'Body'; $PALANG['pSendmail_button'] = 'Send Message'; $PALANG['pSendmail_result_error'] = 'Unable to send email!'; $PALANG['pSendmail_result_success'] = 'Email sent!'; $PALANG['pAdminMenu_list_admin'] = 'Admin List'; $PALANG['pAdminMenu_list_domain'] = 'Domain List'; $PALANG['pAdminMenu_list_virtual'] = 'Virtual List'; $PALANG['pAdminMenu_viewlog'] = 'View Log'; $PALANG['pAdminMenu_backup'] = 'Backup'; $PALANG['pAdminMenu_create_domain_admins'] = 'Domain Admins'; $PALANG['pAdminMenu_create_admin'] = 'New Admin'; $PALANG['pAdminMenu_create_domain'] = 'New Domain'; $PALANG['pAdminMenu_create_alias'] = 'Add Alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Add Mailbox'; $PALANG['pAdminList_admin_domain'] = 'Domain'; $PALANG['pAdminList_admin_username'] = 'Admin'; $PALANG['pAdminList_admin_count'] = 'Domains'; $PALANG['pAdminList_admin_modified'] = 'Last Modified'; $PALANG['pAdminList_admin_active'] = 'Active'; $PALANG['pAdminList_domain_domain'] = 'Domain'; $PALANG['pAdminList_domain_description'] = 'Description'; $PALANG['pAdminList_domain_aliases'] = 'Aliases'; $PALANG['pAdminList_domain_mailboxes'] = 'Mailboxes'; $PALANG['pAdminList_domain_maxquota'] = 'Quota (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; $PALANG['pAdminList_domain_modified'] = 'Last Modified'; $PALANG['pAdminList_domain_active'] = 'Active'; $PALANG['pAdminList_virtual_button'] = 'Go'; $PALANG['pAdminList_virtual_welcome'] = 'Overview for '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Aliases'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Mailboxes'; $PALANG['pAdminList_virtual_alias_address'] = 'From'; $PALANG['pAdminList_virtual_alias_goto'] = 'To'; $PALANG['pAdminList_virtual_alias_modified'] = 'Last Modified'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Email'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Name'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Quota (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Last Modified'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Active'; $PALANG['pAdminCreate_domain_welcome'] = 'Add a new domain'; $PALANG['pAdminCreate_domain_domain'] = 'Domain'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'The domain already exists!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'The domain is invalid!'; $PALANG['pAdminCreate_domain_description'] = 'Description'; $PALANG['pAdminCreate_domain_aliases'] = 'Aliases'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = disable | 0 = unlimited'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Mailboxes'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = disable | 0 = unlimited'; $PALANG['pAdminCreate_domain_maxquota'] = 'Max Quota'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = disable | 0 = unlimited'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Define transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Add default mail aliases'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'Mail server is backup MX'; $PALANG['pAdminCreate_domain_button'] = 'Add Domain'; $PALANG['pAdminCreate_domain_result_error'] = 'Unable to add domain!'; $PALANG['pAdminCreate_domain_result_success'] = 'Domain has been added!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; $PALANG['pAdminDelete_domain_error'] = 'Unable to remove domain!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; $PALANG['pAdminEdit_domain_welcome'] = 'Edit a domain'; $PALANG['pAdminEdit_domain_domain'] = 'Domain'; $PALANG['pAdminEdit_domain_description'] = 'Description'; $PALANG['pAdminEdit_domain_aliases'] = 'Aliases'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = disable | 0 = unlimited'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Mailboxes'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = disable | 0 = unlimited'; $PALANG['pAdminEdit_domain_maxquota'] = 'Max Quota'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = disable | 0 = unlimited'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Define transport'; $PALANG['pAdminEdit_domain_backupmx'] = 'Mail server is backup MX'; $PALANG['pAdminEdit_domain_active'] = 'Active'; $PALANG['pAdminEdit_domain_button'] = 'Edit Domain'; $PALANG['pAdminEdit_domain_result_error'] = 'Unable to modify domain!'; $PALANG['pAdminCreate_admin_welcome'] = 'Add a new domain admin'; $PALANG['pAdminCreate_admin_username'] = 'Admin'; $PALANG['pAdminCreate_admin_username_text'] = 'Email address'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Email address
Admin is not a valid email address!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Email address
The admin already exists or is not valid'; $PALANG['pAdminCreate_admin_password'] = 'Password'; $PALANG['pAdminCreate_admin_password2'] = 'Password (again)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'The passwords that you supplied don\'t match!
Or are empty!
'; $PALANG['pAdminCreate_admin_button'] = 'Add Admin'; $PALANG['pAdminCreate_admin_result_error'] = 'Unable to add admin!'; $PALANG['pAdminCreate_admin_result_success'] = 'Admin has been added!'; $PALANG['pAdminCreate_admin_address'] = 'Domain'; $PALANG['pAdminEdit_admin_welcome'] = 'Edit a domain admin'; $PALANG['pAdminEdit_admin_username'] = 'Admin'; $PALANG['pAdminEdit_admin_password'] = 'Password'; $PALANG['pAdminEdit_admin_password2'] = 'Password (again)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'The passwords that you supplied don\'t match!
Or are empty!
'; $PALANG['pAdminEdit_admin_active'] = 'Active'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super admin'; $PALANG['pAdminEdit_admin_button'] = 'Edit Admin'; $PALANG['pAdminEdit_admin_result_error'] = 'Unable to modify admin!'; $PALANG['pAdminEdit_admin_result_success'] = 'Admin has been modified!'; $PALANG['pUsersLogin_welcome'] = 'Mailbox users login to change your password and aliases.'; $PALANG['pUsersLogin_username'] = 'Login (email)'; $PALANG['pUsersLogin_password'] = 'Password'; $PALANG['pUsersLogin_button'] = 'Login'; $PALANG['pUsersLogin_username_incorrect'] = 'Your login is not correct. Make sure that you login with your email address!'; $PALANG['pUsersLogin_password_incorrect'] = 'Your password is not correct!'; $PALANG['pUsersMenu_vacation'] = 'Auto Response'; $PALANG['pUsersMenu_edit_alias'] = 'Change your forward'; $PALANG['pUsersMenu_password'] = 'Change Password'; $PALANG['pUsersMain_vacation'] = 'Set an "out of office" message or auto responder for your mail.'; $PALANG['pUsersMain_vacationSet'] = 'Auto Response is ON, click \'Auto Response\' to edit/remove'; $PALANG['pUsersMain_edit_alias'] = 'Change your email forwarding.'; $PALANG['pUsersMain_password'] = 'Change your current password.'; $PALANG['pUsersVacation_welcome'] = 'Auto Response.'; $PALANG['pUsersVacation_welcome_text'] = 'You already have an auto response configured!'; $PALANG['pUsersVacation_subject'] = 'Subject'; $PALANG['pUsersVacation_subject_text'] = 'Out of Office'; $PALANG['pUsersVacation_body'] = 'Message'; $PALANG['pUsersVacation_body_text'] = << until . For urgent matters you can contact . EOM; $PALANG['pUsersVacation_button_away'] = 'Going Away'; $PALANG['pUsersVacation_button_back'] = 'Coming Back'; $PALANG['pUsersVacation_result_error'] = 'Unable to update your auto response settings!'; $PALANG['pUsersVacation_result_success'] = 'Your auto response has been removed!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; $PALANG['pUsersVacation_activeuntil'] = 'Active until'; $PALANG['pCreate_dbLog_createmailbox'] = 'create mailbox'; $PALANG['pCreate_dbLog_createalias'] = 'create alias'; $PALANG['pDelete_dbLog_deletealias'] = 'delete alias'; $PALANG['pDelete_dbLog_deletemailbox'] = 'delete mailbox'; $PALANG['pEdit_dbLog_editactive'] = 'change active state'; $PALANG['pEdit_dbLog_editalias'] = 'edit alias'; $PALANG['pEdit_dbLog_editmailbox'] = 'edit mailbox'; $PALANG['pSearch'] = 'search'; $PALANG['pSearch_welcome'] = 'Searching for: '; $PALANG['pReturn_to'] = 'Return to'; $PALANG['pBroadcast_title'] = 'Send broadcast message'; $PALANG['pBroadcast_from'] = 'From'; $PALANG['pBroadcast_name'] = 'Your name'; $PALANG['pBroadcast_subject'] = 'Subject'; $PALANG['pBroadcast_message'] = 'Message'; $PALANG['pBroadcast_send'] = 'Send message'; $PALANG['pBroadcast_success'] = 'Your broadcast message was sent.'; $PALANG['pAdminMenu_broadcast_message'] = 'Broadcast message'; $PALANG['pBroadcast_error_empty'] = 'The fields Name, Subject and Message should\'t be empty !'; $PALANG['pStatus_undeliverable'] = 'maybe UNDELIVERABLE '; $PALANG['pStatus_custom'] = 'Delivers to '; $PALANG['pStatus_popimap'] = 'POP/IMAP '; $PALANG['pPasswordTooShort'] = "Password is too short - requires %s characters"; # usage: flash_error(sprintf($PALANG['pPasswordTooShort'], $CONF['min_password_length'])); $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; $PALANG['pFetchmail_welcome'] = 'Fetch mail for:'; $PALANG['pFetchmail_new_entry'] = 'New entry'; $PALANG['pFetchmail_database_save_error'] = 'Could not save this entry in the database!'; $PALANG['pFetchmail_database_save_success'] = 'Entry saved in database.'; $PALANG['pFetchmail_error_invalid_id'] = 'No entry with ID %s found!'; $PALANG['pFetchmail_invalid_mailbox'] = 'Invalid mailbox!'; $PALANG['pFetchmail_server_missing'] = 'Please enter the remote server name!'; $PALANG['pFetchmail_user_missing'] = 'Please enter the remote username!'; $PALANG['pFetchmail_password_missing'] = 'Please enter the remote password!'; $PALANG['pFetchmail_field_id'] = 'ID'; $PALANG['pFetchmail_field_mailbox'] = 'Mailbox'; $PALANG['pFetchmail_field_src_server'] = 'Server'; $PALANG['pFetchmail_field_src_auth'] = 'Auth Type'; $PALANG['pFetchmail_field_src_user'] = 'User'; $PALANG['pFetchmail_field_src_password'] = 'Password'; $PALANG['pFetchmail_field_src_folder'] = 'Folder'; $PALANG['pFetchmail_field_poll_time'] = 'Poll'; $PALANG['pFetchmail_field_fetchall'] = 'Fetch All'; $PALANG['pFetchmail_field_keep'] = 'Keep'; $PALANG['pFetchmail_field_protocol'] = 'Protocol'; $PALANG['pFetchmail_field_usessl'] = 'SSL active'; $PALANG['pFetchmail_field_extra_options'] = 'Extra Options'; $PALANG['pFetchmail_field_mda'] = 'MDA'; $PALANG['pFetchmail_field_date'] = 'Date'; $PALANG['pFetchmail_field_returned_text'] = 'Returned Text'; $PALANG['pFetchmail_desc_id'] = 'Record ID'; $PALANG['pFetchmail_desc_mailbox'] = 'Local mailbox'; $PALANG['pFetchmail_desc_src_server'] = 'Remote Server'; $PALANG['pFetchmail_desc_src_auth'] = 'Mostly \'password\''; # Translators: Please do NOT translate 'password' here $PALANG['pFetchmail_desc_src_user'] = 'Remote User'; $PALANG['pFetchmail_desc_src_password'] = 'Remote Password'; $PALANG['pFetchmail_desc_src_folder'] = 'Remote Folder'; $PALANG['pFetchmail_desc_poll_time'] = 'Poll every ... minutes'; $PALANG['pFetchmail_desc_fetchall'] = 'Retrieve both old (seen) and new messages'; $PALANG['pFetchmail_desc_keep'] = 'Keep retrieved messages on the remote mailserver'; $PALANG['pFetchmail_desc_protocol'] = 'Protocol to use'; $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; $PALANG['pFetchmail_desc_extra_options'] = 'Extra fetchmail Options'; $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; $PALANG['pFetchmail_desc_date'] = 'Date of last polling/configuration change'; $PALANG['pFetchmail_desc_returned_text'] = 'Text message from last polling'; $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/da.lang0000664000175000017620000006445512157373172017502 0ustar davidpalepurple // // titanus , 2013 // $PALANG['YES'] = 'JA'; $PALANG['NO'] = 'NEJ'; $PALANG['edit'] = 'redigere'; $PALANG['del'] = 'slet'; $PALANG['exit'] = 'Log af'; $PALANG['cancel'] = 'Annuller'; $PALANG['save'] = 'Gem'; $PALANG['confirm'] = 'Er du sikker på du vil slette dette?\n'; $PALANG['confirm_domain'] = 'Vil du virkelig slette alle adresser for dette domæne? Dette kan ikke fortrydes!\n'; $PALANG['check_update'] = 'Søg efter opdateringer'; $PALANG['invalid_parameter'] = 'Ugyldig parameter.'; $PALANG['pFooter_logged_as'] = 'Logget ind som %s'; $PALANG['pLogin_welcome'] = 'Postadministrator: Log ind for at administrere dine domæner.'; $PALANG['pLogin_username'] = 'Brugernavn (email)'; $PALANG['pLogin_password'] = 'Adgangskode'; $PALANG['pLogin_button'] = 'Log ind'; $PALANG['pLogin_failed'] = 'Dit brugernavn eller adgangskode var ikke korrekt.'; $PALANG['pLogin_login_users'] = 'Log ind på brugersektionen her.'; $PALANG['pMenu_main'] = 'Start'; $PALANG['pMenu_overview'] = 'Oversigt'; $PALANG['pMenu_create_alias'] = 'Tilføj alias'; $PALANG['pMenu_create_alias_domain'] = 'Tilføje alias domæne'; $PALANG['pMenu_create_mailbox'] = 'Tilføj postboks'; $PALANG['pMenu_fetchmail'] = 'Hent email'; $PALANG['pMenu_sendmail'] = 'Send email'; $PALANG['pMenu_password'] = 'Adgangskode'; $PALANG['pMenu_viewlog'] = 'Vis log'; $PALANG['pMenu_logout'] = 'Log ud'; $PALANG['pMain_welcome'] = 'Velkommen til postfixAdmin'; $PALANG['pMain_overview'] = 'Vis alle aliases og postbokse. Du kan redigere/slette dem herfra.'; $PALANG['pMain_create_alias'] = 'Tilføj et nyt alias til et domæne.'; $PALANG['pMain_create_mailbox'] = 'Tilføj en ny postboks til et domæne.'; $PALANG['pMain_sendmail'] = 'Send en email til en eksisterende postboks.'; $PALANG['pMain_password'] = 'Ændre adgangskoden til din administratorkonto.'; $PALANG['pMain_viewlog'] = 'Vis logfiler.'; $PALANG['pMain_logout'] = 'Log af systemet.'; $PALANG['pOverview_disabled'] = 'Deaktiveret'; $PALANG['pOverview_unlimited'] = 'Ubegrænset'; $PALANG['pOverview_title'] = ':: Oprettede domæner'; $PALANG['pOverview_up_arrow'] = 'Gå til top'; $PALANG['pOverview_right_arrow'] = 'Næste side'; $PALANG['pOverview_left_arrow'] = 'Foregående side'; $PALANG['pOverview_alias_domain_title'] = ':: Domæne aliases'; $PALANG['pOverview_alias_title'] = ':: Alias'; $PALANG['pOverview_mailbox_title'] = ':: Postbokse'; $PALANG['pOverview_button'] = 'Vis'; $PALANG['pOverview_welcome'] = 'Oversigt for '; $PALANG['pOverview_alias_domain_aliases'] = 'Alias domæner'; $PALANG['pOverview_alias_domain_target'] = '%s er et alias domæne for:'; $PALANG['pOverview_alias_alias_count'] = 'Alias'; $PALANG['pOverview_alias_mailbox_count'] = 'Postbokse'; $PALANG['pOverview_alias_address'] = 'Alias'; $PALANG['pOverview_alias_goto'] = 'Modtager'; $PALANG['pOverview_alias_modified'] = 'Senest ændret'; $PALANG['pOverview_alias_domain_modified'] = 'Senest ændret'; $PALANG['pOverview_alias_active'] = 'Aktiveret'; $PALANG['pOverview_alias_domain_active'] = 'Aktiveret'; $PALANG['pOverview_alias_edit'] = 'Alias'; $PALANG['and_x_more'] = '[og %s til...]'; $PALANG['pOverview_mailbox_username'] = 'Emailadresse'; $PALANG['pOverview_mailbox_name'] = 'Navn'; $PALANG['pOverview_mailbox_quota'] = 'Kvota (MB)'; $PALANG['pOverview_mailbox_modified'] = 'Senest ændret'; $PALANG['pOverview_mailbox_active'] = 'Aktiv'; $PALANG['pOverview_vacation_edit'] = 'Autosvar er aktiveret'; $PALANG['pOverview_vacation_option'] = 'Angiv autosvar'; $PALANG['pOverview_get_domain'] = 'Domæne'; $PALANG['pOverview_get_aliases'] = 'Alias'; $PALANG['pOverview_get_alias_domains'] = 'Domæne aliases'; $PALANG['pOverview_get_mailboxes'] = 'Postbokse'; $PALANG['pOverview_get_quota'] = 'Postboks Kvota (MB)'; $PALANG['pOverview_get_modified'] = 'Senest ændret'; $PALANG['pDelete_delete_error'] = 'Kan ikke slette denne post '; $PALANG['pDelete_delete_success'] = '%s er slettet.'; $PALANG['pDelete_postdelete_error'] = 'Kunne ikke fjerne postkassen '; $PALANG['pDelete_domain_error'] = 'Dette domæne er ikke dit '; $PALANG['pDelete_domain_alias_error'] = 'Dette domæne er ikke dit '; $PALANG['pDelete_alias_error'] = 'Kunne ikke slette aliaset '; $PALANG['pCreate_alias_domain_welcome'] = 'Spejl adresser fra et domæne til et andet.'; $PALANG['pCreate_alias_domain_alias'] = 'Alias-domæne'; $PALANG['pCreate_alias_domain_alias_text'] = 'Domæne som emails kommer fra.'; $PALANG['pCreate_alias_domain_target'] = 'Modtager-domæne'; $PALANG['pCreate_alias_domain_target_text'] = 'Domæne hvor emails skal sendes til.'; $PALANG['pCreate_alias_domain_active'] = 'Aktiv'; $PALANG['pCreate_alias_domain_button'] = 'Tilføj alias domæne'; $PALANG['pCreate_alias_domain_error1'] = 'Du har ikke tilladelse til at lave den valgte konfiguration'; $PALANG['pCreate_alias_domain_error2'] = 'Den valgte konfiguration er ikke korrekt, vælg venligst en anden.'; $PALANG['pCreate_alias_domain_error3'] = 'Indsætning i databasen fejlede.'; $PALANG['pCreate_alias_domain_error4'] = 'Alle domænerne har allerede aliases.'; $PALANG['pCreate_alias_domain_success'] = 'Domæne-alias blev tilføjet alias-tabellen.'; $PALANG['pCreate_alias_welcome'] = 'Tilføj et nyt alias til domænet.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
Aliaset er ikke gyldigt.'; $PALANG['pCreate_alias_address_text_error2'] = '
Emailadressen eksisterer allerede, vælg venligst en anden.'; $PALANG['pCreate_alias_address_text_error3'] = '
Du har nået grænsen for antallet af aliases til domænet.'; $PALANG['pCreate_alias_goto'] = 'Modtager'; $PALANG['pCreate_alias_active'] = 'Aktiv'; $PALANG['pCreate_alias_button'] = 'Tilføj alias'; $PALANG['pCreate_alias_goto_text'] = 'Hvor emailen skal videresendes til.'; $PALANG['pCreate_alias_goto_text_error'] = 'Hvor emailen skal videresendes til.
Modtageradressen er ikke gyldig.'; $PALANG['pCreate_alias_result_error'] = 'Kan ikke tilføje aliaset til alias-tabellen.'; $PALANG['pCreate_alias_result_success'] = 'Aliaset er blevet tilføjet alias-tabellen.'; $PALANG['pCreate_alias_catchall_text'] = 'For at tilføje et stjerne-alias, brug en "*" som alias.
For domæne til domæne-videresending brug "*@domæne.tld" som modtager.'; $PALANG['pEdit_alias_welcome'] = 'Rediger alias.
En modtager pr. linje.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Kan ikke finde aliaset!'; $PALANG['pEdit_alias_goto'] = 'Modtager(e)'; $PALANG['pEdit_alias_active'] = 'Aktiv'; $PALANG['pEdit_alias_goto_text_error1'] = 'Du udfyldte ikke noget i Modtager(e)'; $PALANG['pEdit_alias_goto_text_error2'] = 'Den tilføjede emailadresse er ikke gyldig: '; $PALANG['pEdit_alias_domain_error'] = 'Dette domæne tilhører ikke dig: '; $PALANG['pEdit_alias_domain_result_error'] = 'Kan ikke ændre alias-domænet.'; $PALANG['pEdit_alias_forward_and_store'] = 'Aflever email til den lokale postboks.'; $PALANG['pEdit_alias_forward_only'] = 'Videresend til angivene emailadresse uden lokal kopi.'; $PALANG['pEdit_alias_button'] = 'Ret alias'; $PALANG['pEdit_alias_result_error'] = 'Kan ikke redigere aliaset.'; $PALANG['pCreate_mailbox_welcome'] = 'Tilføj en ny lokal postboks til domænet.'; $PALANG['pCreate_mailbox_username'] = 'Brugernavn'; $PALANG['pCreate_mailbox_username_text_error1'] = '
Emailadressen er ikke gyldig.'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Emailadressen eksisterer allerede. Vælg venligst en anden.'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Du har nået grænsen for antallet af postbokse til domæne.'; $PALANG['pCreate_mailbox_password'] = 'Adgangskode'; $PALANG['pCreate_mailbox_password2'] = 'Adgangskode (igen)'; $PALANG['pCreate_mailbox_password_text'] = 'Adgangskode til POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Adgangskode til POP3/IMAP
Adgangskoderne er ikke ens.
Eller tomme.
'; $PALANG['pCreate_mailbox_name'] = 'Navn'; $PALANG['pCreate_mailbox_name_text'] = 'Fulde navn'; $PALANG['pCreate_mailbox_quota'] = 'Kvota'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Den valgte kvota er for høj.'; $PALANG['pCreate_mailbox_active'] = 'Aktiv'; $PALANG['pCreate_mailbox_mail'] = 'Send velkomsthilsen'; $PALANG['pCreate_mailbox_button'] = 'Tilføj postboks'; $PALANG['pCreate_mailbox_result_error'] = 'Kan ikke tilføje postboksen til postboks-tabellen.'; $PALANG['pCreate_mailbox_result_success'] = 'Postboksen er tilføjet til postboks-tabellen.'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'Postkassen er tilføjet, men ingen (eller kun dele) af de foruddefinerede undermapper kunne oprettes.'; $PALANG['pEdit_mailbox_welcome'] = 'Rediger postboks.'; $PALANG['pEdit_mailbox_username'] = 'Brugernavn'; $PALANG['pEdit_mailbox_username_error'] = 'Kan ikke finde postboksen.'; $PALANG['pEdit_mailbox_password'] = 'Ny adgangskode'; $PALANG['pEdit_mailbox_password2'] = 'Ny adgangskode (igen)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Adgangskoderne er ikke ens.'; $PALANG['pEdit_mailbox_name'] = 'Navn'; $PALANG['pEdit_mailbox_name_text'] = 'Fulde navn'; $PALANG['pEdit_mailbox_quota'] = 'Kvota'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Den valgte kvota er for høj.'; $PALANG['pEdit_mailbox_domain_error'] = 'Dette domæne er ikke dit: '; $PALANG['pEdit_mailbox_button'] = 'Ret postboks'; $PALANG['pEdit_mailbox_result_error'] = 'Kan ikke ændre adgangskoden.'; $PALANG['pPassword_welcome'] = 'Ændr din adgangskode.'; $PALANG['pPassword_admin'] = 'Adgangskode'; $PALANG['pPassword_admin_text_error'] = 'Brugernavnet kunne ikke findes.'; $PALANG['pPassword_password_current'] = 'Nuværende adgangskode'; $PALANG['pPassword_password_current_text_error'] = 'Du glemte at skrive din nuværende adgangskode.'; $PALANG['pPassword_password'] = 'Ny adgangskode'; $PALANG['pPassword_password2'] = 'Ny adgangskode (igen)'; $PALANG['pPassword_password_text_error'] = 'Adgangskoderne er ikke ens.
Eller tomme.
'; $PALANG['pPassword_button'] = 'Ændr adgangskode'; $PALANG['pPassword_result_error'] = 'Kan ikke ændre adgangskoden.'; $PALANG['pPassword_result_success'] = 'Din adgangskode er ændret.'; $PALANG['pEdit_vacation_set'] = 'Ændr / Angiv autosvar'; $PALANG['pEdit_vacation_remove'] = 'Fjern autosvar'; $PALANG['pVacation_result_error'] = 'Indstillingerne til autosvar kunne ikke opdateres.'; $PALANG['pVacation_result_removed'] = 'Autosvar er fjernet.'; $PALANG['pVacation_result_added'] = 'Autosvar er aktiveret.'; $PALANG['pViewlog_welcome'] = 'Vis de sidste 10 poster for '; $PALANG['pViewlog_timestamp'] = 'Tidsstempel'; $PALANG['pViewlog_username'] = 'Administrator'; $PALANG['pViewlog_domain'] = 'Domæne'; $PALANG['pViewlog_action'] = 'Handling'; $PALANG['pViewlog_data'] = 'Data'; $PALANG['pViewlog_action_create_mailbox'] = 'tilføj postboks'; $PALANG['pViewlog_action_delete_mailbox'] = 'slet postboks'; $PALANG['pViewlog_action_edit_mailbox'] = 'rediger postboks'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'ændr postboks status'; $PALANG['pViewlog_action_create_alias'] = 'tilføj alias'; $PALANG['pViewlog_action_create_alias_domain'] = 'lav domæne-alias'; $PALANG['pViewlog_action_delete_alias'] = 'slet alias'; $PALANG['pViewlog_action_delete_alias_domain'] = 'slet domæne-alias'; $PALANG['pViewlog_action_edit_alias'] = 'rediger alias'; $PALANG['pViewlog_action_edit_alias_state'] = 'ændr alias status'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'ændr domæne-alias status'; $PALANG['pViewlog_action_edit_password'] = 'ændr adgangskode'; $PALANG['pViewlog_button'] = 'Vis'; $PALANG['pViewlog_result_error'] = 'Loggen kan ikke findes.'; $PALANG['pSendmail_welcome'] = 'Send en email.'; $PALANG['pSendmail_admin'] = 'Afsender'; $PALANG['pSendmail_to'] = 'Modtager'; $PALANG['pSendmail_to_text_error'] = 'Modtager er tom, eller har en ugyldig emailadresse.'; $PALANG['pSendmail_subject'] = 'Emne'; $PALANG['pSendmail_subject_text'] = 'Velkommen'; $PALANG['pSendmail_body'] = 'Meddelelse'; $PALANG['pSendmail_button'] = 'Send email'; $PALANG['pSendmail_result_error'] = 'Kan ikke sende email.'; $PALANG['pSendmail_result_success'] = 'Email sendt.'; $PALANG['pAdminMenu_list_admin'] = 'Administratorliste'; $PALANG['pAdminMenu_list_domain'] = 'Domæne-liste'; $PALANG['pAdminMenu_list_virtual'] = 'Virtuel Liste'; $PALANG['pAdminMenu_viewlog'] = 'Vis Log'; $PALANG['pAdminMenu_backup'] = 'Backup'; $PALANG['pAdminMenu_create_domain_admins'] = 'Domæne-administrator'; $PALANG['pAdminMenu_create_admin'] = 'Ny administrator'; $PALANG['pAdminMenu_create_domain'] = 'Nyt domæne'; $PALANG['pAdminMenu_create_alias'] = 'Nyt alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Ny postboks'; $PALANG['pAdminList_admin_domain'] = 'Domæne'; $PALANG['pAdminList_admin_username'] = 'Administrator'; $PALANG['pAdminList_admin_count'] = 'Domæner'; $PALANG['pAdminList_admin_modified'] = 'Senest ændret'; $PALANG['pAdminList_admin_active'] = 'Aktiv'; $PALANG['pAdminList_domain_domain'] = 'Domæne'; $PALANG['pAdminList_domain_description'] = 'Beskrivelse'; $PALANG['pAdminList_domain_aliases'] = 'Alias'; $PALANG['pAdminList_domain_mailboxes'] = 'Postbokse'; $PALANG['pAdminList_domain_maxquota'] = 'Maksimal kvota (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; $PALANG['pAdminList_domain_modified'] = 'Senest ændret'; $PALANG['pAdminList_domain_active'] = 'Aktiv'; $PALANG['pAdminList_virtual_button'] = 'Vis'; $PALANG['pAdminList_virtual_welcome'] = 'Oversigt for '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Alias'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Postbokse'; $PALANG['pAdminList_virtual_alias_address'] = 'Fra'; $PALANG['pAdminList_virtual_alias_goto'] = 'Til'; $PALANG['pAdminList_virtual_alias_modified'] = 'Senest ændret'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Email'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Navn'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Kvota (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Senest ændret'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Aktiv'; $PALANG['pAdminCreate_domain_welcome'] = 'Tilføj et nyt domæne'; $PALANG['pAdminCreate_domain_domain'] = 'Domæne'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Domænet eksisterer allerede.'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'Domænet er ikke gyldigt.'; $PALANG['pAdminCreate_domain_description'] = 'Beskrivelse'; $PALANG['pAdminCreate_domain_aliases'] = 'Alias'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = annullér | 0 = uendeligt'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Postbokse'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = annullér | 0 = uendeligt'; $PALANG['pAdminCreate_domain_maxquota'] = 'Maksimal kvota'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = annullér | 0 = uendeligt'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Præcisér transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Tilføj standard alias(es)'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'Mailserveren er backup MX'; $PALANG['pAdminCreate_domain_button'] = 'Tilføj domæne'; $PALANG['pAdminCreate_domain_result_error'] = 'Kan ikke tilføje domænet.'; $PALANG['pAdminCreate_domain_result_success'] = 'Domænet er tilføjet.'; $PALANG['pAdminDelete_admin_error'] = 'Administratoren kunne ikke slettes.'; $PALANG['pAdminDelete_domain_error'] = 'Domænet kunne ikke slettes.'; $PALANG['pAdminDelete_alias_domain_error'] = 'Domæne-aliaset kunne ikke slettes.'; $PALANG['pAdminEdit_domain_welcome'] = 'Redigér et domæne'; $PALANG['pAdminEdit_domain_domain'] = 'Domæne'; $PALANG['pAdminEdit_domain_description'] = 'Beskrivelse'; $PALANG['pAdminEdit_domain_aliases'] = 'Alias'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = annullér | 0 = uendeligt'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Postbokse'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = annullér | 0 = uendeligt'; $PALANG['pAdminEdit_domain_maxquota'] = 'Maksimal kvota'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = annullér | 0 = uendeligt'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Præcisér transport'; $PALANG['pAdminEdit_domain_backupmx'] = 'Mailserveren er backup MX'; $PALANG['pAdminEdit_domain_active'] = 'Aktiv'; $PALANG['pAdminEdit_domain_button'] = 'Rediger domæne'; $PALANG['pAdminEdit_domain_result_error'] = 'Kan ikke rette domænet.'; $PALANG['pAdminCreate_admin_welcome'] = 'Tilføj en ny domæneadministrator'; $PALANG['pAdminCreate_admin_username'] = 'Administrator'; $PALANG['pAdminCreate_admin_username_text'] = 'Emailadresse'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Emailadresse
Administrator er ikke en gyldig emailadresse.'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Emailadresse
Aministratoren findes allerede eller er ikke gyldig'; $PALANG['pAdminCreate_admin_password'] = 'Adgangskode'; $PALANG['pAdminCreate_admin_password2'] = 'Adgangskode (igen)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Adgangskoderne er ikke ens.
Eller tomme.
'; $PALANG['pAdminCreate_admin_button'] = 'Tilføj administrator'; $PALANG['pAdminCreate_admin_result_error'] = 'Administratoren kunne ikke tilføjes.'; $PALANG['pAdminCreate_admin_result_success'] = 'Administratoren er tilføjet.'; $PALANG['pAdminCreate_admin_address'] = 'Domæne'; $PALANG['pAdminEdit_admin_welcome'] = 'Redigér en domæneadministrator'; $PALANG['pAdminEdit_admin_username'] = 'Administrator'; $PALANG['pAdminEdit_admin_password'] = 'Adgangskode'; $PALANG['pAdminEdit_admin_password2'] = 'Adgangskode (igen)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Adgangskoderne er ikke ens.
Eller tomme.
'; $PALANG['pAdminEdit_admin_active'] = 'Aktiv'; $PALANG['pAdminEdit_admin_super_admin'] = 'Superadministrator'; $PALANG['pAdminEdit_admin_button'] = 'Redigér administrator'; $PALANG['pAdminEdit_admin_result_error'] = 'Kunne ikke rette administrator.'; $PALANG['pAdminEdit_admin_result_success'] = 'Administrator er rettet.'; $PALANG['pUsersLogin_welcome'] = 'Postboksbruger: Log ind for at ændre adgangskode og videresending.'; $PALANG['pUsersLogin_username'] = 'Brugernavn (email)'; $PALANG['pUsersLogin_password'] = 'Adgangskode'; $PALANG['pUsersLogin_button'] = 'Log ind'; $PALANG['pUsersLogin_username_incorrect'] = 'Dit brugernavn er forkert. Tjek at du bruger din emailadresse som brugernavn.'; $PALANG['pUsersLogin_password_incorrect'] = 'Din adgangskode er ikke korrekt.'; $PALANG['pUsersMenu_vacation'] = 'Autosvar'; $PALANG['pUsersMenu_edit_alias'] = 'Redigér videresending'; $PALANG['pUsersMenu_password'] = 'Ændr adgangskode'; $PALANG['pUsersMain_vacation'] = 'Tilføj en "ikke tilstede" besked eller et autosvar til din emailadresse.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' er AKTIVERET, klik \'' . $PALANG['pUsersMenu_vacation'] . '\' for at ' . $PALANG['edit'] . '/fjerne'; $PALANG['pUsersMain_edit_alias'] = 'Ændr levering/videresending af email.'; $PALANG['pUsersMain_password'] = 'Ændr din nuværende adgangskode.'; $PALANG['pUsersVacation_welcome'] = 'Autosvar.'; $PALANG['pUsersVacation_welcome_text'] = 'Du har allerede autosvar indstillet!'; $PALANG['pUsersVacation_subject'] = 'Emne'; $PALANG['pUsersVacation_subject_text'] = 'Ikke tilstede'; $PALANG['pUsersVacation_body'] = 'Meddelelse'; $PALANG['pUsersVacation_body_text'] = << til . I nødstilfælde kan kontaktes. EOM; $PALANG['pUsersVacation_button_away'] = 'Tager afsted'; $PALANG['pUsersVacation_button_back'] = 'Kommer tilbage'; $PALANG['pUsersVacation_result_error'] = 'Kan ikke opdatere indstillingerne for autosvar.'; $PALANG['pUsersVacation_result_success'] = 'Autosvar fjernet.'; $PALANG['pUsersVacation_activefrom'] = 'Aktiv fra'; $PALANG['pUsersVacation_activeuntil'] = 'Aktiv til'; $PALANG['pCreate_dbLog_createmailbox'] = 'tilføj postboks'; $PALANG['pCreate_dbLog_createalias'] = 'tilføj alias'; $PALANG['pDelete_dbLog_deletealias'] = 'slet alias'; $PALANG['pDelete_dbLog_deletemailbox'] = 'slet postboks'; $PALANG['pEdit_dbLog_editactive'] = 'ændr aktivtilstand'; $PALANG['pEdit_dbLog_editalias'] = 'redigér alias'; $PALANG['pEdit_dbLog_editmailbox'] = 'redigér postboks'; $PALANG['pSearch'] = 'søg'; $PALANG['pSearch_welcome'] = 'Søg efter: '; $PALANG['pReturn_to'] = 'Tilbage til'; $PALANG['pBroadcast_title'] = 'Rundsend meddelelse'; $PALANG['pBroadcast_from'] = 'Afsender'; $PALANG['pBroadcast_name'] = 'Dit navn'; $PALANG['pBroadcast_subject'] = 'Emne'; $PALANG['pBroadcast_message'] = 'Meddelelse'; $PALANG['pBroadcast_send'] = 'Send meddelelse'; $PALANG['pBroadcast_success'] = 'Din meddelelse er rundsendt.'; $PALANG['pAdminMenu_broadcast_message'] = 'Rundsend meddelse'; $PALANG['pBroadcast_error_empty'] = 'Felterne "Dit navn", "Emne" og "Meddelelse" skal alle udfyldes.'; $PALANG['pStatus_undeliverable'] = 'kan måske ikke leveres '; $PALANG['pStatus_custom'] = 'Leveres til '; $PALANG['pStatus_popimap'] = 'POP/IMAP '; $PALANG['pPasswordTooShort'] = "Adgangskoden er for kort. Der kræves mindst %s tegn"; $PALANG['pInvalidDomainRegex'] = "Ugyldigt domæne-navn %s. Fejlede regulært udtryks-tjek"; $PALANG['pInvalidDomainDNS'] = "Ugyldigt domæne %s, og/eller ikke fundet i DNS"; $PALANG['pInvalidMailRegex'] = "Ugyldig emailadresse. Fejlede regulært udtryks-tjek"; $PALANG['pFetchmail_welcome'] = 'Hent post for:'; $PALANG['pFetchmail_new_entry'] = 'Ny regel'; $PALANG['pFetchmail_database_save_error'] = 'Reglen kunne ikke gemmes i databasen.'; $PALANG['pFetchmail_database_save_success'] = 'Reglen er gemt i databasen.'; $PALANG['pFetchmail_error_invalid_id'] = "Reglen med ID %s eksisterer ikke."; $PALANG['pFetchmail_invalid_mailbox'] = 'Ugyldig postboks.'; $PALANG['pFetchmail_server_missing'] = 'Angiv navnet på fjernserveren.'; $PALANG['pFetchmail_user_missing'] = 'Angiv brugernavnet til fjernserveren.'; $PALANG['pFetchmail_password_missing'] = 'Angiv adgangskoden til fjernserveren.'; $PALANG['pFetchmail_field_id'] = 'ID'; $PALANG['pFetchmail_field_mailbox'] = 'Postboks'; $PALANG['pFetchmail_field_src_server'] = 'Server'; $PALANG['pFetchmail_field_src_auth'] = 'Godkendelsesmetode'; $PALANG['pFetchmail_field_src_user'] = 'Brugernavn'; $PALANG['pFetchmail_field_src_password'] = 'Adgangskode'; $PALANG['pFetchmail_field_src_folder'] = 'Mappe'; $PALANG['pFetchmail_field_poll_time'] = 'Prøve'; $PALANG['pFetchmail_field_fetchall'] = 'Hent alle'; $PALANG['pFetchmail_field_keep'] = 'Behold'; $PALANG['pFetchmail_field_protocol'] = 'Protokol'; $PALANG['pFetchmail_field_usessl'] = 'SSL aktiv'; $PALANG['pFetchmail_field_extra_options'] = 'Ekstra tilvalg'; $PALANG['pFetchmail_field_mda'] = 'MDA (Mail Delivery Agent)'; $PALANG['pFetchmail_field_date'] = 'Dato'; $PALANG['pFetchmail_field_returned_text'] = 'Returneret tekst'; $PALANG['pFetchmail_desc_id'] = 'Post ID'; $PALANG['pFetchmail_desc_mailbox'] = 'Lokal postboks'; $PALANG['pFetchmail_desc_src_server'] = 'Fjernserver'; $PALANG['pFetchmail_desc_src_auth'] = 'Somregel \'password\''; # Translators: Please do NOT translate 'password' here $PALANG['pFetchmail_desc_src_user'] = 'Eksternt brugernavn'; $PALANG['pFetchmail_desc_src_password'] = 'Ekstern adgangskode'; $PALANG['pFetchmail_desc_src_folder'] = 'Ekstern mappe'; $PALANG['pFetchmail_desc_poll_time'] = 'Prøv hvert ... minut'; $PALANG['pFetchmail_desc_fetchall'] = 'Hent både læste og nye beskeder'; $PALANG['pFetchmail_desc_keep'] = 'Gem hentede beskeder på den eksterne postserver'; $PALANG['pFetchmail_desc_protocol'] = 'Brug protokol'; $PALANG['pFetchmail_desc_usessl'] = 'SSL-kryptering'; $PALANG['pFetchmail_desc_extra_options'] = 'Ekstra flag til fetchmail'; $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; $PALANG['pFetchmail_desc_date'] = 'Dato for seneste prøve/konfigurationsændring'; $PALANG['pFetchmail_desc_returned_text'] = 'Tekstbesked fra seneste prøve'; $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/ja.lang0000664000175000017620000007004411636730120017466 0ustar davidpalepurple // $PALANG['YES'] = 'はい'; $PALANG['NO'] = 'いいえ'; $PALANG['edit'] = '編集'; $PALANG['del'] = '削除'; $PALANG['exit'] = '終了'; $PALANG['cancel'] = 'キャンセル'; $PALANG['save'] = '保存'; $PALANG['confirm'] = '本当に削除してもよろしいですか?\n'; $PALANG['confirm_domain'] = '本当にこのドメインのすべての情報を削除してもよろしいですか?これを元に戻すことはできません。\n'; $PALANG['check_update'] = '更新の確認'; $PALANG['invalid_parameter'] = '無効なパラメータです。'; $PALANG['pFooter_logged_as'] = 'ログイン名 %s'; $PALANG['pLogin_welcome'] = 'こちらからドメインの管理ができます。'; $PALANG['pLogin_username'] = 'ログイン (メールアドレス)'; $PALANG['pLogin_password'] = 'パスワード'; $PALANG['pLogin_button'] = 'ログイン'; $PALANG['pLogin_failed'] = 'Your email address or password are not correct.'; # XXX $PALANG['pLogin_login_users'] = '一般ユーザのログインはここをクリックしてください。'; $PALANG['pMenu_main'] = 'メイン'; $PALANG['pMenu_overview'] = '概要'; $PALANG['pMenu_create_alias'] = '転送先の追加'; $PALANG['pMenu_create_alias_domain'] = 'Add Alias Domain'; # XXX $PALANG['pMenu_create_mailbox'] = 'アドレスの追加'; $PALANG['pMenu_fetchmail'] = 'メール取得'; $PALANG['pMenu_sendmail'] = 'メール送信'; $PALANG['pMenu_password'] = 'パスワード'; $PALANG['pMenu_viewlog'] = 'ログ表示'; $PALANG['pMenu_logout'] = 'ログアウト'; $PALANG['pMain_welcome'] = 'Postfix Admin へようこそ!'; $PALANG['pMain_overview'] = '転送アドレスとメールアドレスの一覧を表示します。ここから編集と削除ができます。'; $PALANG['pMain_create_alias'] = '新しい転送アドレスを作成します。'; $PALANG['pMain_create_mailbox'] = '新しいメールアドレスを作成します。'; $PALANG['pMain_sendmail'] = '新しいメールアドレスにメールを送信します。'; $PALANG['pMain_password'] = 'パスワードを変更します。'; $PALANG['pMain_viewlog'] = 'ログファイルを表示します。'; $PALANG['pMain_logout'] = 'ログアウトします。'; $PALANG['pOverview_disabled'] = '無効'; $PALANG['pOverview_unlimited'] = '無制限'; $PALANG['pOverview_title'] = ':: 定義済ドメイン'; $PALANG['pOverview_up_arrow'] = 'トップ'; $PALANG['pOverview_right_arrow'] = '次ページ'; $PALANG['pOverview_left_arrow'] = '前ページ'; $PALANG['pOverview_alias_domain_title'] = ':: Domain Aliases'; # XXX $PALANG['pOverview_alias_title'] = ':: 転送アドレス'; $PALANG['pOverview_mailbox_title'] = ':: メールアドレス'; $PALANG['pOverview_button'] = '表示'; $PALANG['pOverview_welcome'] = '概要 '; $PALANG['pOverview_alias_domain_aliases'] = 'Alias Domains'; # XXX $PALANG['pOverview_alias_domain_target'] = '%s is an Alias Domain for:'; # XXX $PALANG['pOverview_alias_alias_count'] = '転送数'; $PALANG['pOverview_alias_mailbox_count'] = 'アドレス数'; $PALANG['pOverview_alias_address'] = '転送元'; $PALANG['pOverview_alias_goto'] = '転送先'; $PALANG['pOverview_alias_modified'] = '最終更新日'; $PALANG['pOverview_alias_domain_modified'] = 'Last Modified'; # XXX $PALANG['pOverview_alias_active'] = 'アクティブ'; $PALANG['pOverview_alias_domain_active'] = 'Active'; # XXX $PALANG['pOverview_alias_edit'] = '転送'; $PALANG['and_x_more'] = '[その他 %s 個]'; $PALANG['pOverview_mailbox_username'] = 'メールアドレス'; $PALANG['pOverview_mailbox_name'] = '名前'; $PALANG['pOverview_mailbox_quota'] = '容量制限 (MB)'; $PALANG['pOverview_mailbox_modified'] = '最終更新日'; $PALANG['pOverview_mailbox_active'] = 'アクティブ'; $PALANG['pOverview_vacation_edit'] = '自動応答 利用中'; $PALANG['pOverview_vacation_option'] = '自動応答'; $PALANG['pOverview_get_domain'] = 'ドメイン'; $PALANG['pOverview_get_aliases'] = '転送'; $PALANG['pOverview_get_alias_domains'] = 'Domain Aliases'; # XXX $PALANG['pOverview_get_mailboxes'] = 'アドレス'; $PALANG['pOverview_get_quota'] = '容量制限 (MB)'; $PALANG['pOverview_get_modified'] = '最終更新日'; $PALANG['pDelete_delete_error'] = 'エントリを削除できません。 '; $PALANG['pDelete_delete_success'] = '%s を削除しました。'; $PALANG['pDelete_postdelete_error'] = 'メールアドレスを削除できません。 '; $PALANG['pDelete_domain_error'] = 'このドメインは管理外です。 '; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = '転送アドレスを削除できません。 '; $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = '新しい転送先の作成'; $PALANG['pCreate_alias_address'] = '転送元アドレス'; $PALANG['pCreate_alias_address_text_error1'] = '
メールアドレスが無効です。'; $PALANG['pCreate_alias_address_text_error2'] = '
このメールアドレスは既に存在するので、
別のアドレスを選択してください。
'; $PALANG['pCreate_alias_address_text_error3'] = '
転送アドレスの制限数に達しました。'; $PALANG['pCreate_alias_goto'] = '転送先アドレス'; $PALANG['pCreate_alias_active'] = 'アクティブ'; $PALANG['pCreate_alias_button'] = '転送先追加'; $PALANG['pCreate_alias_goto_text'] = 'メールを転送するアドレス'; $PALANG['pCreate_alias_goto_text_error'] = 'メールを転送するアドレス
転送先が無効です。'; $PALANG['pCreate_alias_result_error'] = '転送先を追加できません!'; $PALANG['pCreate_alias_result_success'] = '転送先を追加しました。'; $PALANG['pCreate_alias_catchall_text'] = 'すべてのメールを受け取るには、転送元に "*" を使います。
別のドメインにすべて転送するには、転送先に "*.domain.tld" を使います。'; $PALANG['pEdit_alias_welcome'] = '転送先アドレスの編集
1行に1エントリです。'; $PALANG['pEdit_alias_address'] = '転送元'; $PALANG['pEdit_alias_address_error'] = '転送元が見つかりません!'; $PALANG['pEdit_alias_goto'] = '転送先'; $PALANG['pEdit_alias_active'] = 'アクティブ'; $PALANG['pEdit_alias_goto_text_error1'] = '転送先が入力されていません。'; $PALANG['pEdit_alias_goto_text_error2'] = 'このメールアドレスは無効です: '; $PALANG['pEdit_alias_domain_error'] = 'このドメインは管理外です: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'ローカルのメールボックスに残す'; $PALANG['pEdit_alias_forward_only'] = '指定された転送アドレスのみ'; $PALANG['pEdit_alias_button'] = '転送先修正'; $PALANG['pEdit_alias_result_error'] = '修正できません!'; $PALANG['pCreate_mailbox_welcome'] = '新しいメールアドレスの作成'; $PALANG['pCreate_mailbox_username'] = 'ユーザ名'; $PALANG['pCreate_mailbox_username_text_error1'] = '
メールアドレスが無効です。'; $PALANG['pCreate_mailbox_username_text_error2'] = '
このメールアドレスは既に存在するので、別のアドレスを選択してください。'; $PALANG['pCreate_mailbox_username_text_error3'] = '
メールアドレスの制限数に達しました。'; $PALANG['pCreate_mailbox_password'] = 'パスワード'; $PALANG['pCreate_mailbox_password2'] = 'パスワード (確認)'; $PALANG['pCreate_mailbox_password_text'] = 'POP3/IMAPのパスワード'; $PALANG['pCreate_mailbox_password_text_error'] = 'POP3/IMAPのパスワード
パスワードが一致しません。
または空です。
'; $PALANG['pCreate_mailbox_name'] = '名前'; $PALANG['pCreate_mailbox_name_text'] = 'フルネーム'; $PALANG['pCreate_mailbox_quota'] = '容量制限'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
指定された容量制限が大きすぎます。'; $PALANG['pCreate_mailbox_active'] = 'アクティブ'; $PALANG['pCreate_mailbox_mail'] = 'ようこそメールの送信'; $PALANG['pCreate_mailbox_button'] = 'メールアドレス追加'; $PALANG['pCreate_mailbox_result_error'] = 'メールアドレスを追加できません!'; $PALANG['pCreate_mailbox_result_success'] = 'メールアドレスを追加しました。'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'メールアドレスを追加しました。しかし、いくつかのサブフォルダの作成に失敗しました。'; $PALANG['pEdit_mailbox_welcome'] = 'メールアドレスの編集'; $PALANG['pEdit_mailbox_username'] = 'メールアドレス'; $PALANG['pEdit_mailbox_username_error'] = 'Unable to locate mailbox!'; $PALANG['pEdit_mailbox_password'] = '新しいパスワード'; $PALANG['pEdit_mailbox_password2'] = '新しいパスワード (確認)'; $PALANG['pEdit_mailbox_password_text_error'] = 'パスワードが一致しません。'; $PALANG['pEdit_mailbox_name'] = '名前'; $PALANG['pEdit_mailbox_name_text'] = 'フルネーム'; $PALANG['pEdit_mailbox_quota'] = '容量制限'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
指定された容量制限が大きすぎます。'; $PALANG['pEdit_mailbox_domain_error'] = 'このドメインは管理外です: '; $PALANG['pEdit_mailbox_button'] = 'メールアドレス修正'; $PALANG['pEdit_mailbox_result_error'] = '修正できません!'; $PALANG['pPassword_welcome'] = 'パスワードの変更'; $PALANG['pPassword_admin'] = 'ログイン'; $PALANG['pPassword_admin_text_error'] = '指定されたログインはメールボックスに一致しません。'; $PALANG['pPassword_password_current'] = '現在のパスワード'; $PALANG['pPassword_password_current_text_error'] = '現在のパスワードが入力されていません。'; $PALANG['pPassword_password'] = '新規パスワード'; $PALANG['pPassword_password2'] = '新規パスワード (確認)'; $PALANG['pPassword_password_text_error'] = 'パスワードが一致しません。
または空です。
'; $PALANG['pPassword_button'] = 'パスワード変更'; $PALANG['pPassword_result_error'] = 'パスワードを変更できません!'; $PALANG['pPassword_result_success'] = 'パスワードを変更しました。'; $PALANG['pEdit_vacation_set'] = 'メッセージ変更/設定'; $PALANG['pEdit_vacation_remove'] = 'メッセージ解除'; $PALANG['pVacation_result_error'] = '自動応答の設定を更新できませんでした!'; $PALANG['pVacation_result_removed'] = '自動応答を解除しました。'; $PALANG['pVacation_result_added'] = '自動応答を設定しました。'; $PALANG['pViewlog_welcome'] = '過去10個のアクション '; $PALANG['pViewlog_timestamp'] = 'タイムスタンプ'; $PALANG['pViewlog_username'] = '管理者'; $PALANG['pViewlog_domain'] = 'ドメイン'; $PALANG['pViewlog_action'] = 'アクション'; $PALANG['pViewlog_data'] = 'データ'; $PALANG['pViewlog_action_create_mailbox'] = 'アドレス作成'; $PALANG['pViewlog_action_delete_mailbox'] = 'アドレス削除'; $PALANG['pViewlog_action_edit_mailbox'] = 'アドレス編集'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'アドレス状態編集'; $PALANG['pViewlog_action_create_alias'] = '転送先作成'; $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = '転送先削除'; $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = '転送先編集'; $PALANG['pViewlog_action_edit_alias_state'] = '転送先状態編集'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'パスワード変更'; $PALANG['pViewlog_button'] = '表示'; $PALANG['pViewlog_result_error'] = 'ログが見つかりません!'; $PALANG['pSendmail_welcome'] = 'メール送信'; $PALANG['pSendmail_admin'] = '差出人'; $PALANG['pSendmail_to'] = '宛先'; $PALANG['pSendmail_to_text_error'] = '宛先が空欄か無効です。'; $PALANG['pSendmail_subject'] = '件名'; $PALANG['pSendmail_subject_text'] = 'ようこそ'; $PALANG['pSendmail_body'] = '本文'; $PALANG['pSendmail_button'] = 'メッセージ送信'; $PALANG['pSendmail_result_error'] = 'メールが送信できません!'; $PALANG['pSendmail_result_success'] = 'メールが送信されました。'; $PALANG['pAdminMenu_list_admin'] = '管理者一覧'; $PALANG['pAdminMenu_list_domain'] = 'ドメイン一覧'; $PALANG['pAdminMenu_list_virtual'] = 'アドレス一覧'; $PALANG['pAdminMenu_viewlog'] = 'ログ表示'; $PALANG['pAdminMenu_backup'] = 'バックアップ'; $PALANG['pAdminMenu_create_domain_admins'] = 'ドメイン管理者'; $PALANG['pAdminMenu_create_admin'] = '新しい管理者'; $PALANG['pAdminMenu_create_domain'] = '新しいドメイン'; $PALANG['pAdminMenu_create_alias'] = '転送先の追加'; $PALANG['pAdminMenu_create_mailbox'] = 'アドレスの追加'; $PALANG['pAdminList_admin_domain'] = 'ドメイン'; $PALANG['pAdminList_admin_username'] = '管理者'; $PALANG['pAdminList_admin_count'] = 'ドメイン数'; $PALANG['pAdminList_admin_modified'] = '最終更新日'; $PALANG['pAdminList_admin_active'] = 'アクティブ'; $PALANG['pAdminList_domain_domain'] = 'ドメイン'; $PALANG['pAdminList_domain_description'] = '説明'; $PALANG['pAdminList_domain_aliases'] = '転送数'; $PALANG['pAdminList_domain_mailboxes'] = 'アドレス数'; $PALANG['pAdminList_domain_maxquota'] = '容量制限 (MB)'; $PALANG['pAdminList_domain_transport'] = '配送方法'; $PALANG['pAdminList_domain_backupmx'] = 'バックアップ MX'; $PALANG['pAdminList_domain_modified'] = '最終更新日'; $PALANG['pAdminList_domain_active'] = 'アクティブ'; $PALANG['pAdminList_virtual_button'] = '表示'; $PALANG['pAdminList_virtual_welcome'] = '概要 '; $PALANG['pAdminList_virtual_alias_alias_count'] = '転送数'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'アドレス数'; $PALANG['pAdminList_virtual_alias_address'] = '転送元'; $PALANG['pAdminList_virtual_alias_goto'] = '転送先'; $PALANG['pAdminList_virtual_alias_modified'] = '最終更新日'; $PALANG['pAdminList_virtual_mailbox_username'] = 'メールアドレス'; $PALANG['pAdminList_virtual_mailbox_name'] = '名前'; $PALANG['pAdminList_virtual_mailbox_quota'] = '容量制限 (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = '最終更新日'; $PALANG['pAdminList_virtual_mailbox_active'] = 'アクティブ'; $PALANG['pAdminCreate_domain_welcome'] = '新しいドメインの追加'; $PALANG['pAdminCreate_domain_domain'] = 'ドメイン'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'ドメインが既に存在します。'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'ドメインが無効です。'; $PALANG['pAdminCreate_domain_description'] = '説明'; $PALANG['pAdminCreate_domain_aliases'] = '最大転送先数'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = 無効 | 0 = 無制限'; $PALANG['pAdminCreate_domain_mailboxes'] = '最大メールアドレス数'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = 無効 | 0 = 無制限'; $PALANG['pAdminCreate_domain_maxquota'] = '最大容量制限'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = 無効 | 0 = 無制限'; $PALANG['pAdminCreate_domain_transport'] = '配送方法'; $PALANG['pAdminCreate_domain_transport_text'] = '配送方法の定義'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'デフォルト転送先の追加'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'バックアップ MXサーバ'; $PALANG['pAdminCreate_domain_button'] = 'ドメイン追加'; $PALANG['pAdminCreate_domain_result_error'] = 'ドメインを追加できません!'; $PALANG['pAdminCreate_domain_result_success'] = 'ドメインを追加しました。'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'ドメインが削除できません!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = 'ドメインの修正'; $PALANG['pAdminEdit_domain_domain'] = 'ドメイン'; $PALANG['pAdminEdit_domain_description'] = '説明'; $PALANG['pAdminEdit_domain_aliases'] = '最大転送先数'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = 無効 | 0 = 無制限'; $PALANG['pAdminEdit_domain_mailboxes'] = '最大メールアドレス'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = 無効 | 0 = 無制限'; $PALANG['pAdminEdit_domain_maxquota'] = '最大容量制限'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = 無効 | 0 = 無制限'; $PALANG['pAdminEdit_domain_transport'] = '配送方法'; $PALANG['pAdminEdit_domain_transport_text'] = '配送方法の定義'; $PALANG['pAdminEdit_domain_backupmx'] = 'バックアップ MXサーバ'; $PALANG['pAdminEdit_domain_active'] = 'アクティブ'; $PALANG['pAdminEdit_domain_button'] = 'ドメイン修正'; $PALANG['pAdminEdit_domain_result_error'] = 'ドメインが修正できません!'; $PALANG['pAdminCreate_admin_welcome'] = '新しいドメイン管理者の追加'; $PALANG['pAdminCreate_admin_username'] = 'ドメイン管理者'; $PALANG['pAdminCreate_admin_username_text'] = 'メールアドレス'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'メールアドレス
管理者は有効なメールアドレスではありません。'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'メールアドレス
管理者は存在するか無効です。'; $PALANG['pAdminCreate_admin_password'] = 'パスワード'; $PALANG['pAdminCreate_admin_password2'] = 'パスワード (確認)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'パスワードが一致しません。
または空です。
'; $PALANG['pAdminCreate_admin_button'] = '管理者追加'; $PALANG['pAdminCreate_admin_result_error'] = '管理者を追加できません!'; $PALANG['pAdminCreate_admin_result_success'] = '管理者を追加しました。'; $PALANG['pAdminCreate_admin_address'] = 'ドメイン'; $PALANG['pAdminEdit_admin_welcome'] = 'ドメイン管理者の編集'; $PALANG['pAdminEdit_admin_username'] = '管理者'; $PALANG['pAdminEdit_admin_password'] = 'パスワード'; $PALANG['pAdminEdit_admin_password2'] = 'パスワード (確認)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'パスワードが一致しません。
または空です。
'; $PALANG['pAdminEdit_admin_active'] = 'アクティブ'; $PALANG['pAdminEdit_admin_super_admin'] = '特権管理者'; $PALANG['pAdminEdit_admin_button'] = '管理者修正'; $PALANG['pAdminEdit_admin_result_error'] = '管理者を修正できません!'; $PALANG['pAdminEdit_admin_result_success'] = '管理者を修正しました。'; $PALANG['pUsersLogin_welcome'] = 'あなたのパスワードと転送先が変更できます。'; $PALANG['pUsersLogin_username'] = 'ログイン (メールアドレス)'; $PALANG['pUsersLogin_password'] = 'パスワード'; $PALANG['pUsersLogin_button'] = 'ログイン'; $PALANG['pUsersLogin_username_incorrect'] = 'ログインが違います。正しいメールアドレスを入力してください。'; $PALANG['pUsersLogin_password_incorrect'] = 'パスワードが違います。'; $PALANG['pUsersMenu_vacation'] = '自動応答'; $PALANG['pUsersMenu_edit_alias'] = '転送先変更'; $PALANG['pUsersMenu_password'] = 'パスワード変更'; $PALANG['pUsersMain_vacation'] = '不在メッセージまたは自動応答を設定します'; $PALANG['pUsersMain_vacationSet'] = '自動応答を利用中です。「自動応答」をクリックして編集/解除できます。'; $PALANG['pUsersMain_edit_alias'] = '転送設定を変更します。'; $PALANG['pUsersMain_password'] = 'パスワードを変更します。'; $PALANG['pUsersVacation_welcome'] = '自動応答'; $PALANG['pUsersVacation_welcome_text'] = '既に自動応答を構成してあります。'; $PALANG['pUsersVacation_subject'] = '件名'; $PALANG['pUsersVacation_subject_text'] = '不在'; $PALANG['pUsersVacation_body'] = '本文'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << から まで不在です。 緊急事項は まで連絡してください。 EOM; $PALANG['pUsersVacation_button_away'] = '設定'; $PALANG['pUsersVacation_button_back'] = '解除'; $PALANG['pUsersVacation_result_error'] = '自動応答の設定を更新できませんでした!'; $PALANG['pUsersVacation_result_success'] = '自動応答を解除しました。'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'create mailbox'; # XXX $PALANG['pCreate_dbLog_createalias'] = 'create alias'; # XXX $PALANG['pDelete_dbLog_deletealias'] = 'delete alias'; # XXX $PALANG['pDelete_dbLog_deletemailbox'] = 'delete mailbox'; # XXX $PALANG['pEdit_dbLog_editactive'] = 'change active state'; # XXX $PALANG['pEdit_dbLog_editalias'] = 'edit alias'; # XXX $PALANG['pEdit_dbLog_editmailbox'] = 'edit mailbox'; # XXX $PALANG['pSearch'] = '検索'; $PALANG['pSearch_welcome'] = '検索文字列: '; $PALANG['pReturn_to'] = '戻る: '; $PALANG['pBroadcast_title'] = 'ブロードキャストメッセージの送信'; $PALANG['pBroadcast_from'] = '差出人'; $PALANG['pBroadcast_name'] = '名前'; $PALANG['pBroadcast_subject'] = '件名'; $PALANG['pBroadcast_message'] = 'メッセージ'; $PALANG['pBroadcast_send'] = 'メッセージ送信'; $PALANG['pBroadcast_success'] = 'ブロードキャストメッセージは送信されました。'; $PALANG['pAdminMenu_broadcast_message'] = 'ブロードキャスト'; $PALANG['pBroadcast_error_empty'] = '名前、件名、メッセージは入力が必要です。'; $PALANG['pStatus_undeliverable'] = 'おそらく配送不可能 '; $PALANG['pStatus_custom'] = '配送先 '; $PALANG['pStatus_popimap'] = 'POP/IMAP '; $PALANG['pPasswordTooShort'] = "パスワードが短すぎます。最低 %s 文字必要です。"; # usage: flash_error(sprintf($PALANG['pPasswordTooShort'], $CONF['min_password_length'])); $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'メール取得:'; $PALANG['pFetchmail_new_entry'] = '新しいエントリ'; $PALANG['pFetchmail_database_save_error'] = 'このエントリをデータベースに保存できませんでした。'; $PALANG['pFetchmail_database_save_success'] = 'エントリをデータベースに保存しました。'; $PALANG['pFetchmail_error_invalid_id'] = 'ID %s のエントリが見つかりません。'; $PALANG['pFetchmail_invalid_mailbox'] = 'メールボックスが無効です!'; $PALANG['pFetchmail_server_missing'] = 'リモートサーバ名を入力してください。'; $PALANG['pFetchmail_user_missing'] = 'リモートユーザ名を入力してください。'; $PALANG['pFetchmail_password_missing'] = 'リモートパスワードを入力してください。'; $PALANG['pFetchmail_field_id'] = 'ID'; $PALANG['pFetchmail_field_mailbox'] = 'メールボックス'; $PALANG['pFetchmail_field_src_server'] = 'サーバ'; $PALANG['pFetchmail_field_src_auth'] = '認証タイプ'; $PALANG['pFetchmail_field_src_user'] = 'ユーザ'; $PALANG['pFetchmail_field_src_password'] = 'パスワード'; $PALANG['pFetchmail_field_src_folder'] = 'フォルダ'; $PALANG['pFetchmail_field_poll_time'] = '間隔'; $PALANG['pFetchmail_field_fetchall'] = 'すべて取得'; $PALANG['pFetchmail_field_keep'] = '残す'; $PALANG['pFetchmail_field_protocol'] = 'プロトコル'; $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = '追加オプション'; $PALANG['pFetchmail_field_mda'] = 'MDA'; $PALANG['pFetchmail_field_date'] = '日付'; $PALANG['pFetchmail_field_returned_text'] = '戻りテキスト'; $PALANG['pFetchmail_desc_id'] = 'レコード ID'; $PALANG['pFetchmail_desc_mailbox'] = 'ローカル メールボックス'; $PALANG['pFetchmail_desc_src_server'] = 'リモート サーバ'; $PALANG['pFetchmail_desc_src_auth'] = '大抵は \'password\''; # Translators: Please do NOT translate 'password' here $PALANG['pFetchmail_desc_src_user'] = 'リモート ユーザ'; $PALANG['pFetchmail_desc_src_password'] = 'リモート パスワード'; $PALANG['pFetchmail_desc_src_folder'] = 'リモート フォルダ'; $PALANG['pFetchmail_desc_poll_time'] = '分単位の確認間隔'; $PALANG['pFetchmail_desc_fetchall'] = '既読と新着メッセージを取得するか'; $PALANG['pFetchmail_desc_keep'] = 'リモートサーバに取得済メッセージを残すか'; $PALANG['pFetchmail_desc_protocol'] = '利用するプロトコル'; $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = '追加の fetchmail オプション'; $PALANG['pFetchmail_desc_mda'] = 'メール配送エージェント (Mail Delivery Agent)'; $PALANG['pFetchmail_desc_date'] = '最終取得確認/設定変更日時'; $PALANG['pFetchmail_desc_returned_text'] = '新着確認の戻りテキストメッセージ'; $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/sl.lang0000664000175000017620000006513511636730120017517 0ustar davidpalepurple // $PALANG['YES'] = 'DA'; $PALANG['NO'] = 'NE'; $PALANG['edit'] = 'uredi'; $PALANG['del'] = 'briši'; $PALANG['exit'] = 'Exit'; # XXX $PALANG['cancel'] = 'Cancel'; # XXX $PALANG['save'] = 'Save'; # XXX $PALANG['confirm'] = 'Ali ste prepričani, da želite brisati?\n'; $PALANG['confirm_domain'] = 'Ali ste prepričani, da želite brisati vse zapise za to domeno? Zapisi bodo izgubljeni za vedno!\n'; $PALANG['check_update'] = 'Preveri, če obstaja novejša različica'; $PALANG['invalid_parameter'] = 'Invalid parameter!'; # XXX $PALANG['pFooter_logged_as'] = 'Logged as %s'; # XXX $PALANG['pLogin_welcome'] = 'Administratorji se prijavite tukaj.'; $PALANG['pLogin_username'] = 'Uporabniško ime (e-poštni naslov)'; $PALANG['pLogin_password'] = 'Geslo'; $PALANG['pLogin_button'] = 'Prijavi'; $PALANG['pLogin_failed'] = 'Your email address or password are not correct.'; # XXX $PALANG['pLogin_login_users'] = 'Uporabniki kliknite tukaj, če želite nastaviti odsotnost ali spremeniti geslo.'; $PALANG['pMenu_main'] = 'Main'; # XXX $PALANG['pMenu_overview'] = 'Pregled'; $PALANG['pMenu_create_alias'] = 'Dodaj alias'; $PALANG['pMenu_create_alias_domain'] = 'Add Alias Domain'; # XXX $PALANG['pMenu_create_mailbox'] = 'Dodaj predal'; $PALANG['pMenu_fetchmail'] = 'Fetch Email'; # XXX $PALANG['pMenu_sendmail'] = 'Pošlji e-pošto'; $PALANG['pMenu_password'] = 'Geslo'; $PALANG['pMenu_viewlog'] = 'Preglej log'; $PALANG['pMenu_logout'] = 'Odjavi'; $PALANG['pMain_welcome'] = 'Dobrodošli v Postfix Adminu!'; $PALANG['pMain_overview'] = 'Seznam aliasov in predalov. Tukaj jih lahko urejate in/ali brišete.'; $PALANG['pMain_create_alias'] = 'Ustvari nov alias za določeno domeno.'; $PALANG['pMain_create_mailbox'] = 'Ustvari nov predal za določeno domeno.'; $PALANG['pMain_sendmail'] = 'Pošlji e-pošto v enega izmed novoustvarjenih predalov.'; $PALANG['pMain_password'] = 'Spremeni geslo za administratorja.'; $PALANG['pMain_viewlog'] = 'Pregled dnevniških datotek.'; $PALANG['pMain_logout'] = 'Odjava iz sistema'; $PALANG['pOverview_disabled'] = 'Disabled'; # XXX $PALANG['pOverview_unlimited'] = 'Unlimited'; # XXX $PALANG['pOverview_title'] = ':: Definirane domene'; $PALANG['pOverview_up_arrow'] = 'Na vrh'; $PALANG['pOverview_right_arrow'] = 'Naslednja stran'; $PALANG['pOverview_left_arrow'] = 'Prejsnja stran'; $PALANG['pOverview_alias_domain_title'] = ':: Domain Aliases'; # XXX $PALANG['pOverview_alias_title'] = ':: Alias'; $PALANG['pOverview_mailbox_title'] = ':: Predali'; $PALANG['pOverview_button'] = 'Pojdi'; $PALANG['pOverview_welcome'] = 'Pregled za '; $PALANG['pOverview_alias_domain_aliases'] = 'Alias Domains'; # XXX $PALANG['pOverview_alias_domain_target'] = '%s is an Alias Domain for:'; # XXX $PALANG['pOverview_alias_alias_count'] = 'Aliasi'; $PALANG['pOverview_alias_mailbox_count'] = 'Predali'; $PALANG['pOverview_alias_address'] = 'Od'; $PALANG['pOverview_alias_goto'] = 'Za'; $PALANG['pOverview_alias_modified'] = 'Zadnjič spremenjeno'; $PALANG['pOverview_alias_domain_modified'] = 'Last Modified'; # XXX $PALANG['pOverview_alias_active'] = 'Active'; # XXX $PALANG['pOverview_alias_domain_active'] = 'Active'; # XXX $PALANG['pOverview_alias_edit'] = 'Alias'; # XXX $PALANG['and_x_more'] = '[and %s more...]'; # XXX $PALANG['pOverview_mailbox_username'] = 'E-pošta'; $PALANG['pOverview_mailbox_name'] = 'Ime'; $PALANG['pOverview_mailbox_quota'] = 'Kvota (MB)'; $PALANG['pOverview_mailbox_modified'] = 'Zadnjič spremenjeno'; $PALANG['pOverview_mailbox_active'] = 'Aktiven'; $PALANG['pOverview_vacation_edit'] = 'VACATION IS ON'; # XXX $PALANG['pOverview_vacation_option'] = 'Set Vacation'; # XXX $PALANG['pOverview_get_domain'] = 'Domena'; $PALANG['pOverview_get_aliases'] = 'Aliasi'; $PALANG['pOverview_get_alias_domains'] = 'Domain Aliases'; # XXX $PALANG['pOverview_get_mailboxes'] = 'Predali'; $PALANG['pOverview_get_quota'] = 'Kvota za predale (MB)'; $PALANG['pOverview_get_modified'] = 'Zadnjič spremenjeno'; $PALANG['pDelete_delete_error'] = 'Vnosa ni bilo mogoče izbrisati '; $PALANG['pDelete_delete_success'] = '%s deleted.'; # XXX $PALANG['pDelete_postdelete_error'] = 'Unable to remove mailbox '; # XXX $PALANG['pDelete_domain_error'] = 'Izbrana domena ni pod vašim nadzorom '; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = 'Unable to delete alias '; # XXX $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = 'Ustvari nov alias za določeno domeno.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
Sintaksa aliasa je napačna!'; $PALANG['pCreate_alias_address_text_error2'] = '
Ta e-poštni naslov že obstaja, prosimo izberite drugega!'; $PALANG['pCreate_alias_address_text_error3'] = '
Maksimalno število aliasov je preseženo!'; $PALANG['pCreate_alias_goto'] = 'Za'; $PALANG['pCreate_alias_active'] = 'Active'; # XXX $PALANG['pCreate_alias_button'] = 'Dodaj alias'; $PALANG['pCreate_alias_goto_text'] = 'Kamor želite nasloviti pošto.'; $PALANG['pCreate_alias_goto_text_error'] = 'Kamor mora sporočilo dejansko prispeti.
Vnos "Za" je napačen!'; $PALANG['pCreate_alias_result_error'] = 'Aliasa ni bilo mogoče dodati!'; $PALANG['pCreate_alias_result_success'] = 'Alias je bil uspešno dodan!'; $PALANG['pCreate_alias_catchall_text'] = 'Če želite ustvariti "vseobsegajoči" alias, uporabite "*" namesto aliasa.
Za posredovanje iz domene na domeno, uporabite "*@domena.si" v "Za" polju.'; $PALANG['pEdit_alias_welcome'] = 'Uredi alias za določeno domeno.
V posamezni vrstici je lahko samo en naslov.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Aliasa ni bilo mogoče najti!'; $PALANG['pEdit_alias_goto'] = 'Za'; $PALANG['pEdit_alias_active'] = 'Active'; # XXX $PALANG['pEdit_alias_goto_text_error1'] = 'V polje "Za" niste vnesli ničesar!'; $PALANG['pEdit_alias_goto_text_error2'] = 'E-poštni naslov, ki ste ga vnesli, ni pravilen: '; $PALANG['pEdit_alias_domain_error'] = 'Izbrana domena ni pod vašim nadzorom: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Deliver to the local mailbox.'; # XXX $PALANG['pEdit_alias_forward_only'] = 'Forward to given email addresses only.'; # XXX $PALANG['pEdit_alias_button'] = 'Uredi alias'; $PALANG['pEdit_alias_result_error'] = 'Aliasa ni bilo mogoče spremeniti!'; $PALANG['pCreate_mailbox_welcome'] = 'Ustvari nov predal za izbrano domeno.'; $PALANG['pCreate_mailbox_username'] = 'Uporabniško ime'; $PALANG['pCreate_mailbox_username_text_error1'] = '
E-poštni naslov ni pravilen!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Izbrani e-poštni naslov že obstaja, prosimo izberite drugega!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Maksimalno število predalov je preseženo!'; $PALANG['pCreate_mailbox_password'] = 'Geslo'; $PALANG['pCreate_mailbox_password2'] = 'Geslo (ponovitev)'; $PALANG['pCreate_mailbox_password_text'] = 'Geslo za POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Geslo za POP3/IMAP
Vnešeni gesli se razlikujeta
ali pa sta prazni!
'; $PALANG['pCreate_mailbox_name'] = 'Ime'; $PALANG['pCreate_mailbox_name_text'] = 'Polno ime'; $PALANG['pCreate_mailbox_quota'] = 'Kvota'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Vnešena kvota je prevelika!'; $PALANG['pCreate_mailbox_active'] = 'Aktiven'; $PALANG['pCreate_mailbox_mail'] = 'Ustvari predal'; $PALANG['pCreate_mailbox_button'] = 'Dodaj predal'; $PALANG['pCreate_mailbox_result_error'] = 'Predala ni bilo mogoče ustvariti!'; $PALANG['pCreate_mailbox_result_success'] = 'Predal je bil uspešno ustvarjen!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'The mailbox has been added to the mailbox table, but none (or only some) of the predefined sub-folders could be created'; # XXX $PALANG['pEdit_mailbox_welcome'] = 'Uredi določen predal za izbrano domeno.'; $PALANG['pEdit_mailbox_username'] = 'Uporabniško ime'; $PALANG['pEdit_mailbox_username_error'] = 'Izbranega predala ni bilo mogoče najti!'; $PALANG['pEdit_mailbox_password'] = 'Novo geslo'; $PALANG['pEdit_mailbox_password2'] = 'Novo geslo (ponovitev)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Vnešeni gesli se ne ujemata!'; $PALANG['pEdit_mailbox_name'] = 'Ime'; $PALANG['pEdit_mailbox_name_text'] = 'Full name'; # XXX $PALANG['pEdit_mailbox_quota'] = 'Kvota'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Vnešena kvota je prevelika!'; $PALANG['pEdit_mailbox_domain_error'] = 'Izbrana domena ni pod vašim nadzorom: '; $PALANG['pEdit_mailbox_button'] = 'Uredi predal'; $PALANG['pEdit_mailbox_result_error'] = 'Predala ni bilo mogoče spremeniti!'; $PALANG['pPassword_welcome'] = 'Sprimenjanje gesla.'; $PALANG['pPassword_admin'] = 'Uporabniško ime'; $PALANG['pPassword_admin_text_error'] = 'Uporabniško ime ne ustreza predalu!'; $PALANG['pPassword_password_current'] = 'Trenutno geslo'; $PALANG['pPassword_password_current_text_error'] = 'Vnesti morate trenutno geslo!'; $PALANG['pPassword_password'] = 'Novo geslo'; $PALANG['pPassword_password2'] = 'Novo geslo (ponovitev)'; $PALANG['pPassword_password_text_error'] = 'Vnešeni gesli se ne ujemata
ali pa sta prazni!
'; $PALANG['pPassword_button'] = 'Spremeni geslo'; $PALANG['pPassword_result_error'] = 'Gesla ni bilo mogoče spremeniti!'; $PALANG['pPassword_result_success'] = 'Geslo je bilo uspešno spremenjeno!'; $PALANG['pEdit_vacation_set'] = 'Change / Set away message'; # XXX $PALANG['pEdit_vacation_remove'] = 'Remove away message'; # XXX $PALANG['pVacation_result_error'] = 'Unable to update auto response settings!'; # XXX $PALANG['pVacation_result_removed'] = 'Auto response has been removed!'; # XXX $PALANG['pVacation_result_added'] = 'Auto response has been enabled!'; # XXX $PALANG['pViewlog_welcome'] = 'Seznam zadnjih 10 operacij za '; $PALANG['pViewlog_timestamp'] = 'Čas'; $PALANG['pViewlog_username'] = 'Administrator'; $PALANG['pViewlog_domain'] = 'Domena'; $PALANG['pViewlog_action'] = 'Operacija'; $PALANG['pViewlog_data'] = 'Podatki'; $PALANG['pViewlog_action_create_mailbox'] = 'create mailbox'; # XXX $PALANG['pViewlog_action_delete_mailbox'] = 'delete mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox'] = 'edit mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox_state'] = 'edit mailbox active'; # XXX $PALANG['pViewlog_action_create_alias'] = 'create alias'; # XXX $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'delete alias'; # XXX $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'edit alias'; # XXX $PALANG['pViewlog_action_edit_alias_state'] = 'edit alias active'; # XXX $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'change password'; # XXX $PALANG['pViewlog_button'] = 'Pojdi'; $PALANG['pViewlog_result_error'] = 'Dnevnikov ni bilo mogoče najti!'; $PALANG['pSendmail_welcome'] = 'Pošlji e-pošto.'; $PALANG['pSendmail_admin'] = 'Od'; $PALANG['pSendmail_to'] = 'Za'; $PALANG['pSendmail_to_text_error'] = 'Polje "Za" ne vsebuje veljavnega e-poštnega naslova!'; $PALANG['pSendmail_subject'] = 'Zadeva'; $PALANG['pSendmail_subject_text'] = 'Pozdravljeni!'; $PALANG['pSendmail_body'] = 'Besedilo'; $PALANG['pSendmail_button'] = 'Pošlji sporočilo'; $PALANG['pSendmail_result_error'] = 'Predala ni bilo mogoče ustvariti!'; # XXX text change - new: Unable to send email! $PALANG['pSendmail_result_success'] = 'Predal je bil uspešno ustvarjen!'; # XXX text change - new: Email sent! $PALANG['pAdminMenu_list_admin'] = 'Seznam administratorjev'; $PALANG['pAdminMenu_list_domain'] = 'Seznam domen'; $PALANG['pAdminMenu_list_virtual'] = 'Seznam aliasov in predalov'; $PALANG['pAdminMenu_viewlog'] = 'Pregled dnevnika'; $PALANG['pAdminMenu_backup'] = 'Rezervna kopija'; $PALANG['pAdminMenu_create_domain_admins'] = 'Domenski administratorji'; $PALANG['pAdminMenu_create_admin'] = 'Nov administrator'; $PALANG['pAdminMenu_create_domain'] = 'Nova domena'; $PALANG['pAdminMenu_create_alias'] = 'Dodaj alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Dodaj predal'; $PALANG['pAdminList_admin_domain'] = 'Domena'; $PALANG['pAdminList_admin_username'] = 'Administrator'; $PALANG['pAdminList_admin_count'] = 'Domene'; $PALANG['pAdminList_admin_modified'] = 'Zadnjič spremenjeno'; $PALANG['pAdminList_admin_active'] = 'Aktiven'; $PALANG['pAdminList_domain_domain'] = 'Domena'; $PALANG['pAdminList_domain_description'] = 'Opis'; $PALANG['pAdminList_domain_aliases'] = 'Aliasi'; $PALANG['pAdminList_domain_mailboxes'] = 'Predali'; $PALANG['pAdminList_domain_maxquota'] = 'Maksimalna kvota (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; # XXX $PALANG['pAdminList_domain_modified'] = 'Zadnjič spremenjeno'; $PALANG['pAdminList_domain_active'] = 'Aktiven'; $PALANG['pAdminList_virtual_button'] = 'Pojdi'; $PALANG['pAdminList_virtual_welcome'] = 'Pregled za: '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Aliasi'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Predali'; $PALANG['pAdminList_virtual_alias_address'] = 'Od'; $PALANG['pAdminList_virtual_alias_goto'] = 'Za'; $PALANG['pAdminList_virtual_alias_modified'] = 'Zadnjič spremenjeno'; $PALANG['pAdminList_virtual_mailbox_username'] = 'E-pošta'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Ime'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Kvota (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Zadnjič spremenjeno'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Aktiven'; $PALANG['pAdminCreate_domain_welcome'] = 'Dodaj novo domeno'; $PALANG['pAdminCreate_domain_domain'] = 'Domena'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Vnešena domena že obstaja!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'The domain is invalid!'; # XXX $PALANG['pAdminCreate_domain_description'] = 'Opis'; $PALANG['pAdminCreate_domain_aliases'] = 'Aliasi'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = onemogoči | 0 = neomejeno'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Predali'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = onemogoči | 0 = neomejeno'; $PALANG['pAdminCreate_domain_maxquota'] = 'Maksimalna kvota'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = onemogoči | 0 = neomejeno'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Definiraj transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Dodaj privzete aliase'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'Poštni strežnik je sekundarni MX'; $PALANG['pAdminCreate_domain_button'] = 'Dodaj domeno'; $PALANG['pAdminCreate_domain_result_error'] = 'Domene ni bilo mogoče dodati!'; $PALANG['pAdminCreate_domain_result_success'] = 'Domena je bila uspešno dodana!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Unable to remove domain!'; # XXX $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = 'Uredi domeno'; $PALANG['pAdminEdit_domain_domain'] = 'Domena'; $PALANG['pAdminEdit_domain_description'] = 'Opis'; $PALANG['pAdminEdit_domain_aliases'] = 'Aliasi'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = onemogoči | 0 = neomejeno'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Predali'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = onemogoči | 0 = neomejeno'; $PALANG['pAdminEdit_domain_maxquota'] = 'Maksimalna kvota'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = onemogoči | 0 = neomejeno'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Define transport'; # XXX $PALANG['pAdminEdit_domain_backupmx'] = 'Poštni strežnik je sekundarni MX'; $PALANG['pAdminEdit_domain_active'] = 'Aktiven'; $PALANG['pAdminEdit_domain_button'] = 'Shrani'; $PALANG['pAdminEdit_domain_result_error'] = 'Domene ni bilo mogoče spremeniti!'; $PALANG['pAdminCreate_admin_welcome'] = 'Dodaj domenskega administratorja'; $PALANG['pAdminCreate_admin_username'] = 'Administrator'; $PALANG['pAdminCreate_admin_username_text'] = 'E-poštni naslov'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'E-poštni naslov
Administrator ni veljaven e-poštni naslov!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'E-poštni naslov
Adminstrator že obstaja ali pa ni pravilen'; $PALANG['pAdminCreate_admin_password'] = 'Geslo'; $PALANG['pAdminCreate_admin_password2'] = 'Geslo (ponovitev)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Vnešeni gesli se ne ujemata
ali pa sta prazni!
'; $PALANG['pAdminCreate_admin_button'] = 'Dodaj administratorja'; $PALANG['pAdminCreate_admin_result_error'] = 'Administratorja ni bilo mogoče dodati!'; $PALANG['pAdminCreate_admin_result_success'] = 'Admininstrator je bil uspešno dodan'; $PALANG['pAdminCreate_admin_address'] = 'Domena'; $PALANG['pAdminEdit_admin_welcome'] = 'Uredi domenskega administratorja'; $PALANG['pAdminEdit_admin_username'] = 'Administrator'; $PALANG['pAdminEdit_admin_password'] = 'Geslo'; $PALANG['pAdminEdit_admin_password2'] = 'Geslo (ponovitev)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Vnešeni gesli se ne ujemata
ali pa sta prazni!
'; $PALANG['pAdminEdit_admin_active'] = 'Aktiven'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super admin'; # XXX $PALANG['pAdminEdit_admin_button'] = 'Shrani'; $PALANG['pAdminEdit_admin_result_error'] = 'Administratorja ni bilo mogoče spremeniti!'; $PALANG['pAdminEdit_admin_result_success'] = 'Admininstrator je bil uspešno spremenjen!'; $PALANG['pUsersLogin_welcome'] = 'Če želite spremeniti gesli ali nastaviti sporočilo o odsotnosti, se prijavite.'; $PALANG['pUsersLogin_username'] = 'E-poštni naslov'; $PALANG['pUsersLogin_password'] = 'Geslo'; $PALANG['pUsersLogin_button'] = 'Prijava'; $PALANG['pUsersLogin_username_incorrect'] = 'Uporabniško ime ni pravilno! Uporabiti morate svoj e-poštni naslov!'; $PALANG['pUsersLogin_password_incorrect'] = 'Geslo ni pravilno!'; $PALANG['pUsersMenu_vacation'] = 'Obvestilo o odsotnosti'; $PALANG['pUsersMenu_edit_alias'] = 'Nastavi preusmeritev'; $PALANG['pUsersMenu_password'] = 'Spremeni geslo'; $PALANG['pUsersMain_vacation'] = 'Nastavite obvestilo o odsotnosti.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' is ON, click \'' . $PALANG['pUsersMenu_vacation'] . '\' to ' . $PALANG['edit'] . '/remove'; # XXX $PALANG['pUsersMain_edit_alias'] = 'Nastavite preusmeritev na drug e-poštni naslov.'; $PALANG['pUsersMain_password'] = 'Spremenite geslo.'; $PALANG['pUsersVacation_welcome'] = 'Tukaj lahko nastavite obvestilo o odsotnosti.'; $PALANG['pUsersVacation_welcome_text'] = 'Obvestilo o odsotnosti imate že nastavljeno!'; $PALANG['pUsersVacation_subject'] = 'Zadeva'; $PALANG['pUsersVacation_subject_text'] = 'Odsotnost'; $PALANG['pUsersVacation_body'] = 'Besedilo'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << do sem odsoten. Za nujne zadeve prosim kontaktirajte . EOM; $PALANG['pUsersVacation_button_away'] = 'Vključi odsotnost'; $PALANG['pUsersVacation_button_back'] = 'Izključi odsotnost'; $PALANG['pUsersVacation_result_error'] = 'Vašim nastavitev o odsotnosti ni bilo mogoče posodobiti!'; $PALANG['pUsersVacation_result_success'] = 'Obvestilo o odsotnosti je izključeno!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'ustvari predal'; $PALANG['pCreate_dbLog_createalias'] = 'ustvari alias'; $PALANG['pDelete_dbLog_deletealias'] = 'briši alias'; $PALANG['pDelete_dbLog_deletemailbox'] = 'briši predal'; $PALANG['pEdit_dbLog_editactive'] = 'spremeni stanje aktivnosti'; $PALANG['pEdit_dbLog_editalias'] = 'uredi alias'; $PALANG['pEdit_dbLog_editmailbox'] = 'uredi predal'; $PALANG['pSearch'] = 'search'; # XXX $PALANG['pSearch_welcome'] = 'Išči: '; $PALANG['pReturn_to'] = 'Return to'; # XXX $PALANG['pBroadcast_title'] = 'Send broadcast message'; # XXX $PALANG['pBroadcast_from'] = 'From'; # XXX $PALANG['pBroadcast_name'] = 'Your name'; # XXX $PALANG['pBroadcast_subject'] = 'Subject'; # XXX $PALANG['pBroadcast_message'] = 'Message'; # XXX $PALANG['pBroadcast_send'] = 'Send message'; # XXX $PALANG['pBroadcast_success'] = 'Your broadcast message was sent.'; # XXX $PALANG['pAdminMenu_broadcast_message'] = 'Broadcast message'; # XXX $PALANG['pBroadcast_error_empty'] = 'The fields Name, Subject and Message should\'t be empty !'; # XXX $PALANG['pStatus_undeliverable'] = 'maybe UNDELIVERABLE '; # XXX $PALANG['pStatus_custom'] = 'Delivers to '; # XXX $PALANG['pStatus_popimap'] = 'POP/IMAP '; # XXX $PALANG['pPasswordTooShort'] = "Password is too short - requires %s characters"; # XXX $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Fetch mail for:'; # XXX $PALANG['pFetchmail_new_entry'] = 'New entry'; # XXX $PALANG['pFetchmail_database_save_error'] = 'Could not save this entry in the database!'; # XXX $PALANG['pFetchmail_database_save_success'] = 'Entry saved in database.'; # XXX $PALANG['pFetchmail_error_invalid_id'] = 'No entry with ID %s found!'; # XXX $PALANG['pFetchmail_invalid_mailbox'] = 'Invalid mailbox!'; # XXX $PALANG['pFetchmail_server_missing'] = 'Please enter the remote server name!'; # XXX $PALANG['pFetchmail_user_missing'] = 'Please enter the remote username!'; # XXX $PALANG['pFetchmail_password_missing'] = 'Please enter the remote password!'; # XXX $PALANG['pFetchmail_field_id'] = 'ID'; # XXX $PALANG['pFetchmail_field_mailbox'] = 'Mailbox'; # XXX $PALANG['pFetchmail_field_src_server'] = 'Server'; # XXX $PALANG['pFetchmail_field_src_auth'] = 'Auth Type'; # XXX $PALANG['pFetchmail_field_src_user'] = 'User'; # XXX $PALANG['pFetchmail_field_src_password'] = 'Password'; # XXX $PALANG['pFetchmail_field_src_folder'] = 'Folder'; # XXX $PALANG['pFetchmail_field_poll_time'] = 'Poll'; # XXX $PALANG['pFetchmail_field_fetchall'] = 'Fetch All'; # XXX $PALANG['pFetchmail_field_keep'] = 'Keep'; # XXX $PALANG['pFetchmail_field_protocol'] = 'Protocol'; # XXX $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra Options'; # XXX $PALANG['pFetchmail_field_mda'] = 'MDA'; # XXX $PALANG['pFetchmail_field_date'] = 'Date'; # XXX $PALANG['pFetchmail_field_returned_text'] = 'Returned Text'; # XXX $PALANG['pFetchmail_desc_id'] = 'Record ID'; # XXX $PALANG['pFetchmail_desc_mailbox'] = 'Local mailbox'; # XXX $PALANG['pFetchmail_desc_src_server'] = 'Remote Server'; # XXX $PALANG['pFetchmail_desc_src_auth'] = 'Mostly \'password\''; # Translators: Please do NOT translate 'password' here # XXX $PALANG['pFetchmail_desc_src_user'] = 'Remote User'; # XXX $PALANG['pFetchmail_desc_src_password'] = 'Remote Password'; # XXX $PALANG['pFetchmail_desc_src_folder'] = 'Remote Folder'; # XXX $PALANG['pFetchmail_desc_poll_time'] = 'Poll every ... minutes'; # XXX $PALANG['pFetchmail_desc_fetchall'] = 'Retrieve both old (seen) and new messages'; # XXX $PALANG['pFetchmail_desc_keep'] = 'Keep retrieved messages on the remote mailserver'; # XXX $PALANG['pFetchmail_desc_protocol'] = 'Protocol to use'; # XXX $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Extra fetchmail Options'; # XXX $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; # XXX $PALANG['pFetchmail_desc_date'] = 'Date of last polling/configuration change'; # XXX $PALANG['pFetchmail_desc_returned_text'] = 'Text message from last polling'; # XXX $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/ca.lang0000664000175000017620000006547211636730120017470 0ustar davidpalepurpleImposible borrar el registre '; $PALANG['pDelete_delete_success'] = '%s deleted.'; # XXX $PALANG['pDelete_postdelete_error'] = 'Unable to remove mailbox '; # XXX $PALANG['pDelete_domain_error'] = 'Aquest domini no et pertany '; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = 'Unable to delete alias '; # XXX $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = 'Crear un nou àlies pel domini.'; $PALANG['pCreate_alias_address'] = 'Àlies'; $PALANG['pCreate_alias_address_text_error1'] = '
L\'àlies no és vàlid!'; $PALANG['pCreate_alias_address_text_error2'] = '
Aquesta adreça ja existeix, escull una altra de diferent, si us plau!'; $PALANG['pCreate_alias_address_text_error3'] = '
Has arribat al límit de creació d\'àlies!'; $PALANG['pCreate_alias_goto'] = 'Destí'; $PALANG['pCreate_alias_active'] = 'Active'; # XXX $PALANG['pCreate_alias_button'] = 'Afegir àlies'; $PALANG['pCreate_alias_goto_text'] = 'A on ha de ser enviat l\'e-mail.'; $PALANG['pCreate_alias_goto_text_error'] = 'A on ha de ser enviat l\'e-mail.
El destí no és vàlid!'; $PALANG['pCreate_alias_result_error'] = '¡No és posible afegir l\'àlies a la taula d\'àlies!'; $PALANG['pCreate_alias_result_success'] = 'L\'àlies ha estat creat correctament!'; $PALANG['pCreate_alias_catchall_text'] = 'Per crear un àlies general usi "*" com a àlies.
Per una redirecció de domini a domini, usi "*@domain.tld" com a Destí.'; $PALANG['pEdit_alias_welcome'] = 'Editi un àlies pel seu domini.
Una entrada per línia.'; $PALANG['pEdit_alias_address'] = 'Àlies'; $PALANG['pEdit_alias_address_error'] = 'Imposible de localizar l\'àlies!'; $PALANG['pEdit_alias_goto'] = 'Destí'; $PALANG['pEdit_alias_active'] = 'Active'; # XXX $PALANG['pEdit_alias_goto_text_error1'] = 'No has introduït res al destí'; $PALANG['pEdit_alias_goto_text_error2'] = 'L\'adreça d\'e-mail introduida no és vàlida: '; $PALANG['pEdit_alias_domain_error'] = 'Aquest domini no et pertany: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Deliver to the local mailbox.'; # XXX $PALANG['pEdit_alias_forward_only'] = 'Forward to given email addresses only.'; # XXX $PALANG['pEdit_alias_button'] = 'Editar àlies'; $PALANG['pEdit_alias_result_error'] = 'Imposible modificar l\'àlies!'; $PALANG['pCreate_mailbox_welcome'] = 'Crear una nova bústia pel seu domini.'; $PALANG['pCreate_mailbox_username'] = 'Usuari'; $PALANG['pCreate_mailbox_username_text_error1'] = '
L\'e-mail no és vàlido!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Aquest e-mail ja existeix, escull un de diferente si us plau!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Has arribat al límit de creació de bústies!'; $PALANG['pCreate_mailbox_password'] = 'Contrasenya'; $PALANG['pCreate_mailbox_password2'] = 'Contrasenya (repetir)'; $PALANG['pCreate_mailbox_password_text'] = 'Contrasenya per a POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Contrasenya per a POP3/IMAP
Les contrasenyes introduides no coincideixen
o estan en blanc!
'; $PALANG['pCreate_mailbox_name'] = 'Nom'; $PALANG['pCreate_mailbox_name_text'] = 'Nom complet'; $PALANG['pCreate_mailbox_quota'] = 'Quota'; # XXX $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
La quota especificada és massa alta!'; $PALANG['pCreate_mailbox_active'] = 'Actiu'; $PALANG['pCreate_mailbox_mail'] = 'Crear bústia'; $PALANG['pCreate_mailbox_button'] = 'Afegir bústia'; $PALANG['pCreate_mailbox_result_error'] = 'Imposible afegir una bústia a la taula de bústies!'; $PALANG['pCreate_mailbox_result_success'] = 'La bústia ha estat afegida a la taula de bústies!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'The mailbox has been added to the mailbox table, but none (or only some) of the predefined sub-folders could be created'; # XXX $PALANG['pEdit_mailbox_welcome'] = 'Editar una bústia pel seu domini.'; $PALANG['pEdit_mailbox_username'] = 'Usuari'; $PALANG['pEdit_mailbox_username_error'] = 'Imposible localitzar la bústia!'; $PALANG['pEdit_mailbox_password'] = 'Nova contrasenya'; $PALANG['pEdit_mailbox_password2'] = 'Nova contrasenya (repetiu)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Les contrasenyes introduides no coincideixen!'; $PALANG['pEdit_mailbox_name'] = 'Nom'; $PALANG['pEdit_mailbox_name_text'] = 'Full name'; # XXX $PALANG['pEdit_mailbox_quota'] = 'Quota'; # XXX $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
La quota especificada és massa alta!'; $PALANG['pEdit_mailbox_domain_error'] = 'Aquest domini no et pertany: '; $PALANG['pEdit_mailbox_button'] = 'Editar bústia'; $PALANG['pEdit_mailbox_result_error'] = 'Imposible canviar la contrasenya!'; $PALANG['pPassword_welcome'] = 'Canvia la teva contrasenya de login.'; $PALANG['pPassword_admin'] = 'Login'; $PALANG['pPassword_admin_text_error'] = 'El login suministrat no coincideix amb cap bústia!'; $PALANG['pPassword_password_current'] = 'Contrasenya actual'; $PALANG['pPassword_password_current_text_error'] = 'No ha introduït la contrasenya actual!'; $PALANG['pPassword_password'] = 'Nova contrasenya'; $PALANG['pPassword_password2'] = 'Nova contrasenya (repetiu)'; $PALANG['pPassword_password_text_error'] = 'Les contrasenyes introduides no coincideixen
o estan en blanc!
'; $PALANG['pPassword_button'] = 'Canviar la contrasenya'; $PALANG['pPassword_result_error'] = 'Imposible canviar la contrasenya!'; $PALANG['pPassword_result_success'] = 'La seva contrasenya ha estat canviada!'; $PALANG['pEdit_vacation_set'] = 'Change / Set away message'; # XXX $PALANG['pEdit_vacation_remove'] = 'Remove away message'; # XXX $PALANG['pVacation_result_error'] = 'Unable to update auto response settings!'; # XXX $PALANG['pVacation_result_removed'] = 'Auto response has been removed!'; # XXX $PALANG['pVacation_result_added'] = 'Auto response has been enabled!'; # XXX $PALANG['pViewlog_welcome'] = 'Veure les últimes 10 accions per '; $PALANG['pViewlog_timestamp'] = 'Data/Hora'; $PALANG['pViewlog_username'] = 'Administrador'; $PALANG['pViewlog_domain'] = 'Domini'; $PALANG['pViewlog_action'] = 'Acció'; $PALANG['pViewlog_data'] = 'Dades'; $PALANG['pViewlog_action_create_mailbox'] = 'create mailbox'; # XXX $PALANG['pViewlog_action_delete_mailbox'] = 'delete mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox'] = 'edit mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox_state'] = 'edit mailbox active'; # XXX $PALANG['pViewlog_action_create_alias'] = 'create alias'; # XXX $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'delete alias'; # XXX $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'edit alias'; # XXX $PALANG['pViewlog_action_edit_alias_state'] = 'edit alias active'; # XXX $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'change password'; # XXX $PALANG['pViewlog_button'] = 'Ves'; $PALANG['pViewlog_result_error'] = 'Imposible trobar els logs!'; $PALANG['pSendmail_welcome'] = 'Enviar un e-mail.'; $PALANG['pSendmail_admin'] = 'De'; $PALANG['pSendmail_to'] = 'Destí'; $PALANG['pSendmail_to_text_error'] = 'La direcció de destí està buida o és una direcció invàlida!'; $PALANG['pSendmail_subject'] = 'Assumpte'; $PALANG['pSendmail_subject_text'] = 'Benvingut'; $PALANG['pSendmail_body'] = 'Cos'; $PALANG['pSendmail_button'] = 'Enviar missatge'; $PALANG['pSendmail_result_error'] = 'Imposible crear la bústia!'; # XXX text change - new: Unable to send email! $PALANG['pSendmail_result_success'] = 'La bústia ha estat creada!'; # XXX text change - new: Email sent! $PALANG['pAdminMenu_list_admin'] = 'Llistat d\'administradors'; $PALANG['pAdminMenu_list_domain'] = 'Llistat de dominis'; $PALANG['pAdminMenu_list_virtual'] = 'Llista de direccions virtuals'; $PALANG['pAdminMenu_viewlog'] = 'Veure Logs'; $PALANG['pAdminMenu_backup'] = 'Backup'; $PALANG['pAdminMenu_create_domain_admins'] = 'Administradors de domini'; $PALANG['pAdminMenu_create_admin'] = 'Nou administrador'; $PALANG['pAdminMenu_create_domain'] = 'Nou dominio'; $PALANG['pAdminMenu_create_alias'] = 'Afegir àlies'; $PALANG['pAdminMenu_create_mailbox'] = 'Afegir bústia'; $PALANG['pAdminList_admin_domain'] = 'Domini'; $PALANG['pAdminList_admin_username'] = 'Administrador'; $PALANG['pAdminList_admin_count'] = 'Dominis'; $PALANG['pAdminList_admin_modified'] = 'Última Modificació'; $PALANG['pAdminList_admin_active'] = 'Actiu'; $PALANG['pAdminList_domain_domain'] = 'Domini'; $PALANG['pAdminList_domain_description'] = 'Descripció'; $PALANG['pAdminList_domain_aliases'] = 'Àlies'; $PALANG['pAdminList_domain_mailboxes'] = 'Bústies'; $PALANG['pAdminList_domain_maxquota'] = 'Quota (MB)'; # XXX $PALANG['pAdminList_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; # XXX $PALANG['pAdminList_domain_modified'] = 'Última Modificació'; $PALANG['pAdminList_domain_active'] = 'Actiu'; $PALANG['pAdminList_virtual_button'] = 'Ves'; $PALANG['pAdminList_virtual_welcome'] = 'Resum de '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Àlies'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Bústies'; $PALANG['pAdminList_virtual_alias_address'] = 'De'; $PALANG['pAdminList_virtual_alias_goto'] = 'Destí'; $PALANG['pAdminList_virtual_alias_modified'] = 'Última Modificació'; $PALANG['pAdminList_virtual_mailbox_username'] = 'E-mail'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Nom'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Quota (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Última Modificació'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Actiu'; $PALANG['pAdminCreate_domain_welcome'] = 'Afegir nou domini'; $PALANG['pAdminCreate_domain_domain'] = 'Domini'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'El domini ja existeix!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'The domain is invalid!'; # XXX $PALANG['pAdminCreate_domain_description'] = 'Descripció'; $PALANG['pAdminCreate_domain_aliases'] = 'Àlies'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = ilimitat | 0 = deshabilitar'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Bústies'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = ilimitat | 0 = deshabilitar'; $PALANG['pAdminCreate_domain_maxquota'] = 'Quota màxima'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = ilimitat | 0 = deshabilitar'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Define transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Afegir àlies per defecte'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; # XXX $PALANG['pAdminCreate_domain_backupmx'] = 'Mail server is backup MX'; $PALANG['pAdminCreate_domain_button'] = 'Afegir domini'; $PALANG['pAdminCreate_domain_result_error'] = 'Imposible afegir el domini!'; $PALANG['pAdminCreate_domain_result_success'] = 'El domini ha estat afegit!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Unable to remove domain!'; # XXX $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = 'Editar un domini'; $PALANG['pAdminEdit_domain_domain'] = 'Domini'; $PALANG['pAdminEdit_domain_description'] = 'Descripció'; $PALANG['pAdminEdit_domain_aliases'] = 'Àlies'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = ilimitat | 0 = deshabilitar'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Bústies'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = ilimitat | 0 = deshabilitar'; $PALANG['pAdminEdit_domain_maxquota'] = 'Quota màxima'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = ilimitat | 0 = deshabilitar'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminEdit_domain_transport_text'] = 'Define transport'; # XXX $PALANG['pAdminEdit_domain_backupmx'] = 'Mail server is backup MX'; # XXX $PALANG['pAdminEdit_domain_active'] = 'Actiu'; $PALANG['pAdminEdit_domain_button'] = 'Editar domini'; $PALANG['pAdminEdit_domain_result_error'] = 'Imposible modificar el domini!'; $PALANG['pAdminCreate_admin_welcome'] = 'Afegir un nou administrador de domini'; $PALANG['pAdminCreate_admin_username'] = 'Administrador'; $PALANG['pAdminCreate_admin_username_text'] = 'E-mail'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'E-mail
Administrador no es un e-mail vàlid!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'E-mail
L\'administrador ja existeix o no es vàlid!'; $PALANG['pAdminCreate_admin_password'] = 'Contrasenya'; $PALANG['pAdminCreate_admin_password2'] = 'Contrasenya (repetiu)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Les contrasenyes introduides no coincideixen
o estan en blanc!
'; $PALANG['pAdminCreate_admin_button'] = 'Afegir administrador'; $PALANG['pAdminCreate_admin_result_error'] = 'Imposible afegir l\'administrador!'; $PALANG['pAdminCreate_admin_result_success'] = 'L\'administrador ha estat afegit!'; $PALANG['pAdminCreate_admin_address'] = 'Domini'; $PALANG['pAdminEdit_admin_welcome'] = 'Editar un administrador de domini'; $PALANG['pAdminEdit_admin_username'] = 'Administrador'; $PALANG['pAdminEdit_admin_password'] = 'Contrasenya'; $PALANG['pAdminEdit_admin_password2'] = 'Contrasenya (repetiu)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Les contrasenyes introduides no coincideixen
o estan en blanc!
'; $PALANG['pAdminEdit_admin_active'] = 'Actiu'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super admin'; # XXX $PALANG['pAdminEdit_admin_button'] = 'Editar administrador'; $PALANG['pAdminEdit_admin_result_error'] = 'Imposible modificar l\'administrador!'; $PALANG['pAdminEdit_admin_result_success'] = 'L\'administrador ha estat modificat!'; $PALANG['pUsersLogin_welcome'] = 'Login d\'usuaris per canviar la contrasenya i els àlies.'; $PALANG['pUsersLogin_username'] = 'Login (e-mail)'; $PALANG['pUsersLogin_password'] = 'Contrasenya'; $PALANG['pUsersLogin_button'] = 'Login'; $PALANG['pUsersLogin_username_incorrect'] = 'El seu login no és correcte. Asseguri\'s d\'haver introduït la seva adreça d\'e-mail com a login!'; $PALANG['pUsersLogin_password_incorrect'] = 'La seva contrasenya no és correcta!'; $PALANG['pUsersMenu_vacation'] = 'Resposta automàtica'; $PALANG['pUsersMenu_edit_alias'] = 'Canviar la redirecció'; $PALANG['pUsersMenu_password'] = 'Canviar la contrasenya'; $PALANG['pUsersMain_vacation'] = 'Configuri un missatge de "Fora de la feina" o una resposta automàtica pel seu correu.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' is ON, click \'' . $PALANG['pUsersMenu_vacation'] . '\' to ' . $PALANG['edit'] . '/remove'; # XXX $PALANG['pUsersMain_edit_alias'] = 'Canvïi la seva redirecció de correu.'; $PALANG['pUsersMain_password'] = 'Canvïi la seva contrasenya.'; $PALANG['pUsersVacation_welcome'] = 'Resposta automàtica.'; $PALANG['pUsersVacation_welcome_text'] = 'Ja disposa d\'una resposta automàtica configurada!'; $PALANG['pUsersVacation_subject'] = 'Assumpte'; $PALANG['pUsersVacation_subject_text'] = 'Fora de la feina'; $PALANG['pUsersVacation_body'] = 'Cos'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << fins al . Per assumptes urgents pot contactar amb mi a . EOM; $PALANG['pUsersVacation_button_away'] = 'Absent'; $PALANG['pUsersVacation_button_back'] = 'De tornada'; $PALANG['pUsersVacation_result_error'] = 'Imposible actualitzar la configuració de la seva resposta automàtica!'; $PALANG['pUsersVacation_result_success'] = 'La seva resposta automàtica ha estat esborrada!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'create mailbox'; # XXX $PALANG['pCreate_dbLog_createalias'] = 'create alias'; # XXX $PALANG['pDelete_dbLog_deletealias'] = 'delete alias'; # XXX $PALANG['pDelete_dbLog_deletemailbox'] = 'delete mailbox'; # XXX $PALANG['pEdit_dbLog_editactive'] = 'change active state'; # XXX $PALANG['pEdit_dbLog_editalias'] = 'edit alias'; # XXX $PALANG['pEdit_dbLog_editmailbox'] = 'edit mailbox'; # XXX $PALANG['pSearch'] = 'search'; # XXX $PALANG['pSearch_welcome'] = 'Searching for: '; # XXX $PALANG['pReturn_to'] = 'Return to'; # XXX $PALANG['pBroadcast_title'] = 'Send broadcast message'; # XXX $PALANG['pBroadcast_from'] = 'From'; # XXX $PALANG['pBroadcast_name'] = 'Your name'; # XXX $PALANG['pBroadcast_subject'] = 'Subject'; # XXX $PALANG['pBroadcast_message'] = 'Message'; # XXX $PALANG['pBroadcast_send'] = 'Send message'; # XXX $PALANG['pBroadcast_success'] = 'Your broadcast message was sent.'; # XXX $PALANG['pAdminMenu_broadcast_message'] = 'Broadcast message'; # XXX $PALANG['pBroadcast_error_empty'] = 'The fields Name, Subject and Message should\'t be empty !'; # XXX $PALANG['pStatus_undeliverable'] = 'maybe UNDELIVERABLE '; # XXX $PALANG['pStatus_custom'] = 'Delivers to '; # XXX $PALANG['pStatus_popimap'] = 'POP/IMAP '; # XXX $PALANG['pPasswordTooShort'] = "Password is too short - requires %s characters"; # XXX $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Fetch mail for:'; # XXX $PALANG['pFetchmail_new_entry'] = 'New entry'; # XXX $PALANG['pFetchmail_database_save_error'] = 'Could not save this entry in the database!'; # XXX $PALANG['pFetchmail_database_save_success'] = 'Entry saved in database.'; # XXX $PALANG['pFetchmail_error_invalid_id'] = 'No entry with ID %s found!'; # XXX $PALANG['pFetchmail_invalid_mailbox'] = 'Invalid mailbox!'; # XXX $PALANG['pFetchmail_server_missing'] = 'Please enter the remote server name!'; # XXX $PALANG['pFetchmail_user_missing'] = 'Please enter the remote username!'; # XXX $PALANG['pFetchmail_password_missing'] = 'Please enter the remote password!'; # XXX $PALANG['pFetchmail_field_id'] = 'ID'; # XXX $PALANG['pFetchmail_field_mailbox'] = 'Mailbox'; # XXX $PALANG['pFetchmail_field_src_server'] = 'Server'; # XXX $PALANG['pFetchmail_field_src_auth'] = 'Auth Type'; # XXX $PALANG['pFetchmail_field_src_user'] = 'User'; # XXX $PALANG['pFetchmail_field_src_password'] = 'Password'; # XXX $PALANG['pFetchmail_field_src_folder'] = 'Folder'; # XXX $PALANG['pFetchmail_field_poll_time'] = 'Poll'; # XXX $PALANG['pFetchmail_field_fetchall'] = 'Fetch All'; # XXX $PALANG['pFetchmail_field_keep'] = 'Keep'; # XXX $PALANG['pFetchmail_field_protocol'] = 'Protocol'; # XXX $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra Options'; # XXX $PALANG['pFetchmail_field_mda'] = 'MDA'; # XXX $PALANG['pFetchmail_field_date'] = 'Date'; # XXX $PALANG['pFetchmail_field_returned_text'] = 'Returned Text'; # XXX $PALANG['pFetchmail_desc_id'] = 'Record ID'; # XXX $PALANG['pFetchmail_desc_mailbox'] = 'Local mailbox'; # XXX $PALANG['pFetchmail_desc_src_server'] = 'Remote Server'; # XXX $PALANG['pFetchmail_desc_src_auth'] = 'Mostly \'password\''; # Translators: Please do NOT translate 'password' here # XXX $PALANG['pFetchmail_desc_src_user'] = 'Remote User'; # XXX $PALANG['pFetchmail_desc_src_password'] = 'Remote Password'; # XXX $PALANG['pFetchmail_desc_src_folder'] = 'Remote Folder'; # XXX $PALANG['pFetchmail_desc_poll_time'] = 'Poll every ... minutes'; # XXX $PALANG['pFetchmail_desc_fetchall'] = 'Retrieve both old (seen) and new messages'; # XXX $PALANG['pFetchmail_desc_keep'] = 'Keep retrieved messages on the remote mailserver'; # XXX $PALANG['pFetchmail_desc_protocol'] = 'Protocol to use'; # XXX $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Extra fetchmail Options'; # XXX $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; # XXX $PALANG['pFetchmail_desc_date'] = 'Date of last polling/configuration change'; # XXX $PALANG['pFetchmail_desc_returned_text'] = 'Text message from last polling'; # XXX $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/fi.lang0000664000175000017620000006466111636730120017502 0ustar davidpalepurple // $PALANG['YES'] = 'Kyllä'; $PALANG['NO'] = 'Ei'; $PALANG['edit'] = 'muokkaa'; $PALANG['del'] = 'poista'; $PALANG['exit'] = 'Poistu'; $PALANG['cancel'] = 'Peruuta'; $PALANG['save'] = 'Tallenna'; $PALANG['confirm'] = 'Oletko varma että haluat poistaa tämän?\n'; $PALANG['confirm_domain'] = 'Oletko varma että haluat poistaa kaikki tietueet tästä domainista? Tätä komentoa ei voi perua!\n'; $PALANG['check_update'] = 'Tarkista päivitykset'; $PALANG['invalid_parameter'] = 'Viallinen parametri!'; $PALANG['pFooter_logged_as'] = 'Kirjautunut sisään tunnuksella %s'; $PALANG['pLogin_welcome'] = 'Kirjautuminen'; $PALANG['pLogin_username'] = 'Tunnus'; $PALANG['pLogin_password'] = 'Salasana'; $PALANG['pLogin_button'] = 'Kirjaudu'; $PALANG['pLogin_failed'] = 'Sähköpostiosoite tai salasana väärin!'; $PALANG['pLogin_login_users'] = 'Käyttäjien kirjautuminen.'; $PALANG['pMenu_main'] = 'Etusivu'; $PALANG['pMenu_overview'] = 'Yleisnäkymä'; $PALANG['pMenu_create_alias'] = 'Lisää alias'; $PALANG['pMenu_create_alias_domain'] = 'Lisää alias domain'; $PALANG['pMenu_create_mailbox'] = 'Lisää postilaatikko'; $PALANG['pMenu_fetchmail'] = 'Hae sähköpostit'; $PALANG['pMenu_sendmail'] = 'Lähetä postia'; $PALANG['pMenu_password'] = 'Salasana'; $PALANG['pMenu_viewlog'] = 'Näytä loki'; $PALANG['pMenu_logout'] = 'Kirjaudu ulos'; $PALANG['pMain_welcome'] = 'Tervetuloa sähköpostin hallintaan.'; $PALANG['pMain_overview'] = 'Listaa aliakset ja postilaatikot. Voit muokata ja poistaa niitä tästä.'; $PALANG['pMain_create_alias'] = 'Luo uusi alias domainiin.'; $PALANG['pMain_create_mailbox'] = 'Luo uusi postilaatikko domainiin.'; $PALANG['pMain_sendmail'] = 'Lähetä sähköpostia juuri luotuun postilaatikkoon.'; $PALANG['pMain_password'] = 'Vaihda hallintatunnuksen salasanaa.'; $PALANG['pMain_viewlog'] = 'Näytä lokitiedostot.'; $PALANG['pMain_logout'] = 'Kirjaudu ulos järjestelmästä'; $PALANG['pOverview_disabled'] = 'Poissa käytöstä'; $PALANG['pOverview_unlimited'] = 'Rajoittamaton'; $PALANG['pOverview_title'] = ':: Määritellyt Domainit'; $PALANG['pOverview_up_arrow'] = 'Mene ylös'; $PALANG['pOverview_right_arrow'] = 'Seuraava sivu'; $PALANG['pOverview_left_arrow'] = 'Edellinen sivu'; $PALANG['pOverview_alias_domain_title'] = ':: Domain Aliakset'; $PALANG['pOverview_alias_title'] = ':: Alias'; $PALANG['pOverview_mailbox_title'] = ':: Sähköpostilaatikot'; $PALANG['pOverview_button'] = 'Siirry'; $PALANG['pOverview_welcome'] = 'Yleisnäkymä '; $PALANG['pOverview_alias_domain_aliases'] = 'Alias Domainit'; $PALANG['pOverview_alias_domain_target'] = '%s on Alias Domaini domainille:'; $PALANG['pOverview_alias_alias_count'] = 'Aliakset'; $PALANG['pOverview_alias_mailbox_count'] = 'Postilaatikot'; $PALANG['pOverview_alias_address'] = 'Keneltä'; $PALANG['pOverview_alias_goto'] = 'Kenelle'; $PALANG['pOverview_alias_modified'] = 'Viimeksi muokattu'; $PALANG['pOverview_alias_domain_modified'] = 'Viimeksi muokattu'; $PALANG['pOverview_alias_active'] = 'Aktiivinen'; $PALANG['pOverview_alias_domain_active'] = 'Aktiivinen'; $PALANG['pOverview_alias_edit'] = 'Alias'; $PALANG['and_x_more'] = '[ja %s lisää...]'; $PALANG['pOverview_mailbox_username'] = 'Sähköposti'; $PALANG['pOverview_mailbox_name'] = 'Nimi'; $PALANG['pOverview_mailbox_quota'] = 'Kiintiö (MB)'; $PALANG['pOverview_mailbox_modified'] = 'Viimeksi muokattu'; $PALANG['pOverview_mailbox_active'] = 'Aktiivinen'; $PALANG['pOverview_vacation_edit'] = 'Lomavastaaja on päällä'; $PALANG['pOverview_vacation_option'] = 'Aseta lomavastaaja'; $PALANG['pOverview_get_domain'] = 'Domain'; $PALANG['pOverview_get_aliases'] = 'Aliakset'; $PALANG['pOverview_get_alias_domains'] = 'Domain Aliakset'; $PALANG['pOverview_get_mailboxes'] = 'Postilaatikot'; $PALANG['pOverview_get_quota'] = 'Postilaatikon kiintiö (MB)'; $PALANG['pOverview_get_modified'] = 'Viimeksi muokattu'; $PALANG['pDelete_delete_error'] = 'Tietueen poisto ei onnistu '; $PALANG['pDelete_delete_success'] = '%s poistettu.'; $PALANG['pDelete_postdelete_error'] = 'Sähköpostilaatikkoa ei voitu poistaa '; $PALANG['pDelete_domain_error'] = 'Tämä ei ole sinun domainisi '; $PALANG['pDelete_domain_alias_error'] = 'Tämä ei ole sinun domainisi '; $PALANG['pDelete_alias_error'] = 'Aliasta ei voitu poistaa '; $PALANG['pCreate_alias_domain_welcome'] = 'Peiliosoitteet domainistasi toiseen.'; $PALANG['pCreate_alias_domain_alias'] = 'Alias Domaini'; $PALANG['pCreate_alias_domain_alias_text'] = 'Domaini johon sähköpostit tulevat.'; $PALANG['pCreate_alias_domain_target'] = 'Kohde Domaini'; $PALANG['pCreate_alias_domain_target_text'] = 'Domaini johon mailien pitäisi mennä.'; $PALANG['pCreate_alias_domain_active'] = 'Aktiivinen'; $PALANG['pCreate_alias_domain_button'] = 'Lisää Alias Domaini'; $PALANG['pCreate_alias_domain_error1'] = 'Sinulla ei ole oikeutta luoda valittua konfiguraatiota.'; $PALANG['pCreate_alias_domain_error2'] = 'Valittu konfiguraatio on viallinen, ole hyvä ja valitse toinen!'; $PALANG['pCreate_alias_domain_error3'] = 'Syöttö tietokantaan epäonnistui.'; $PALANG['pCreate_alias_domain_error4'] = 'Kaikilla domaineilla on jo alias.'; $PALANG['pCreate_alias_domain_success'] = 'Domainin alias on lisätty domain alias tauluun!'; $PALANG['pCreate_alias_welcome'] = 'Luo uusi alias.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
Alias ei ole oikean muotoinen!'; $PALANG['pCreate_alias_address_text_error2'] = '
Tämä sähköpostiosoite on jo käytössä, ole hyvä ja valitse jokin toinen!'; $PALANG['pCreate_alias_address_text_error3'] = '
Aliasten maksimimäärä saavutettu. Et voi lisätä aliaksia enää!'; $PALANG['pCreate_alias_goto'] = 'Kenelle'; $PALANG['pCreate_alias_active'] = 'Aktiivinen'; $PALANG['pCreate_alias_button'] = 'Lisää alias'; $PALANG['pCreate_alias_goto_text'] = 'Minne posti lähetetään.'; $PALANG['pCreate_alias_goto_text_error'] = 'Minne sähköposti lähetetään.
"Kenelle" osoite ei ole oikean muotoinen!'; $PALANG['pCreate_alias_result_error'] = 'Aliaksen lisäys alias tauluun epäonnistui!'; $PALANG['pCreate_alias_result_success'] = 'Alias on lisätty!'; $PALANG['pCreate_alias_catchall_text'] = 'Jos haluat luoda catch-all osoitteen käytä "*" merkkiä aliaksena.
Ohjaus domainista domainiin tapahtuu käyttämällä "*@domain.tld" Kenelle: -osoitteena.'; $PALANG['pEdit_alias_welcome'] = 'Muokkaa aliasta.
Yksi kohta per rivi.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Aliasta ei löydy!'; $PALANG['pEdit_alias_goto'] = 'Kenelle'; $PALANG['pEdit_alias_active'] = 'Aktiivinen'; $PALANG['pEdit_alias_goto_text_error1'] = 'Et kirjoitanut mitään Kenelle: -riville'; $PALANG['pEdit_alias_goto_text_error2'] = 'Antamasi sähköpostiosoite ei ole oikean muotoinen: '; $PALANG['pEdit_alias_domain_error'] = 'Tämä ei ole sinun domainisi: '; $PALANG['pEdit_alias_domain_result_error'] = 'Alias domainia ei voitu muokata!'; $PALANG['pEdit_alias_forward_and_store'] = 'Toimita paikalliseen laatikkoon.'; $PALANG['pEdit_alias_forward_only'] = 'Edelleenlähetä ainoastaan annettuun sähköpostiosoitteeseen.'; $PALANG['pEdit_alias_button'] = 'Muokkaa aliasta'; $PALANG['pEdit_alias_result_error'] = 'Aliasta ei voi muokata!'; $PALANG['pCreate_mailbox_welcome'] = 'Luo uusi paikallinen postilaatikko.'; $PALANG['pCreate_mailbox_username'] = 'Käyttäjätunnus'; $PALANG['pCreate_mailbox_username_text_error1'] = '
Sähköpostiosoite ei ole oikean muotoinen!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Sähköpostiosoite on jo käytössä, ole hyvä ja valitse jokin toinen!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Postilaatikoiden maksimimäärä saavutettu!'; $PALANG['pCreate_mailbox_password'] = 'Salasana'; $PALANG['pCreate_mailbox_password2'] = 'Salasana (toistamiseen)'; $PALANG['pCreate_mailbox_password_text'] = 'POP3/IMAP salasana'; $PALANG['pCreate_mailbox_password_text_error'] = 'POP3/IMAP salasana
Antamasi salasanat eivät täsmää!
tai ne ovat tyhjät!
'; $PALANG['pCreate_mailbox_name'] = 'Nimi'; $PALANG['pCreate_mailbox_name_text'] = 'Koko nimi'; $PALANG['pCreate_mailbox_quota'] = 'Kiintiö'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Antamasi kiintiö on liian korkea!'; $PALANG['pCreate_mailbox_active'] = 'Aktiivinen'; $PALANG['pCreate_mailbox_mail'] = 'Luo postilaatikko'; $PALANG['pCreate_mailbox_button'] = 'Lisää postilaatikko'; $PALANG['pCreate_mailbox_result_error'] = 'Postilaatikon lisääminen ei onnistu!'; $PALANG['pCreate_mailbox_result_success'] = 'Postilaatikko on lisätty!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'Sähköpostilaatikko on lisätty tauluun, mutta ennaltamääriteltyjen alikansioiden luonneista yksi tai useampi epäonnistui'; $PALANG['pEdit_mailbox_welcome'] = 'Muokkaa postilaatikkoa.'; $PALANG['pEdit_mailbox_username'] = 'Käyttäjätunnus'; $PALANG['pEdit_mailbox_username_error'] = 'Postilaatikkoa ei löydy!'; $PALANG['pEdit_mailbox_password'] = 'Uusi salasana'; $PALANG['pEdit_mailbox_password2'] = 'Uusi salasana (toistamiseen)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Antamasi salasanat eivät täsmää!'; $PALANG['pEdit_mailbox_name'] = 'Nimi'; $PALANG['pEdit_mailbox_name_text'] = 'Koko nimi'; $PALANG['pEdit_mailbox_quota'] = 'Kiintiö'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Antamasi kiintiö on liian korkea!'; $PALANG['pEdit_mailbox_domain_error'] = 'Tämä domaini ei ole sinun: '; $PALANG['pEdit_mailbox_button'] = 'Muokkaa postilaatikkoa'; $PALANG['pEdit_mailbox_result_error'] = 'Postilaatikon muokkaus ei onnistunut!'; $PALANG['pPassword_welcome'] = 'Vaihda tunnuksesi salasana.'; $PALANG['pPassword_admin'] = 'Tunnus'; $PALANG['pPassword_admin_text_error'] = 'Antamaasi tunnusta ei ole olemassa!'; $PALANG['pPassword_password_current'] = 'Nykyinen salasanasi'; $PALANG['pPassword_password_current_text_error'] = 'Et antanut nykyistä salasanaasi!'; $PALANG['pPassword_password'] = 'Uusi salasana'; $PALANG['pPassword_password2'] = 'Uusi salasana (toistamiseen)'; $PALANG['pPassword_password_text_error'] = 'Antamasi salasanat eivät täsmää!
Tai ovat tyhjiä!
'; $PALANG['pPassword_button'] = 'Vaihda salasana'; $PALANG['pPassword_result_error'] = 'Salasanan vaihto ei onnistunut!'; $PALANG['pPassword_result_success'] = 'Salasana vaihdettu!'; $PALANG['pEdit_vacation_set'] = 'Muuta / Aseta poissaoloviesti'; $PALANG['pEdit_vacation_remove'] = 'Poista poissaoloviesti'; $PALANG['pVacation_result_error'] = 'Automaattivastauksen asetuksia ei voitu päivittää!'; $PALANG['pVacation_result_removed'] = 'Automaattivastaus poistettu!'; $PALANG['pVacation_result_added'] = 'Automaattivastaus päällä!'; $PALANG['pViewlog_welcome'] = 'Näytä viimeiset kymmenen tapahtumaa domainille '; $PALANG['pViewlog_timestamp'] = 'Aikaleima'; $PALANG['pViewlog_username'] = 'Admin'; $PALANG['pViewlog_domain'] = 'Domain'; $PALANG['pViewlog_action'] = 'Tapahtuma'; $PALANG['pViewlog_data'] = 'Tiedot'; $PALANG['pViewlog_action_create_mailbox'] = 'luo sähköpostilaatikko'; $PALANG['pViewlog_action_delete_mailbox'] = 'poista sähköpostilaatikko'; $PALANG['pViewlog_action_edit_mailbox'] = 'muokkaa sähköpostilaatikkoa'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'muokkaa aktiivista sähköpostilaatikkoa'; $PALANG['pViewlog_action_create_alias'] = 'luo alias'; $PALANG['pViewlog_action_create_alias_domain'] = 'luo alias domaini'; $PALANG['pViewlog_action_delete_alias'] = 'poista alias'; $PALANG['pViewlog_action_delete_alias_domain'] = 'poista alias domaini'; $PALANG['pViewlog_action_edit_alias'] = 'muokkaa aliasta'; $PALANG['pViewlog_action_edit_alias_state'] = 'muokkaa aktiivista aliasta'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'muokkaa aktiivista alias domainia'; $PALANG['pViewlog_action_edit_password'] = 'vaihda salasana'; $PALANG['pViewlog_button'] = 'Siirry'; $PALANG['pViewlog_result_error'] = 'Lokeja ei löydy!'; $PALANG['pSendmail_welcome'] = 'Lähetä sähköpostia.'; $PALANG['pSendmail_admin'] = 'Keneltä'; $PALANG['pSendmail_to'] = 'Kenelle'; $PALANG['pSendmail_to_text_error'] = 'Kenelle on tyhjä tai osoite ei ole toimiva sähköpostiosoite!'; $PALANG['pSendmail_subject'] = 'Otsikko'; $PALANG['pSendmail_subject_text'] = 'Tervetuloa'; $PALANG['pSendmail_body'] = 'Viesti'; $PALANG['pSendmail_button'] = 'Lähetä viesti'; $PALANG['pSendmail_result_error'] = 'Sähköpostin lähetys ei onnistunut!'; $PALANG['pSendmail_result_success'] = 'Sähköposti lähetetty!'; $PALANG['pAdminMenu_list_admin'] = 'Ylläpitäjä Lista'; $PALANG['pAdminMenu_list_domain'] = 'Domain Lista'; $PALANG['pAdminMenu_list_virtual'] = 'Virtual Lista'; $PALANG['pAdminMenu_viewlog'] = 'Näytä loki'; $PALANG['pAdminMenu_backup'] = 'Varmistus'; $PALANG['pAdminMenu_create_domain_admins'] = 'Domainin ylläpitäjät'; $PALANG['pAdminMenu_create_admin'] = 'Uusi ylläpitäjä'; $PALANG['pAdminMenu_create_domain'] = 'Uusi domain'; $PALANG['pAdminMenu_create_alias'] = 'Lisää alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Lisää postilaatikko'; $PALANG['pAdminList_admin_domain'] = 'Domain'; $PALANG['pAdminList_admin_username'] = 'Ylläpitäjä'; $PALANG['pAdminList_admin_count'] = 'Domainit'; $PALANG['pAdminList_admin_modified'] = 'Viimeksi muokattu'; $PALANG['pAdminList_admin_active'] = 'Aktiivinen'; $PALANG['pAdminList_domain_domain'] = 'Domain'; $PALANG['pAdminList_domain_description'] = 'Kuvaus'; $PALANG['pAdminList_domain_aliases'] = 'Aliakset'; $PALANG['pAdminList_domain_mailboxes'] = 'Postilaatikot'; $PALANG['pAdminList_domain_maxquota'] = 'Suurin sallittu kiintiö (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; $PALANG['pAdminList_domain_backupmx'] = 'Vara MX'; $PALANG['pAdminList_domain_modified'] = 'Viimeksi muokattu'; $PALANG['pAdminList_domain_active'] = 'Atiivinen'; $PALANG['pAdminList_virtual_button'] = 'Siirry'; $PALANG['pAdminList_virtual_welcome'] = 'Yleisnäkymä '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Aliakset'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Postilaatikot'; $PALANG['pAdminList_virtual_alias_address'] = 'Keneltä'; $PALANG['pAdminList_virtual_alias_goto'] = 'Kenelle'; $PALANG['pAdminList_virtual_alias_modified'] = 'Viimeksi muokattu'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Sähköposti'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Nimi'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Kiintiö (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Viimeksi muokattu'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Aktiivinen'; $PALANG['pAdminCreate_domain_welcome'] = 'Lisää uusi domain'; $PALANG['pAdminCreate_domain_domain'] = 'Domain'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Domain on jo järjestelmässä!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'Domain on virheellinen!'; $PALANG['pAdminCreate_domain_description'] = 'Kuvaus'; $PALANG['pAdminCreate_domain_aliases'] = 'Aliakset'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = ei käytössä | 0 = rajoittamaton'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Postilaatikot'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = ei käytössä | 0 = rajoittamaton'; $PALANG['pAdminCreate_domain_maxquota'] = 'Max kiintiö'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = ei käytössä | 0 = rajoittamaton'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Määritä transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Lisää oletus aliakset'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'Sähköpostipalvelin on vara MX'; $PALANG['pAdminCreate_domain_button'] = 'Lisää domain'; $PALANG['pAdminCreate_domain_result_error'] = 'Domainin lisäys ei onnistunut!'; $PALANG['pAdminCreate_domain_result_success'] = 'Domain on lisätty!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Domainin voitu poistaa!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Domainin aliasta ei voitu poistaa!'; $PALANG['pAdminEdit_domain_welcome'] = 'Muokkaa domainia'; $PALANG['pAdminEdit_domain_domain'] = 'Domain'; $PALANG['pAdminEdit_domain_description'] = 'Kuvaus'; $PALANG['pAdminEdit_domain_aliases'] = 'Aliakset'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = ei käytössä | 0 = rajoittamaton'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Postilaatikot'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = ei käytössä | 0 = rajoittamaton'; $PALANG['pAdminEdit_domain_maxquota'] = 'Max kiintiö'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = ei käytössä | 0 = rajoittamaton'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Määritä transport'; $PALANG['pAdminEdit_domain_backupmx'] = 'Sähköpostipalvelin on vara MX'; $PALANG['pAdminEdit_domain_active'] = 'Aktiivinen'; $PALANG['pAdminEdit_domain_button'] = 'Muokkaa domainia'; $PALANG['pAdminEdit_domain_result_error'] = 'Domainin muokkaus ei onnistu!'; $PALANG['pAdminCreate_admin_welcome'] = 'Lisää uusi domainin ylläpitäjä'; $PALANG['pAdminCreate_admin_username'] = 'Ylläpitäjä'; $PALANG['pAdminCreate_admin_username_text'] = 'Sähköpostiosoite'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Sähköpostiosoite
Ylläpitäjän sähköpostiosoite ei ole oikeanmuotoinen!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Sähköpostiosoite
Ylläpitäjän sähköpostiosoite on jo olemassa tai se ei ole oikean muotoinen'; $PALANG['pAdminCreate_admin_password'] = 'Salasana'; $PALANG['pAdminCreate_admin_password2'] = 'Salasana (toistamiseen)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Antamasi salasanat eivät täsmää
Tai ne ovat tyhjiä!
'; $PALANG['pAdminCreate_admin_button'] = 'Lisää ylläpitäjä'; $PALANG['pAdminCreate_admin_result_error'] = 'Ylläpitäjän lisäys ei onnistu!'; $PALANG['pAdminCreate_admin_result_success'] = 'Ylläpitäjä on lisätty!'; $PALANG['pAdminCreate_admin_address'] = 'Domain'; $PALANG['pAdminEdit_admin_welcome'] = 'Muokkaa domainin ylläpitäjää'; $PALANG['pAdminEdit_admin_username'] = 'Ylläpitäjä'; $PALANG['pAdminEdit_admin_password'] = 'Salasana'; $PALANG['pAdminEdit_admin_password2'] = 'Salasana (toistamiseen)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Antamasi salasanat eivät täsmää!
Tai ne ovat tyhjiä!
'; $PALANG['pAdminEdit_admin_active'] = 'Aktiivinen'; $PALANG['pAdminEdit_admin_super_admin'] = 'Pääylläpitäjä'; $PALANG['pAdminEdit_admin_button'] = 'Muokkaa ylläpitäjää'; $PALANG['pAdminEdit_admin_result_error'] = 'Ylläpitäjän muokkaaminen ei onnistu!'; $PALANG['pAdminEdit_admin_result_success'] = 'Ylläpitäjän muokkaus onnistui!'; $PALANG['pUsersLogin_welcome'] = 'Salasanan vaihto.'; $PALANG['pUsersLogin_username'] = 'Tunnus'; $PALANG['pUsersLogin_password'] = 'Salasana'; $PALANG['pUsersLogin_button'] = 'Kirjaudu'; $PALANG['pUsersLogin_username_incorrect'] = 'Käyttäjätunnus tai salasana väärin!'; $PALANG['pUsersLogin_password_incorrect'] = 'Käyttäjätunnus tai salasana väärin!'; $PALANG['pUsersMenu_vacation'] = 'Automaattivastaus'; $PALANG['pUsersMenu_edit_alias'] = 'Muokkaa uudelleenohjausta'; $PALANG['pUsersMenu_password'] = 'Vaihda salasana'; $PALANG['pUsersMain_vacation'] = 'Aseta lomavastaaja tai automaattivastaus sähköpostiisi.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' on päällä, paina \'' . $PALANG['pUsersMenu_vacation'] . '\' muokataksesi tai poistaaksesi'; $PALANG['pUsersMain_edit_alias'] = 'Muuta uudelleenohjauksen osoitetta.'; $PALANG['pUsersMain_password'] = 'Vaihda nykyinen salasanasi.'; $PALANG['pUsersVacation_welcome'] = 'Automaattivastaus.'; $PALANG['pUsersVacation_welcome_text'] = 'Sinulla on jo automaattivastaus päällä!'; $PALANG['pUsersVacation_subject'] = 'Otsikko'; $PALANG['pUsersVacation_subject_text'] = 'Lomalla'; $PALANG['pUsersVacation_body'] = 'Viesti'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << välisen ajan. Kiireellisissä asioissa voitte ottaa yhteyttä . EOM; $PALANG['pUsersVacation_button_away'] = 'Lomalle'; $PALANG['pUsersVacation_button_back'] = 'Takaisin lomalta'; $PALANG['pUsersVacation_result_error'] = 'Automaattivastauksen asettaminen epäonnistui!'; $PALANG['pUsersVacation_result_success'] = 'Automaattivastaus on poistettu käytöstä!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'luo sähköpostilaatikko'; $PALANG['pCreate_dbLog_createalias'] = 'luo alias'; $PALANG['pDelete_dbLog_deletealias'] = 'poista alias'; $PALANG['pDelete_dbLog_deletemailbox'] = 'poista sähköpostilaatikko'; $PALANG['pEdit_dbLog_editactive'] = 'vaihda aktiivisuus tilaa'; $PALANG['pEdit_dbLog_editalias'] = 'muokkaa aliasta'; $PALANG['pEdit_dbLog_editmailbox'] = 'muokkaa sähköpostilaatikkoa'; $PALANG['pSearch'] = 'hae'; $PALANG['pSearch_welcome'] = 'Haetaan: '; $PALANG['pReturn_to'] = 'Palaa osoitteeseen'; $PALANG['pBroadcast_title'] = 'Lähetä tiedotusviesti'; $PALANG['pBroadcast_from'] = 'Lähettäjä'; $PALANG['pBroadcast_name'] = 'Nimesi'; $PALANG['pBroadcast_subject'] = 'Aihe'; $PALANG['pBroadcast_message'] = 'Viesti'; $PALANG['pBroadcast_send'] = 'Lähetä viesti'; $PALANG['pBroadcast_success'] = 'Tiedostusviestisi on lähetetty.'; $PALANG['pAdminMenu_broadcast_message'] = 'Tiedotusviesti'; $PALANG['pBroadcast_error_empty'] = 'Nimi, Aihe tai Viesti kenttien ei pidä olla tyhjiä!'; $PALANG['pStatus_undeliverable'] = 'ehkä ei voida toimittaa '; $PALANG['pStatus_custom'] = 'Toimittaa osoiteeseen '; $PALANG['pStatus_popimap'] = 'POP/IMAP '; $PALANG['pPasswordTooShort'] = "Salasana on liian lyhyt, vaaditaan %s merkkiä"; $PALANG['pInvalidDomainRegex'] = "Virheellinen domain nimi %s, ei läpäise regexp testiä"; $PALANG['pInvalidDomainDNS'] = "Virheellinen domain %s ja/tai ei löydy nimipalvelimista"; $PALANG['pInvalidMailRegex'] = "Virheellinen sähköpostiosoite, ei läpäise regexp testiä"; $PALANG['pFetchmail_welcome'] = 'Hae postit:'; $PALANG['pFetchmail_new_entry'] = 'Uusi tietue'; $PALANG['pFetchmail_database_save_error'] = 'Tätä tietuetta ei voitu tallentaa tietokantaan!'; $PALANG['pFetchmail_database_save_success'] = 'Tietue tallennettu tietokantaan.'; $PALANG['pFetchmail_error_invalid_id'] = 'Tietuetta ID:llä %s ei löytynyt!'; $PALANG['pFetchmail_invalid_mailbox'] = 'Viallinen sähköpostilaatikko!'; $PALANG['pFetchmail_server_missing'] = 'Ole hyvä ja syötä etäpalvelimen nimi!'; $PALANG['pFetchmail_user_missing'] = 'Ole hyvä ja syötä etäkäyttäjän tunnus!'; $PALANG['pFetchmail_password_missing'] = 'Ole hyvä ja syötä etäkäyttäjän salasana!'; $PALANG['pFetchmail_field_id'] = 'ID'; $PALANG['pFetchmail_field_mailbox'] = 'Sähköpostilaatikko'; $PALANG['pFetchmail_field_src_server'] = 'Palvelin'; $PALANG['pFetchmail_field_src_auth'] = 'Tunnistautumisen tyyppi'; $PALANG['pFetchmail_field_src_user'] = 'Käyttäjä'; $PALANG['pFetchmail_field_src_password'] = 'Salasana'; $PALANG['pFetchmail_field_src_folder'] = 'Kansio'; $PALANG['pFetchmail_field_poll_time'] = 'Tarkista'; $PALANG['pFetchmail_field_fetchall'] = 'Hae kaikki'; $PALANG['pFetchmail_field_keep'] = 'Pidä'; $PALANG['pFetchmail_field_protocol'] = 'Protokolla'; $PALANG['pFetchmail_field_usessl'] = 'SSL aktiivinen'; $PALANG['pFetchmail_field_extra_options'] = 'Lisämääritteet'; $PALANG['pFetchmail_field_mda'] = 'MDA'; $PALANG['pFetchmail_field_date'] = 'Päivämäärä'; $PALANG['pFetchmail_field_returned_text'] = 'Palautettu teksti'; $PALANG['pFetchmail_desc_id'] = 'Tietue ID'; $PALANG['pFetchmail_desc_mailbox'] = 'Paikallinen sähköpostilaatikko'; $PALANG['pFetchmail_desc_src_server'] = 'Etäpalvelin'; $PALANG['pFetchmail_desc_src_auth'] = 'Useimmiten \'password\''; $PALANG['pFetchmail_desc_src_user'] = 'Etäkäyttäjä'; $PALANG['pFetchmail_desc_src_password'] = 'Etäkäyttäjän salasana'; $PALANG['pFetchmail_desc_src_folder'] = 'Etäpalvelimen kansio'; $PALANG['pFetchmail_desc_poll_time'] = 'Tarkista joka ... minuutti'; $PALANG['pFetchmail_desc_fetchall'] = 'Hae sekä vanhat(luetut) että uudet viestit'; $PALANG['pFetchmail_desc_keep'] = 'Jätä kopio haetuista viesteistä etäpalvelimelle'; $PALANG['pFetchmail_desc_protocol'] = 'Käytettävä protokolla'; $PALANG['pFetchmail_desc_usessl'] = 'SSL salaus'; $PALANG['pFetchmail_desc_extra_options'] = 'Lisämääritteet fetchmailílle'; $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; $PALANG['pFetchmail_desc_date'] = 'Viimeisen tarkistuksen/konfiguraatio muutoksen päivämäärä'; $PALANG['pFetchmail_desc_returned_text'] = 'Viesti edellisestä tarkistuksesta'; $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/nn.lang0000664000175000017620000006374011636730120017514 0ustar davidpalepurpleKan ikke slette'; $PALANG['pDelete_delete_success'] = '%s deleted.'; # XXX $PALANG['pDelete_postdelete_error'] = 'Unable to remove mailbox '; # XXX $PALANG['pDelete_domain_error'] = 'Dette domenet er ikke ditt'; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = 'Unable to delete alias '; # XXX $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = 'Opprett et nytt alias.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
Aliaset er ikke gyldig!'; $PALANG['pCreate_alias_address_text_error2'] = '
Denne epostadressen eksisterer allerede, velg en annen!'; $PALANG['pCreate_alias_address_text_error3'] = '
Du er over grensen for antall aliaser i ditt domene!'; $PALANG['pCreate_alias_goto'] = 'Mottaker'; $PALANG['pCreate_alias_active'] = 'Active'; # XXX $PALANG['pCreate_alias_button'] = 'Legg til Alias'; $PALANG['pCreate_alias_goto_text'] = 'Hvor skal e-posten videresendes?'; $PALANG['pCreate_alias_goto_text_error'] = 'Hvor skal eposten videresendes?.
Mottakerfeltet er ikke gyldig!'; $PALANG['pCreate_alias_result_error'] = 'Klarte ikke legge til aliaset!'; $PALANG['pCreate_alias_result_success'] = 'Aliaset er lagt til i alias-tabellen!'; $PALANG['pCreate_alias_catchall_text'] = 'For å opprette et alias som "mottar alt" bruk "*" som alias.
For domene-til-domene videresending bruk "*@domene.tld" som mottaker.'; $PALANG['pEdit_alias_welcome'] = 'Endre et alias.
En mottaker per linje.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Finner ikke aliaset!'; $PALANG['pEdit_alias_goto'] = 'Mottaker'; $PALANG['pEdit_alias_active'] = 'Active'; # XXX $PALANG['pEdit_alias_goto_text_error1'] = 'Du skrev ikke noe i mottakerfeltet'; $PALANG['pEdit_alias_goto_text_error2'] = 'E-post adressen er ugyldig: '; $PALANG['pEdit_alias_domain_error'] = 'Dette er ikke ditt domene: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Deliver to the local mailbox.'; # XXX $PALANG['pEdit_alias_forward_only'] = 'Forward to given email addresses only.'; # XXX $PALANG['pEdit_alias_button'] = 'Endre Alias'; $PALANG['pEdit_alias_result_error'] = 'Kan ikke endre Aliaset!'; $PALANG['pCreate_mailbox_welcome'] = 'Opprett en ny epostkonto.'; $PALANG['pCreate_mailbox_username'] = 'Brukernavn'; $PALANG['pCreate_mailbox_username_text_error1'] = '
E-postadressen er ugyldig!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
E-postadressen eksisterer allerede, velg en annen!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Du er over grensen for antall e-postkontoer!'; $PALANG['pCreate_mailbox_password'] = 'Passord'; $PALANG['pCreate_mailbox_password2'] = 'Passord (igjen)'; $PALANG['pCreate_mailbox_password_text'] = 'Passord for POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Passord for POP3/IMAP
Passordene er ikke like!
Eller feltet er tomt!
'; $PALANG['pCreate_mailbox_name'] = 'Namn'; $PALANG['pCreate_mailbox_name_text'] = 'Fornavn og etternavn'; $PALANG['pCreate_mailbox_quota'] = 'Kvote'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Den ønskede kvoten er for høy!'; $PALANG['pCreate_mailbox_active'] = 'Aktiv'; $PALANG['pCreate_mailbox_mail'] = 'Opprett epostkonto'; $PALANG['pCreate_mailbox_button'] = 'Opprett Alias'; $PALANG['pCreate_mailbox_result_error'] = 'Klarte ikke å legge til e-postkontoen!'; $PALANG['pCreate_mailbox_result_success'] = 'E-postkontoen er opprettet!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'The mailbox has been added to the mailbox table, but none (or only some) of the predefined sub-folders could be created'; # XXX $PALANG['pEdit_mailbox_welcome'] = 'Endre en e-postkonto.'; $PALANG['pEdit_mailbox_username'] = 'Brukernavn'; $PALANG['pEdit_mailbox_username_error'] = 'Fant ikke e-postkontoen!'; $PALANG['pEdit_mailbox_password'] = 'Nytt passord'; $PALANG['pEdit_mailbox_password2'] = 'Nytt passord (igjen)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Passordene er ikke like!'; $PALANG['pEdit_mailbox_name'] = 'Navn'; $PALANG['pEdit_mailbox_name_text'] = 'Full name'; # XXX $PALANG['pEdit_mailbox_quota'] = 'Kvote'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Kvoten er for høy!'; $PALANG['pEdit_mailbox_domain_error'] = 'Dette domenet er ikke ditt: '; $PALANG['pEdit_mailbox_button'] = 'Endre E-postkonto'; $PALANG['pEdit_mailbox_result_error'] = 'Klarte ikke å skifte passord'; $PALANG['pPassword_welcome'] = 'Endre Passord.'; $PALANG['pPassword_admin'] = 'Brukernavn'; $PALANG['pPassword_admin_text_error'] = 'Brukarnavnet eksisterer ikke'; $PALANG['pPassword_password_current'] = 'Eksisterende passord'; $PALANG['pPassword_password_current_text_error'] = 'Oppgi det eksisterende passordet!'; $PALANG['pPassword_password'] = 'Nytt passord'; $PALANG['pPassword_password2'] = 'Nytt passord (igjen)'; $PALANG['pPassword_password_text_error'] = 'Passordene er ikke like!
Eller feltet er tomt!
'; $PALANG['pPassword_button'] = 'Endre Passord'; $PALANG['pPassword_result_error'] = 'Klarte ikke å endre passord!'; $PALANG['pPassword_result_success'] = 'Passordet ditt er nå endret!'; $PALANG['pEdit_vacation_set'] = 'Change / Set away message'; # XXX $PALANG['pEdit_vacation_remove'] = 'Remove away message'; # XXX $PALANG['pVacation_result_error'] = 'Unable to update auto response settings!'; # XXX $PALANG['pVacation_result_removed'] = 'Auto response has been removed!'; # XXX $PALANG['pVacation_result_added'] = 'Auto response has been enabled!'; # XXX $PALANG['pViewlog_welcome'] = 'Vis de 10 siste handlingene '; $PALANG['pViewlog_timestamp'] = 'Klokkeslett'; $PALANG['pViewlog_username'] = 'Administrator'; $PALANG['pViewlog_domain'] = 'Domene'; $PALANG['pViewlog_action'] = 'Handling'; $PALANG['pViewlog_data'] = 'Data'; $PALANG['pViewlog_action_create_mailbox'] = 'create mailbox'; # XXX $PALANG['pViewlog_action_delete_mailbox'] = 'delete mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox'] = 'edit mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox_state'] = 'edit mailbox active'; # XXX $PALANG['pViewlog_action_create_alias'] = 'create alias'; # XXX $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'delete alias'; # XXX $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'edit alias'; # XXX $PALANG['pViewlog_action_edit_alias_state'] = 'edit alias active'; # XXX $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'change password'; # XXX $PALANG['pViewlog_button'] = 'Vis'; $PALANG['pViewlog_result_error'] = 'Fant ikke loggen!'; $PALANG['pSendmail_welcome'] = 'Send E-post.'; $PALANG['pSendmail_admin'] = 'Fra'; $PALANG['pSendmail_to'] = 'Mottaker'; $PALANG['pSendmail_to_text_error'] = '"Mottaker"-feltet er tomt eller er ugyldig!'; $PALANG['pSendmail_subject'] = 'Emne'; $PALANG['pSendmail_subject_text'] = 'Velkommen'; $PALANG['pSendmail_body'] = 'Melding'; $PALANG['pSendmail_button'] = 'Send beskjed'; $PALANG['pSendmail_result_error'] = 'Klarte ikke å opprette e-postkontoen!'; # XXX text change - new: Unable to send email! $PALANG['pSendmail_result_success'] = 'E-postkontoen er opprettet!'; # XXX text change - new: Email sent! $PALANG['pAdminMenu_list_admin'] = 'Administrator-liste'; $PALANG['pAdminMenu_list_domain'] = 'Domene-liste'; $PALANG['pAdminMenu_list_virtual'] = 'Virtuell Liste'; $PALANG['pAdminMenu_viewlog'] = 'Vis logg'; $PALANG['pAdminMenu_backup'] = 'Backup'; $PALANG['pAdminMenu_create_domain_admins'] = 'Domene-administratorer'; $PALANG['pAdminMenu_create_admin'] = 'Ny Administrator'; $PALANG['pAdminMenu_create_domain'] = 'Nytt Domene'; $PALANG['pAdminMenu_create_alias'] = 'Legg til Alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Legg til e-postkonto'; $PALANG['pAdminList_admin_domain'] = 'Domene'; $PALANG['pAdminList_admin_username'] = 'Administrator'; $PALANG['pAdminList_admin_count'] = 'Domener'; $PALANG['pAdminList_admin_modified'] = 'Sist endret'; $PALANG['pAdminList_admin_active'] = 'Aktiv'; $PALANG['pAdminList_domain_domain'] = 'Domene'; $PALANG['pAdminList_domain_description'] = 'Beskrivelse'; $PALANG['pAdminList_domain_aliases'] = 'Alias'; $PALANG['pAdminList_domain_mailboxes'] = 'Epostkontoer'; $PALANG['pAdminList_domain_maxquota'] = 'Maks Kvote (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; $PALANG['pAdminList_domain_modified'] = 'Sist endret'; $PALANG['pAdminList_domain_active'] = 'Aktive'; $PALANG['pAdminList_virtual_button'] = 'Vis'; $PALANG['pAdminList_virtual_welcome'] = 'Oversikt for '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Alias'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Epostkontoer'; $PALANG['pAdminList_virtual_alias_address'] = 'Fra'; $PALANG['pAdminList_virtual_alias_goto'] = 'Til'; $PALANG['pAdminList_virtual_alias_modified'] = 'Sist endret'; $PALANG['pAdminList_virtual_mailbox_username'] = 'E-post'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Navn'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Kvote (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Sist endret'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Aktiv'; $PALANG['pAdminCreate_domain_welcome'] = 'Legg til et nytt domene'; $PALANG['pAdminCreate_domain_domain'] = 'Domene'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Domenet eksisterer!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'The domain is invalid!'; # XXX $PALANG['pAdminCreate_domain_description'] = 'Beskrivelse'; $PALANG['pAdminCreate_domain_aliases'] = 'Alias'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = deaktivere | 0 = ubegrenset'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Epostkontoer'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = deaktivere | 0 = ubegrenset'; $PALANG['pAdminCreate_domain_maxquota'] = 'Maks Kvote'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = deaktivere | 0 = ubegrenset'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Definer transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Legg til standard Alias'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; # XXX $PALANG['pAdminCreate_domain_backupmx'] = 'E-postserveren er backup-MX'; $PALANG['pAdminCreate_domain_button'] = 'Legg til domene'; $PALANG['pAdminCreate_domain_result_error'] = 'Klarte ikke å legge til domenet!'; $PALANG['pAdminCreate_domain_result_success'] = 'Domenet er lagt til!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Unable to remove domain!'; # XXX $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = 'Endre domenet'; $PALANG['pAdminEdit_domain_domain'] = 'Domene'; $PALANG['pAdminEdit_domain_description'] = 'Beskrivelse'; $PALANG['pAdminEdit_domain_aliases'] = 'Alias'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = deaktivere | 0 = ubegrenset'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Epost kontoer'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = deaktivere | 0 = ubegrenset'; $PALANG['pAdminEdit_domain_maxquota'] = 'Maks kvote'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = deaktivere | 0 = ubegrenset'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Definer transport'; $PALANG['pAdminEdit_domain_backupmx'] = 'E-postservereb er backup-MX'; $PALANG['pAdminEdit_domain_active'] = 'Aktive'; $PALANG['pAdminEdit_domain_button'] = 'Endre'; $PALANG['pAdminEdit_domain_result_error'] = 'Klarte ikke å oppdatere domenet!'; $PALANG['pAdminCreate_admin_welcome'] = 'Legg til ny domene-administrator'; $PALANG['pAdminCreate_admin_username'] = 'Administrator'; $PALANG['pAdminCreate_admin_username_text'] = 'E-postadresse'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'E-postadresse
Administrator er ikke gyldig adresse!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'E-postadresse
Administratoren eksisterer eller er ikke gyldig'; $PALANG['pAdminCreate_admin_password'] = 'Passord'; $PALANG['pAdminCreate_admin_password2'] = 'Passord (igjen)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Passordene er ikke like!
Eller feltene er tomme!
'; $PALANG['pAdminCreate_admin_button'] = 'Legg til en administrator'; $PALANG['pAdminCreate_admin_result_error'] = 'Klarte ikke å legge til administratoren!'; $PALANG['pAdminCreate_admin_result_success'] = 'Administratoren er lagt til!'; $PALANG['pAdminCreate_admin_address'] = 'Domene'; $PALANG['pAdminEdit_admin_welcome'] = 'Endre domene-administrator'; $PALANG['pAdminEdit_admin_username'] = 'Administrator'; $PALANG['pAdminEdit_admin_password'] = 'Passord'; $PALANG['pAdminEdit_admin_password2'] = 'Passord (igjen)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Passordene er ikke like!
Eller feltene er tomme!
'; $PALANG['pAdminEdit_admin_active'] = 'Aktiv'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super admin'; # XXX $PALANG['pAdminEdit_admin_button'] = 'Endre Administrator'; $PALANG['pAdminEdit_admin_result_error'] = 'Klarte ikke å endre administratoren!'; $PALANG['pAdminEdit_admin_result_success'] = 'Administratoren er endret/oppdatert!'; $PALANG['pUsersLogin_welcome'] = 'Brukere, logg inn for å endre passord og videresending.'; $PALANG['pUsersLogin_username'] = 'Brukernavn (e-post adr.)'; $PALANG['pUsersLogin_password'] = 'Passord'; $PALANG['pUsersLogin_button'] = 'Logg inn'; $PALANG['pUsersLogin_username_incorrect'] = 'Feil brukernavn! Bruk e-postadressen din for å logge inn!'; $PALANG['pUsersLogin_password_incorrect'] = 'Feil passord!'; $PALANG['pUsersMenu_vacation'] = 'Automatisk Svar'; $PALANG['pUsersMenu_edit_alias'] = 'Endre videresending'; $PALANG['pUsersMenu_password'] = 'Endre Passord'; $PALANG['pUsersMain_vacation'] = 'Legg til en beskjed når du har status "ikke tilstede" eller et annet automatisk svar.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' is ON, click \'' . $PALANG['pUsersMenu_vacation'] . '\' to ' . $PALANG['edit'] . '/remove'; # XXX $PALANG['pUsersMain_edit_alias'] = 'Endre videresending.'; $PALANG['pUsersMain_password'] = 'Endre passord.'; $PALANG['pUsersVacation_welcome'] = 'Automatisk Svar.'; $PALANG['pUsersVacation_welcome_text'] = 'Du har allerede autosvar!'; $PALANG['pUsersVacation_subject'] = 'Emne'; $PALANG['pUsersVacation_subject_text'] = 'Ikke tilstede'; $PALANG['pUsersVacation_body'] = 'Melding'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << til . For viktige henvendelser kan du kontakte . EOM; $PALANG['pUsersVacation_button_away'] = 'Ikke tilstede'; $PALANG['pUsersVacation_button_back'] = 'Straks tilbake'; $PALANG['pUsersVacation_result_error'] = 'Klarte ikke å oppdatere dine autosvar-instillinger!'; $PALANG['pUsersVacation_result_success'] = 'Ditt autosvar er fjernet'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'oppret e-postkonto'; $PALANG['pCreate_dbLog_createalias'] = 'opprett alias'; $PALANG['pDelete_dbLog_deletealias'] = 'slett alias'; $PALANG['pDelete_dbLog_deletemailbox'] = 'slett e-postkonto'; $PALANG['pEdit_dbLog_editactive'] = 'endre status'; $PALANG['pEdit_dbLog_editalias'] = 'endre alias'; $PALANG['pEdit_dbLog_editmailbox'] = 'endre e-postkonto'; $PALANG['pSearch'] = 'søker'; $PALANG['pSearch_welcome'] = 'Søker etter: '; $PALANG['pReturn_to'] = 'Return to'; # XXX $PALANG['pBroadcast_title'] = 'Send broadcast message'; # XXX $PALANG['pBroadcast_from'] = 'From'; # XXX $PALANG['pBroadcast_name'] = 'Your name'; # XXX $PALANG['pBroadcast_subject'] = 'Subject'; # XXX $PALANG['pBroadcast_message'] = 'Message'; # XXX $PALANG['pBroadcast_send'] = 'Send message'; # XXX $PALANG['pBroadcast_success'] = 'Your broadcast message was sent.'; # XXX $PALANG['pAdminMenu_broadcast_message'] = 'Broadcast message'; # XXX $PALANG['pBroadcast_error_empty'] = 'The fields Name, Subject and Message should\'t be empty !'; # XXX $PALANG['pStatus_undeliverable'] = 'maybe UNDELIVERABLE '; # XXX $PALANG['pStatus_custom'] = 'Delivers to '; # XXX $PALANG['pStatus_popimap'] = 'POP/IMAP '; # XXX $PALANG['pPasswordTooShort'] = "Password is too short - requires %s characters"; # XXX $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Fetch mail for:'; # XXX $PALANG['pFetchmail_new_entry'] = 'New entry'; # XXX $PALANG['pFetchmail_database_save_error'] = 'Could not save this entry in the database!'; # XXX $PALANG['pFetchmail_database_save_success'] = 'Entry saved in database.'; # XXX $PALANG['pFetchmail_error_invalid_id'] = 'No entry with ID %s found!'; # XXX $PALANG['pFetchmail_invalid_mailbox'] = 'Invalid mailbox!'; # XXX $PALANG['pFetchmail_server_missing'] = 'Please enter the remote server name!'; # XXX $PALANG['pFetchmail_user_missing'] = 'Please enter the remote username!'; # XXX $PALANG['pFetchmail_password_missing'] = 'Please enter the remote password!'; # XXX $PALANG['pFetchmail_field_id'] = 'ID'; # XXX $PALANG['pFetchmail_field_mailbox'] = 'Mailbox'; # XXX $PALANG['pFetchmail_field_src_server'] = 'Server'; # XXX $PALANG['pFetchmail_field_src_auth'] = 'Auth Type'; # XXX $PALANG['pFetchmail_field_src_user'] = 'User'; # XXX $PALANG['pFetchmail_field_src_password'] = 'Password'; # XXX $PALANG['pFetchmail_field_src_folder'] = 'Folder'; # XXX $PALANG['pFetchmail_field_poll_time'] = 'Poll'; # XXX $PALANG['pFetchmail_field_fetchall'] = 'Fetch All'; # XXX $PALANG['pFetchmail_field_keep'] = 'Keep'; # XXX $PALANG['pFetchmail_field_protocol'] = 'Protocol'; # XXX $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra Options'; # XXX $PALANG['pFetchmail_field_mda'] = 'MDA'; # XXX $PALANG['pFetchmail_field_date'] = 'Date'; # XXX $PALANG['pFetchmail_field_returned_text'] = 'Returned Text'; # XXX $PALANG['pFetchmail_desc_id'] = 'Record ID'; # XXX $PALANG['pFetchmail_desc_mailbox'] = 'Local mailbox'; # XXX $PALANG['pFetchmail_desc_src_server'] = 'Remote Server'; # XXX $PALANG['pFetchmail_desc_src_auth'] = 'Mostly \'password\''; # Translators: Please do NOT translate 'password' here # XXX $PALANG['pFetchmail_desc_src_user'] = 'Remote User'; # XXX $PALANG['pFetchmail_desc_src_password'] = 'Remote Password'; # XXX $PALANG['pFetchmail_desc_src_folder'] = 'Remote Folder'; # XXX $PALANG['pFetchmail_desc_poll_time'] = 'Poll every ... minutes'; # XXX $PALANG['pFetchmail_desc_fetchall'] = 'Retrieve both old (seen) and new messages'; # XXX $PALANG['pFetchmail_desc_keep'] = 'Keep retrieved messages on the remote mailserver'; # XXX $PALANG['pFetchmail_desc_protocol'] = 'Protocol to use'; # XXX $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Extra fetchmail Options'; # XXX $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; # XXX $PALANG['pFetchmail_desc_date'] = 'Date of last polling/configuration change'; # XXX $PALANG['pFetchmail_desc_returned_text'] = 'Text message from last polling'; # XXX $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/sk.lang0000664000175000017620000006322011636730120017507 0ustar davidpalepurpleNie je možné zmazať položku '; $PALANG['pDelete_delete_success'] = '%s zmazané.'; $PALANG['pDelete_postdelete_error'] = 'Nie je možné odstrániť schránku '; $PALANG['pDelete_domain_error'] = 'Táto doména nie je vaša '; $PALANG['pDelete_domain_alias_error'] = 'Táto doména nie je vaša '; $PALANG['pDelete_alias_error'] = 'Nie je možné odstrániť alias '; $PALANG['pCreate_alias_domain_welcome'] = 'Zrkadliť adresy z jednej domény na druhú'; $PALANG['pCreate_alias_domain_alias'] = 'Alias'; $PALANG['pCreate_alias_domain_alias_text'] = 'Kam príde email'; $PALANG['pCreate_alias_domain_target'] = 'Cieľová doména'; $PALANG['pCreate_alias_domain_target_text'] = 'Kam sa email presmeruje'; $PALANG['pCreate_alias_domain_active'] = 'Aktívny'; $PALANG['pCreate_alias_domain_button'] = 'Vytvoriť alias domény'; $PALANG['pCreate_alias_domain_error1'] = 'Nie ste oprávnení vytvoriť zvolenú konfiguráciu.'; $PALANG['pCreate_alias_domain_error2'] = 'Zvolená konfigurácia nie je platná, zvoľte inú!'; $PALANG['pCreate_alias_domain_error3'] = 'Chyba pri vkladaní do databázy.'; $PALANG['pCreate_alias_domain_error4'] = 'Všetky domény už majú aliasy.'; $PALANG['pCreate_alias_domain_success'] = 'Alias domény bol pridaný do tabuľky!'; $PALANG['pCreate_alias_welcome'] = 'Vytvoriť nový alias v doméne'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
Adresa nie je platná!'; $PALANG['pCreate_alias_address_text_error2'] = '
Takáto emailová adresa už existuje!'; $PALANG['pCreate_alias_address_text_error3'] = '
Dosiahli ste limit, nemôžete vytvárať ďalšie aliasy!'; $PALANG['pCreate_alias_goto'] = 'Cieľ'; $PALANG['pCreate_alias_active'] = 'Aktívny'; $PALANG['pCreate_alias_button'] = 'Vytvoriť alias'; $PALANG['pCreate_alias_goto_text'] = 'Kam má pošta chodiť'; $PALANG['pCreate_alias_goto_text_error'] = 'Kam má pošta chodiť
Cieľ nie je platný!'; $PALANG['pCreate_alias_result_error'] = 'Nepodarilo sa pridať alias do tabuľky!'; $PALANG['pCreate_alias_result_success'] = 'Alias bol pridaný do tabuľky!'; $PALANG['pCreate_alias_catchall_text'] = 'Pre vytvorenie doménového koša použite * ako alias.
Pre alias doména-doména použite *@domain.tld ako cieľ.'; $PALANG['pEdit_alias_welcome'] = 'Upraviť aliasy
Jeden záznam na riadku'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Nie je možné nájsť alias!'; $PALANG['pEdit_alias_goto'] = 'Cieľ'; $PALANG['pEdit_alias_active'] = 'Aktívny'; $PALANG['pEdit_alias_goto_text_error1'] = 'Nezadali ste cieľ'; $PALANG['pEdit_alias_goto_text_error2'] = 'Zadaná emailová adresa nie je platná: '; $PALANG['pEdit_alias_domain_error'] = 'Táto doména nie je vaša: '; $PALANG['pEdit_alias_domain_result_error'] = 'Nepodarilo sa zmeniť alias domény!'; $PALANG['pEdit_alias_forward_and_store'] = 'Doručiť aj do lokálnej schránky'; $PALANG['pEdit_alias_forward_only'] = 'Len presmerovať na zadané emailové adresy'; $PALANG['pEdit_alias_button'] = 'Upraviť'; $PALANG['pEdit_alias_result_error'] = 'Nepodarilo se upraviť alias!'; $PALANG['pCreate_mailbox_welcome'] = 'Vytvoriť novú schránku v doméne'; $PALANG['pCreate_mailbox_username'] = 'Užívateľské meno'; $PALANG['pCreate_mailbox_username_text_error1'] = '
Adresa nie je platná!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Takáto emailová adresa už¸ existuje!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Dosiahli ste limit, nemôžete vytvárať ďalšie schránky!'; $PALANG['pCreate_mailbox_password'] = 'Heslo'; $PALANG['pCreate_mailbox_password2'] = 'Heslo (znovu)'; $PALANG['pCreate_mailbox_password_text'] = 'Heslo pre POP3/IMAP/SMTP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Heslo pre POP3/IMAP/SMTP
Zadaná heslá sú rozdielne alebo prázdne!'; $PALANG['pCreate_mailbox_name'] = 'Meno'; $PALANG['pCreate_mailbox_name_text'] = 'Celé meno'; $PALANG['pCreate_mailbox_quota'] = 'Kvóta'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Zadané miesto je príliš velké!'; $PALANG['pCreate_mailbox_active'] = 'Aktívna'; $PALANG['pCreate_mailbox_mail'] = 'Poslať uvítací email'; $PALANG['pCreate_mailbox_button'] = 'Vytvoriť schránku'; $PALANG['pCreate_mailbox_result_error'] = 'Nepodarilo sa pridať schránku do tabuľky!'; $PALANG['pCreate_mailbox_result_success'] = 'Schránka bola pridaná do tabuľky!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'Schránka bola pridaná do tabuľky, ale nepodarilo sa vytvoriť (niektoré) definované adresáre'; $PALANG['pEdit_mailbox_welcome'] = 'Upraviť schránku v doméne'; $PALANG['pEdit_mailbox_username'] = 'Užívateľské meno'; $PALANG['pEdit_mailbox_username_error'] = 'Nepodarilo sa nájsť schránku!'; $PALANG['pEdit_mailbox_password'] = 'Nové heslo'; $PALANG['pEdit_mailbox_password2'] = 'Nové heslo (znovu)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Zadaná heslá se nezhodujú!'; $PALANG['pEdit_mailbox_name'] = 'Meno'; $PALANG['pEdit_mailbox_name_text'] = 'Celé meno'; $PALANG['pEdit_mailbox_quota'] = 'Kvóta'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Zadané miesto je príliš veľké!'; $PALANG['pEdit_mailbox_domain_error'] = 'Táto doména nie je vaša: '; $PALANG['pEdit_mailbox_button'] = 'Upraviť schránku'; $PALANG['pEdit_mailbox_result_error'] = 'Nepodarilo sa upraviť schránku!'; $PALANG['pPassword_welcome'] = 'Zmeniť heslo'; $PALANG['pPassword_admin'] = 'Užívateľské meno'; $PALANG['pPassword_admin_text_error'] = 'Užívateľské meno sa nezhoduje so žiadnou schránkou!'; $PALANG['pPassword_password_current'] = 'Súčasné heslo'; $PALANG['pPassword_password_current_text_error'] = 'Nezadali ste súčasné heslo!'; $PALANG['pPassword_password'] = 'Nové heslo'; $PALANG['pPassword_password2'] = 'Nové heslo (znovu)'; $PALANG['pPassword_password_text_error'] = 'Zadané heslá sú rozdielne alebo prázdne!'; $PALANG['pPassword_button'] = 'Zmeniť heslo'; $PALANG['pPassword_result_error'] = 'Nepodarilo sa zmeniť heslo!'; $PALANG['pPassword_result_success'] = 'Heslo bolo zmenené!'; $PALANG['pEdit_vacation_set'] = 'Zmeniť/nastaviť aut. odpoveď'; $PALANG['pEdit_vacation_remove'] = 'Odstrániť aut. odpoveď'; $PALANG['pVacation_result_error'] = 'Neopdarilo sa zmeniť automatickú odpoveď!'; $PALANG['pVacation_result_removed'] = 'Automatická odpoveď bola odstránená!'; $PALANG['pVacation_result_added'] = 'Automatická odpoveď bola nastavená!'; $PALANG['pViewlog_welcome'] = 'Prehľad 10 posledných akcií pre '; $PALANG['pViewlog_timestamp'] = 'Časová značka'; $PALANG['pViewlog_username'] = 'Užívateľ'; $PALANG['pViewlog_domain'] = 'Doména'; $PALANG['pViewlog_action'] = 'Akcia'; $PALANG['pViewlog_data'] = 'Podrobnosti'; $PALANG['pViewlog_action_create_mailbox'] = 'vytvorenie schránky'; $PALANG['pViewlog_action_delete_mailbox'] = 'zrušenie schránky'; $PALANG['pViewlog_action_edit_mailbox'] = 'zmena schránky'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'zmena aktivity schránky'; $PALANG['pViewlog_action_create_alias'] = 'vytvorenie aliasu'; $PALANG['pViewlog_action_create_alias_domain'] = 'vytvorenie aliasu domény'; $PALANG['pViewlog_action_delete_alias'] = 'zrušenie aliasu'; $PALANG['pViewlog_action_delete_alias_domain'] = 'zrušenie aliasu domény'; $PALANG['pViewlog_action_edit_alias'] = 'zmena aliasu'; $PALANG['pViewlog_action_edit_alias_state'] = 'zmena aktivity aliasu'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'zmena aktivity aliasu domény'; $PALANG['pViewlog_action_edit_password'] = 'zmena hesla'; $PALANG['pViewlog_button'] = 'Prejsť'; $PALANG['pViewlog_result_error'] = 'Nepodarilo sa nájsť záznamy!'; $PALANG['pSendmail_welcome'] = 'Poslať email'; $PALANG['pSendmail_admin'] = 'Od'; $PALANG['pSendmail_to'] = 'Komu'; $PALANG['pSendmail_to_text_error'] = 'Cieľ nie je platná emailová adresa!'; $PALANG['pSendmail_subject'] = 'Predmet'; $PALANG['pSendmail_subject_text'] = 'Vitajte'; $PALANG['pSendmail_body'] = 'Obsah'; $PALANG['pSendmail_button'] = 'Poslať email'; $PALANG['pSendmail_result_error'] = 'Nepodarilo sa poslať email!'; $PALANG['pSendmail_result_success'] = 'Email odoslaný!'; $PALANG['pAdminMenu_list_admin'] = 'Administrátori'; $PALANG['pAdminMenu_list_domain'] = 'Domény'; $PALANG['pAdminMenu_list_virtual'] = 'Aliasy'; $PALANG['pAdminMenu_viewlog'] = 'Záznamy'; $PALANG['pAdminMenu_backup'] = 'Zálohovať'; $PALANG['pAdminMenu_create_domain_admins'] = 'Doménoví administrátori'; $PALANG['pAdminMenu_create_admin'] = 'Nový admin'; $PALANG['pAdminMenu_create_domain'] = 'Nová doména'; $PALANG['pAdminMenu_create_alias'] = 'Pridať alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Pridať schránku'; $PALANG['pAdminList_admin_domain'] = 'Doména'; $PALANG['pAdminList_admin_username'] = 'Administrátor'; $PALANG['pAdminList_admin_count'] = 'Domény'; $PALANG['pAdminList_admin_modified'] = 'Posledná zmena'; $PALANG['pAdminList_admin_active'] = 'Aktívny'; $PALANG['pAdminList_domain_domain'] = 'Doména'; $PALANG['pAdminList_domain_description'] = 'Popis'; $PALANG['pAdminList_domain_aliases'] = 'Aliasov'; $PALANG['pAdminList_domain_mailboxes'] = 'Schránok'; $PALANG['pAdminList_domain_maxquota'] = 'Max. kvóta (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; $PALANG['pAdminList_domain_backupmx'] = 'Záložný MX'; $PALANG['pAdminList_domain_modified'] = 'Posledná zmena'; $PALANG['pAdminList_domain_active'] = 'Aktívna'; $PALANG['pAdminList_virtual_button'] = 'Prejsť'; $PALANG['pAdminList_virtual_welcome'] = 'Prehľad pre '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Aliasov'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Schránok'; $PALANG['pAdminList_virtual_alias_address'] = 'Od'; $PALANG['pAdminList_virtual_alias_goto'] = 'Cieľ'; $PALANG['pAdminList_virtual_alias_modified'] = 'Posledná zmena'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Emailová adresa'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Meno'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Kvóta (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Posledná zmena'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Aktívny'; $PALANG['pAdminCreate_domain_welcome'] = 'Pridať novú doménu'; $PALANG['pAdminCreate_domain_domain'] = 'Doména'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Takáto doména už existuje!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'Doména nie je platná!'; $PALANG['pAdminCreate_domain_description'] = 'Popis'; $PALANG['pAdminCreate_domain_aliases'] = 'Aliasov'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = zakázať | 0 = neobmedzene'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Schránok'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = zakázať | 0 = neobmedzene'; $PALANG['pAdminCreate_domain_maxquota'] = 'Maximálna kvóta'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = vypnúť | 0 = neobmedzená'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Použiť transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Vytvoriť implicitné aliasy'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'Mail server je záložný MX'; $PALANG['pAdminCreate_domain_button'] = 'Vytvoriť doménu'; $PALANG['pAdminCreate_domain_result_error'] = 'Nepodarilo sa pridať doménu!'; $PALANG['pAdminCreate_domain_result_success'] = 'Doména bola pridaná!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Nepodarilo sa odstrániť doménu!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Nepodario sa odstrániť alias domény!'; $PALANG['pAdminEdit_domain_welcome'] = 'Upraviť doménu'; $PALANG['pAdminEdit_domain_domain'] = 'Doména'; $PALANG['pAdminEdit_domain_description'] = 'Popis'; $PALANG['pAdminEdit_domain_aliases'] = 'Aliasov'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = zakázať | 0 = neobmedzene'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Schránok'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = zakázať | 0 = neobmedzene'; $PALANG['pAdminEdit_domain_maxquota'] = 'Maximálna kvóta'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = vypnúť | 0 = neobmedzene'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Použiť transport'; $PALANG['pAdminEdit_domain_backupmx'] = 'Mail server je záložný MX'; $PALANG['pAdminEdit_domain_active'] = 'Aktívna'; $PALANG['pAdminEdit_domain_button'] = 'Upraviť doménu'; $PALANG['pAdminEdit_domain_result_error'] = 'Nepodarilo sa upraviť doménu!'; $PALANG['pAdminCreate_admin_welcome'] = 'Pridať nového administrátora'; $PALANG['pAdminCreate_admin_username'] = 'Užívateľské meno'; $PALANG['pAdminCreate_admin_username_text'] = 'Emailová adresa'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Emailová adresa
Táto adresa nie je platná!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Email address
Takáto adresa už existuje!'; $PALANG['pAdminCreate_admin_password'] = 'Heslo'; $PALANG['pAdminCreate_admin_password2'] = 'Heslo (znovu)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Zadané heslá sú rozdielne alebo prázdne!'; $PALANG['pAdminCreate_admin_button'] = 'Vytvoriť administrátora'; $PALANG['pAdminCreate_admin_result_error'] = 'Nepodarilo sa pridať administrátora!'; $PALANG['pAdminCreate_admin_result_success'] = 'Administrátor bol pridaný!'; $PALANG['pAdminCreate_admin_address'] = 'Domény'; $PALANG['pAdminEdit_admin_welcome'] = 'Upraviť doménového administrátora'; $PALANG['pAdminEdit_admin_username'] = 'Užívateľské meno'; $PALANG['pAdminEdit_admin_password'] = 'Heslo'; $PALANG['pAdminEdit_admin_password2'] = 'Heslo (znovu)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Zadané heslá sú rozdielne alebo prázdne!'; $PALANG['pAdminEdit_admin_active'] = 'Aktívny'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super admin'; $PALANG['pAdminEdit_admin_button'] = 'Upraviť administrátora'; $PALANG['pAdminEdit_admin_result_error'] = 'Nepodarilo sa upraviť administrátora!'; $PALANG['pAdminEdit_admin_result_success'] = 'Administrátor bol upravený!'; $PALANG['pUsersLogin_welcome'] = 'Prihlásenie užívateľov pre zmenu hesla alebo presmerovanie'; $PALANG['pUsersLogin_username'] = 'Užívateľské meno (email)'; $PALANG['pUsersLogin_password'] = 'Heslo'; $PALANG['pUsersLogin_button'] = 'Prihlásiť'; $PALANG['pUsersLogin_username_incorrect'] = 'Nesprávné užívateľské meno. Prihlasujte sa svojou emailovou adresou!'; $PALANG['pUsersLogin_password_incorrect'] = 'Nesprávne heslo!'; $PALANG['pUsersMenu_vacation'] = 'Automatická odpoveď'; $PALANG['pUsersMenu_edit_alias'] = 'Presmerovanie'; $PALANG['pUsersMenu_password'] = 'Zmena hesla'; $PALANG['pUsersMain_vacation'] = 'Nastaviť automatickú odpoveď (dovolenka a pod.).'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' zapnutá, kliknite na \'' . $PALANG['pUsersMenu_vacation'] . '\', ak ju chcete ' . $PALANG['edit'] . '/odstrániť'; $PALANG['pUsersMain_edit_alias'] = 'Nastaviť/zmeniť presmerovanie'; $PALANG['pUsersMain_password'] = 'Zmeniť heslo'; $PALANG['pUsersVacation_welcome'] = 'Automatická odpoveď'; $PALANG['pUsersVacation_welcome_text'] = 'Automatická odpoveď je zapnutá!'; $PALANG['pUsersVacation_subject'] = 'Predmet'; $PALANG['pUsersVacation_subject_text'] = 'Dovolenka'; $PALANG['pUsersVacation_body'] = 'Správa'; $PALANG['pUsersVacation_body_text'] = << od . S neodkladnými vecami kontaktujte . EOM; $PALANG['pUsersVacation_button_away'] = 'Zmeniť/nastaviť aut. odpoveď'; $PALANG['pUsersVacation_button_back'] = 'Odstrániť aut. odpoveď'; $PALANG['pUsersVacation_result_error'] = 'Nepodarilo sa upraviť nastavenie!'; $PALANG['pUsersVacation_result_success'] = 'Nastavenie bolo upravené!'; $PALANG['pUsersVacation_activefrom'] = 'Aktívna od'; $PALANG['pUsersVacation_activeuntil'] = 'Aktívna do'; $PALANG['pCreate_dbLog_createmailbox'] = 'vytvoriť mailbox'; $PALANG['pCreate_dbLog_createalias'] = 'vytvoriť alias'; $PALANG['pDelete_dbLog_deletealias'] = 'zmazať alias'; $PALANG['pDelete_dbLog_deletemailbox'] = 'zmazať mailbox'; $PALANG['pEdit_dbLog_editactive'] = 'zmena aktivity'; $PALANG['pEdit_dbLog_editalias'] = 'upraviť alias'; $PALANG['pEdit_dbLog_editmailbox'] = 'upraviť mailbox'; $PALANG['pSearch'] = 'Hľadanie'; $PALANG['pSearch_welcome'] = 'Hľadanie: '; $PALANG['pReturn_to'] = 'Návrat na'; $PALANG['pBroadcast_title'] = 'Poslať hromadnú správu všetkým používateľom'; $PALANG['pBroadcast_from'] = 'Od'; $PALANG['pBroadcast_name'] = 'Vaše meno'; $PALANG['pBroadcast_subject'] = 'Predmet'; $PALANG['pBroadcast_message'] = 'Obsah'; $PALANG['pBroadcast_send'] = 'Poslať správu'; $PALANG['pBroadcast_success'] = 'Hromadná správa bola odoslaná.'; $PALANG['pAdminMenu_broadcast_message'] = 'Hromadná správa'; $PALANG['pBroadcast_error_empty'] = 'Polie Vaše meno, Predmet a Obsah nemôžu byť prázdne!'; $PALANG['pStatus_undeliverable'] = 'možno NEDORUČITEĽNÉ '; $PALANG['pStatus_custom'] = 'Doručuje sa na '; $PALANG['pStatus_popimap'] = 'POP/IMAP '; $PALANG['pPasswordTooShort'] = "Heslo je príliš krátke - musí mať aspoň %s znakov"; $PALANG['pInvalidDomainRegex'] = "Neplatný názov domény %s"; $PALANG['pInvalidDomainDNS'] = "Neplatná doména %s alebo neexistuje jej DNS záznam"; $PALANG['pInvalidMailRegex'] = "Neplatná emailová adresa"; $PALANG['pFetchmail_welcome'] = 'Sťahovanie emailu pre:'; $PALANG['pFetchmail_new_entry'] = 'Nová položka'; $PALANG['pFetchmail_database_save_error'] = 'Nepodarilo sa uložiť položku do databázy!'; $PALANG['pFetchmail_database_save_success'] = 'Položka uložená do databázy.'; $PALANG['pFetchmail_error_invalid_id'] = 'Položka s ID %s neexistuje!'; $PALANG['pFetchmail_invalid_mailbox'] = 'Neplatná schránka!'; $PALANG['pFetchmail_server_missing'] = 'Zadajte názov vzdialeného servera!'; $PALANG['pFetchmail_user_missing'] = 'Zadajte meno vzdialeného používateľa!'; $PALANG['pFetchmail_password_missing'] = 'Zadajte heslo vzdialeného používateľa!'; $PALANG['pFetchmail_field_id'] = 'ID'; $PALANG['pFetchmail_field_mailbox'] = 'Schránka'; $PALANG['pFetchmail_field_src_server'] = 'Server'; $PALANG['pFetchmail_field_src_auth'] = 'Autentifikácia'; $PALANG['pFetchmail_field_src_user'] = 'Meno'; $PALANG['pFetchmail_field_src_password'] = 'Heslo'; $PALANG['pFetchmail_field_src_folder'] = 'Adresár'; $PALANG['pFetchmail_field_poll_time'] = 'Opakovanie'; $PALANG['pFetchmail_field_fetchall'] = 'Staré'; $PALANG['pFetchmail_field_keep'] = 'Ponechať'; $PALANG['pFetchmail_field_protocol'] = 'Protokol'; $PALANG['pFetchmail_field_usessl'] = 'SSL'; $PALANG['pFetchmail_field_extra_options'] = 'Parametre'; $PALANG['pFetchmail_field_mda'] = 'MDA'; $PALANG['pFetchmail_field_date'] = 'Dátum'; $PALANG['pFetchmail_field_returned_text'] = 'Výsledok'; $PALANG['pFetchmail_desc_id'] = 'ID záznamu'; $PALANG['pFetchmail_desc_mailbox'] = 'Lokálna schránka'; $PALANG['pFetchmail_desc_src_server'] = 'Vzdialený server'; $PALANG['pFetchmail_desc_src_auth'] = 'Väčšinou \'password\''; # Translators: Please do NOT translate 'password' here $PALANG['pFetchmail_desc_src_user'] = 'Vzdialené meno používateľa'; $PALANG['pFetchmail_desc_src_password'] = 'Vzdialené heslo'; $PALANG['pFetchmail_desc_src_folder'] = 'Vzdialený adresár'; $PALANG['pFetchmail_desc_poll_time'] = 'Sťahovať každých ... minút'; $PALANG['pFetchmail_desc_fetchall'] = 'Sťahovať staré (prečítané) aj nové správy'; $PALANG['pFetchmail_desc_keep'] = 'Ponechať stiahnuté správy na vzdialenom serveri'; $PALANG['pFetchmail_desc_protocol'] = 'Použiť protokol'; $PALANG['pFetchmail_desc_usessl'] = 'Šifrovanie SSL'; $PALANG['pFetchmail_desc_extra_options'] = 'Ďalšie parametre pre fetchmail'; $PALANG['pFetchmail_desc_mda'] = 'Doručovací program (Mail Delivery Agent)'; $PALANG['pFetchmail_desc_date'] = 'Dátum poslednej zmeny konfigurácie'; $PALANG['pFetchmail_desc_returned_text'] = 'Správa z posledného sťahovania'; $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/bg.lang0000664000175000017620000007562511636730120017476 0ustar davidpalepurpleНе мога да изтрия записа '; $PALANG['pDelete_delete_success'] = '%s deleted.'; # XXX $PALANG['pDelete_postdelete_error'] = 'Не мога да изтрия пощенската кутия'; $PALANG['pDelete_domain_error'] = 'Този домейн не е ваш! '; $PALANG['pDelete_domain_alias_error'] = 'Този домейн не е ваш '; $PALANG['pDelete_alias_error'] = 'Unable to delete alias '; # XXX $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'Не ви е позволено да използвате избраната конфигурация.'; $PALANG['pCreate_alias_domain_error2'] = 'Избраната конфигурация е невалидна. Изберете друга!'; $PALANG['pCreate_alias_domain_error3'] = 'Възникна грешка при добавяне в базата.'; $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = 'Създай нов alias за вашия домейн.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
Този ALIAS не е валиден!'; $PALANG['pCreate_alias_address_text_error2'] = '
Този е-мейл адрес вече съществува, моля изберете различен!'; $PALANG['pCreate_alias_address_text_error3'] = '
Достигнали сте лимита си за създаване на alias-и!'; $PALANG['pCreate_alias_goto'] = 'Към'; $PALANG['pCreate_alias_active'] = 'Активен'; $PALANG['pCreate_alias_button'] = 'Добави Alias'; $PALANG['pCreate_alias_goto_text'] = 'Накъде трябва да се изпраща писмото.'; $PALANG['pCreate_alias_goto_text_error'] = 'Накъде трябва да се изпраща писмото.
Избраният адрес в полето Към не е валиден!'; $PALANG['pCreate_alias_result_error'] = 'Не мога да добавя alias-а към таблицата!'; $PALANG['pCreate_alias_result_success'] = 'Alias-а беше добавен успешно в таблицата!'; $PALANG['pCreate_alias_catchall_text'] = 'За да създадете catch-all използвайте "*" за alias.
За пренасочване на домейн към домейн използвайте "*@domain.tld" в полето Към.'; $PALANG['pEdit_alias_welcome'] = 'Редактиране на alias за вашия домейн.
Един запис на ред.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Не мога да открия този alias!'; $PALANG['pEdit_alias_goto'] = 'Към'; $PALANG['pEdit_alias_active'] = 'Active'; # XXX $PALANG['pEdit_alias_goto_text_error1'] = 'Не сте въвели нищо в полето Към'; $PALANG['pEdit_alias_goto_text_error2'] = 'Е-мейл адреса, който сте въвели не е валиден: '; $PALANG['pEdit_alias_domain_error'] = 'Този домейн не е ваш: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Deliver to the local mailbox.'; # XXX $PALANG['pEdit_alias_forward_only'] = 'Forward to given email addresses only.'; # XXX $PALANG['pEdit_alias_button'] = 'Редактирай Alias'; $PALANG['pEdit_alias_result_error'] = 'Не мога да модифицирам този alias!'; $PALANG['pCreate_mailbox_welcome'] = 'Създаване на нова пощенска кутия за вашия домейн.'; $PALANG['pCreate_mailbox_username'] = 'Логин'; $PALANG['pCreate_mailbox_username_text_error1'] = '
Е-мейл-а не е валиден!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Този е-мейл адрес вече съществува, моля изберете друг!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Вие сте достигнали своя лимит за създаване на пощенски кутии!'; $PALANG['pCreate_mailbox_password'] = 'Парола'; $PALANG['pCreate_mailbox_password2'] = 'Парола (отново)'; $PALANG['pCreate_mailbox_password_text'] = 'Парола за POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Парола за POP3/IMAP
Паролите, които сте дали не съвпадат!
Или са празни!
'; $PALANG['pCreate_mailbox_name'] = 'Име'; $PALANG['pCreate_mailbox_name_text'] = 'Пълно име'; $PALANG['pCreate_mailbox_quota'] = 'Обем'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Обема, който сте задали е твърде голям!'; $PALANG['pCreate_mailbox_active'] = 'Активен'; $PALANG['pCreate_mailbox_mail'] = 'Създай пощенска кутия'; $PALANG['pCreate_mailbox_button'] = 'Добави пощенска кутия'; $PALANG['pCreate_mailbox_result_error'] = 'Не мога да добавя пощенската кутия в таблицата!'; $PALANG['pCreate_mailbox_result_success'] = 'Пощенската кутия бе успешно създадена и добавена в таблицата!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'The mailbox has been added to the mailbox table, but none (or only some) of the predefined sub-folders could be created'; # XXX $PALANG['pEdit_mailbox_welcome'] = 'Редакция на пощенска кутия за вашия домейн.'; $PALANG['pEdit_mailbox_username'] = 'Логин'; $PALANG['pEdit_mailbox_username_error'] = 'Не мога да открия пощенската кутия!'; $PALANG['pEdit_mailbox_password'] = 'Нова парола'; $PALANG['pEdit_mailbox_password2'] = 'Нова парола (отново)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Паролите, които сте дали не съвпадат!'; $PALANG['pEdit_mailbox_name'] = 'Име'; $PALANG['pEdit_mailbox_name_text'] = 'Full name'; # XXX $PALANG['pEdit_mailbox_quota'] = 'Обем'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Обема, който сте дали е твърде голям!'; $PALANG['pEdit_mailbox_domain_error'] = 'Този домейн не е ваш: '; $PALANG['pEdit_mailbox_button'] = 'Редакция на пощенска кутия'; $PALANG['pEdit_mailbox_result_error'] = 'Не мога да модифицирам пощенската кутия!'; $PALANG['pPassword_welcome'] = 'Смяна на парола.'; $PALANG['pPassword_admin'] = 'Логин'; $PALANG['pPassword_admin_text_error'] = 'Логин-а, който сте дали не съвпада с пощенската кутия!'; $PALANG['pPassword_password_current'] = 'Настояща парола'; $PALANG['pPassword_password_current_text_error'] = 'Не сте въвели вашата настояща парола!'; $PALANG['pPassword_password'] = 'Нова парола'; $PALANG['pPassword_password2'] = 'Нова парола (отново)'; $PALANG['pPassword_password_text_error'] = 'Паролите, които сте въвели не съвпадат!
Или са празни!
'; $PALANG['pPassword_button'] = 'Смени парола'; $PALANG['pPassword_result_error'] = 'Не мога да сменя паролата!'; $PALANG['pPassword_result_success'] = 'Паролата ви бе сменена успешно!'; $PALANG['pEdit_vacation_set'] = 'Change / Set away message'; # XXX $PALANG['pEdit_vacation_remove'] = 'Remove away message'; # XXX $PALANG['pVacation_result_error'] = 'Unable to update auto response settings!'; # XXX $PALANG['pVacation_result_removed'] = 'Auto response has been removed!'; # XXX $PALANG['pVacation_result_added'] = 'Auto response has been enabled!'; # XXX $PALANG['pViewlog_welcome'] = 'Разглеждане на последните 10 действия за '; $PALANG['pViewlog_timestamp'] = 'Дата'; $PALANG['pViewlog_username'] = 'Админ'; $PALANG['pViewlog_domain'] = 'Домейн'; $PALANG['pViewlog_action'] = 'Действие'; $PALANG['pViewlog_data'] = 'Данни'; $PALANG['pViewlog_action_create_mailbox'] = 'create mailbox'; # XXX $PALANG['pViewlog_action_delete_mailbox'] = 'delete mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox'] = 'edit mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox_state'] = 'edit mailbox active'; # XXX $PALANG['pViewlog_action_create_alias'] = 'create alias'; # XXX $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'delete alias'; # XXX $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'edit alias'; # XXX $PALANG['pViewlog_action_edit_alias_state'] = 'edit alias active'; # XXX $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'change password'; # XXX $PALANG['pViewlog_button'] = 'Напред'; $PALANG['pViewlog_result_error'] = 'Не мога да открия логовете!'; $PALANG['pSendmail_welcome'] = 'Изпращане на е-мейл.'; $PALANG['pSendmail_admin'] = 'От'; $PALANG['pSendmail_to'] = 'До'; $PALANG['pSendmail_to_text_error'] = 'Полето До е празен или невалиден е-мейл адрес!'; $PALANG['pSendmail_subject'] = 'Заглавие'; $PALANG['pSendmail_subject_text'] = 'Добре дошли'; $PALANG['pSendmail_body'] = 'Текст'; $PALANG['pSendmail_button'] = 'Изпрати'; $PALANG['pSendmail_result_error'] = 'Не мога да изпратя съобщението!'; $PALANG['pSendmail_result_success'] = 'Съобщението беше изпратено!'; $PALANG['pAdminMenu_list_admin'] = 'Списък с админите'; $PALANG['pAdminMenu_list_domain'] = 'Списък с домейните'; $PALANG['pAdminMenu_list_virtual'] = 'Виртуален списък'; $PALANG['pAdminMenu_viewlog'] = 'Преглед на лога'; $PALANG['pAdminMenu_backup'] = 'Резервно копие'; $PALANG['pAdminMenu_create_domain_admins'] = 'Админи на домейни'; $PALANG['pAdminMenu_create_admin'] = 'Нов админ'; $PALANG['pAdminMenu_create_domain'] = 'Нов домейн'; $PALANG['pAdminMenu_create_alias'] = 'Добави Alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Добави пощенска кутия'; $PALANG['pAdminList_admin_domain'] = 'Домейн'; $PALANG['pAdminList_admin_username'] = 'Админ'; $PALANG['pAdminList_admin_count'] = 'Домейни'; $PALANG['pAdminList_admin_modified'] = 'Последно модифициран'; $PALANG['pAdminList_admin_active'] = 'Активен'; $PALANG['pAdminList_domain_domain'] = 'Домейн'; $PALANG['pAdminList_domain_description'] = 'Описание'; $PALANG['pAdminList_domain_aliases'] = 'Alias-и'; $PALANG['pAdminList_domain_mailboxes'] = 'Пощенски кутии'; $PALANG['pAdminList_domain_maxquota'] = 'Максимален обем (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; # XXX $PALANG['pAdminList_domain_modified'] = 'Последно модифициран'; $PALANG['pAdminList_domain_active'] = 'Активен'; $PALANG['pAdminList_virtual_button'] = 'Напред'; $PALANG['pAdminList_virtual_welcome'] = 'Преглед на '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Alias-и'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Пощенски кутии'; $PALANG['pAdminList_virtual_alias_address'] = 'От'; $PALANG['pAdminList_virtual_alias_goto'] = 'Към'; $PALANG['pAdminList_virtual_alias_modified'] = 'Последно модифициран'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Е-мейл'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Име'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Обем (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Последно модифициран'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Активен'; $PALANG['pAdminCreate_domain_welcome'] = 'Добавяне на нов домейн'; $PALANG['pAdminCreate_domain_domain'] = 'домейн'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Този домейн вече съществува!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'Невалиден домайн!'; $PALANG['pAdminCreate_domain_description'] = 'Описание'; $PALANG['pAdminCreate_domain_aliases'] = 'Alias-и'; $PALANG['pAdminCreate_domain_aliases_text'] = '0 = изключени | -1 = неограничени'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Пощенски кутии'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '0 = изключени | -1 = неограничени'; $PALANG['pAdminCreate_domain_maxquota'] = 'Максимален обем'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
0 = изключено | -1 = неограничен'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Define transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Добави alias-и по подразбиране'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; # XXX $PALANG['pAdminCreate_domain_backupmx'] = 'Мейл сървъра е резервен MX'; $PALANG['pAdminCreate_domain_button'] = 'Добави домейн'; $PALANG['pAdminCreate_domain_result_error'] = 'Не мога да добавя домейна!'; $PALANG['pAdminCreate_domain_result_success'] = 'Домейна бе добавен успешно!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Грешка при изтриването на домейна!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = 'Редактиране на домейн'; $PALANG['pAdminEdit_domain_domain'] = 'Домейн'; $PALANG['pAdminEdit_domain_description'] = 'Описание'; $PALANG['pAdminEdit_domain_aliases'] = 'Alias-и'; $PALANG['pAdminEdit_domain_aliases_text'] = '0 = изключени | -1 = неограничени'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Пощенски кутии'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '0 = изключени | -1 = неограничени'; $PALANG['pAdminEdit_domain_maxquota'] = 'Максимален обем'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
0 = изключено | -1 = неограничен'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Define transport'; $PALANG['pAdminEdit_domain_backupmx'] = 'Мейл сървъра е резервен MX'; $PALANG['pAdminEdit_domain_active'] = 'Активен'; $PALANG['pAdminEdit_domain_button'] = 'Редактирай домейн'; $PALANG['pAdminEdit_domain_result_error'] = 'Не мога да модифицирам домейна!'; $PALANG['pAdminCreate_admin_welcome'] = 'Добави нов админ на домейна'; $PALANG['pAdminCreate_admin_username'] = 'Админ'; $PALANG['pAdminCreate_admin_username_text'] = 'Е-мейл адрес'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Е-мейл адрес
Админ не е валиден е-мейл адрес!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Е-мейл адрес
Админ-а вече съществува или не е валиден'; $PALANG['pAdminCreate_admin_password'] = 'Парола'; $PALANG['pAdminCreate_admin_password2'] = 'Парола (отново)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Паролите, които сте въвели не съвпадат!
Или са празни!
'; $PALANG['pAdminCreate_admin_button'] = 'Добави админ'; $PALANG['pAdminCreate_admin_result_error'] = 'Не мога да добавя админа!'; $PALANG['pAdminCreate_admin_result_success'] = 'Админа беше добавен успешно!'; $PALANG['pAdminCreate_admin_address'] = 'Домейн'; $PALANG['pAdminEdit_admin_welcome'] = 'Редакция на админ на домейн'; $PALANG['pAdminEdit_admin_username'] = 'Админ'; $PALANG['pAdminEdit_admin_password'] = 'Парола'; $PALANG['pAdminEdit_admin_password2'] = 'Парола (отново)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Паролите, които сте въвели не съвпадат!
Или са празни!
'; $PALANG['pAdminEdit_admin_active'] = 'Активен'; $PALANG['pAdminEdit_admin_super_admin'] = 'Главен Администратор'; $PALANG['pAdminEdit_admin_button'] = 'Редактирай Админ'; $PALANG['pAdminEdit_admin_result_error'] = 'Не мога да модифицирам админа!'; $PALANG['pAdminEdit_admin_result_success'] = 'Админ-а беше модифициран!'; $PALANG['pUsersLogin_welcome'] = 'Потребителски вход за смяна на парола и alias-и.'; $PALANG['pUsersLogin_username'] = 'Логин (е-мейл)'; $PALANG['pUsersLogin_password'] = 'Парола'; $PALANG['pUsersLogin_button'] = 'Вход'; $PALANG['pUsersLogin_username_incorrect'] = 'Вашият логин не е правилен. Моля проверете за коректност на вашият е-мейл адрес!'; $PALANG['pUsersLogin_password_incorrect'] = 'Вашата парола не е правилна!'; $PALANG['pUsersMenu_vacation'] = 'Автоматичен отговор'; $PALANG['pUsersMenu_edit_alias'] = 'Смяна на пренасочването'; $PALANG['pUsersMenu_password'] = 'Смени парола'; $PALANG['pUsersMain_vacation'] = 'Настройване на "out of office" съобщение или автоматичен отговор за вашият е-мейл.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' is ON, click \'' . $PALANG['pUsersMenu_vacation'] . '\' to ' . $PALANG['edit'] . '/remove'; # XXX $PALANG['pUsersMain_edit_alias'] = 'Смяна на пренасочването на е-мейл.'; $PALANG['pUsersMain_password'] = 'Смяна на настоящата парола.'; $PALANG['pUsersVacation_welcome'] = 'Автоматичен отговор.'; $PALANG['pUsersVacation_welcome_text'] = 'Вие вече си имате конфигриран автоматичен отговор!'; $PALANG['pUsersVacation_subject'] = 'Заглавие'; $PALANG['pUsersVacation_subject_text'] = 'Out of Office'; # XXX $PALANG['pUsersVacation_body'] = 'Текст'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << до . При спешност можете да се свържете с . EOM; $PALANG['pUsersVacation_button_away'] = 'Отивам във ваканция'; $PALANG['pUsersVacation_button_back'] = 'Връщам се от ваканция'; $PALANG['pUsersVacation_result_error'] = 'Не мога да обновя настройките за вашият автоматичен отговор!'; $PALANG['pUsersVacation_result_success'] = 'Вашият автоматичен отговор беше премахнат!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'create mailbox'; # XXX $PALANG['pCreate_dbLog_createalias'] = 'create alias'; # XXX $PALANG['pDelete_dbLog_deletealias'] = 'delete alias'; # XXX $PALANG['pDelete_dbLog_deletemailbox'] = 'delete mailbox'; # XXX $PALANG['pEdit_dbLog_editactive'] = 'change active state'; # XXX $PALANG['pEdit_dbLog_editalias'] = 'edit alias'; # XXX $PALANG['pEdit_dbLog_editmailbox'] = 'edit mailbox'; # XXX $PALANG['pSearch'] = 'search'; # XXX $PALANG['pSearch_welcome'] = 'Searching for: '; # XXX $PALANG['pReturn_to'] = 'Return to'; # XXX $PALANG['pBroadcast_title'] = 'Съобщение до всички'; $PALANG['pBroadcast_from'] = 'От'; $PALANG['pBroadcast_name'] = 'Име'; $PALANG['pBroadcast_subject'] = 'Заглавие'; $PALANG['pBroadcast_message'] = 'Съобщение'; $PALANG['pBroadcast_send'] = 'Изпрати'; $PALANG['pBroadcast_success'] = 'Вашето съобщение беше изпратено.'; $PALANG['pAdminMenu_broadcast_message'] = 'Съобщение до всички'; $PALANG['pBroadcast_error_empty'] = 'Полетата Име, Заглавие и Съобщение са задължителни!'; $PALANG['pStatus_undeliverable'] = 'maybe UNDELIVERABLE '; # XXX $PALANG['pStatus_custom'] = 'Delivers to '; # XXX $PALANG['pStatus_popimap'] = 'POP/IMAP '; # XXX $PALANG['pPasswordTooShort'] = "Password is too short - requires %s characters"; # XXX $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Fetch mail for:'; # XXX $PALANG['pFetchmail_new_entry'] = 'New entry'; # XXX $PALANG['pFetchmail_database_save_error'] = 'Could not save this entry in the database!'; # XXX $PALANG['pFetchmail_database_save_success'] = 'Entry saved in database.'; # XXX $PALANG['pFetchmail_error_invalid_id'] = 'No entry with ID %s found!'; # XXX $PALANG['pFetchmail_invalid_mailbox'] = 'Invalid mailbox!'; # XXX $PALANG['pFetchmail_server_missing'] = 'Please enter the remote server name!'; # XXX $PALANG['pFetchmail_user_missing'] = 'Please enter the remote username!'; # XXX $PALANG['pFetchmail_password_missing'] = 'Please enter the remote password!'; # XXX $PALANG['pFetchmail_field_id'] = 'ID'; # XXX $PALANG['pFetchmail_field_mailbox'] = 'Mailbox'; # XXX $PALANG['pFetchmail_field_src_server'] = 'Server'; # XXX $PALANG['pFetchmail_field_src_auth'] = 'Auth Type'; # XXX $PALANG['pFetchmail_field_src_user'] = 'User'; # XXX $PALANG['pFetchmail_field_src_password'] = 'Password'; # XXX $PALANG['pFetchmail_field_src_folder'] = 'Folder'; # XXX $PALANG['pFetchmail_field_poll_time'] = 'Poll'; # XXX $PALANG['pFetchmail_field_fetchall'] = 'Fetch All'; # XXX $PALANG['pFetchmail_field_keep'] = 'Keep'; # XXX $PALANG['pFetchmail_field_protocol'] = 'Protocol'; # XXX $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra Options'; # XXX $PALANG['pFetchmail_field_mda'] = 'MDA'; # XXX $PALANG['pFetchmail_field_date'] = 'Date'; # XXX $PALANG['pFetchmail_field_returned_text'] = 'Returned Text'; # XXX $PALANG['pFetchmail_desc_id'] = 'Record ID'; # XXX $PALANG['pFetchmail_desc_mailbox'] = 'Local mailbox'; # XXX $PALANG['pFetchmail_desc_src_server'] = 'Remote Server'; # XXX $PALANG['pFetchmail_desc_src_auth'] = 'Mostly \'password\''; # Translators: Please do NOT translate 'password' here # XXX $PALANG['pFetchmail_desc_src_user'] = 'Remote User'; # XXX $PALANG['pFetchmail_desc_src_password'] = 'Remote Password'; # XXX $PALANG['pFetchmail_desc_src_folder'] = 'Remote Folder'; # XXX $PALANG['pFetchmail_desc_poll_time'] = 'Poll every ... minutes'; # XXX $PALANG['pFetchmail_desc_fetchall'] = 'Retrieve both old (seen) and new messages'; # XXX $PALANG['pFetchmail_desc_keep'] = 'Keep retrieved messages on the remote mailserver'; # XXX $PALANG['pFetchmail_desc_protocol'] = 'Protocol to use'; # XXX $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Extra fetchmail Options'; # XXX $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; # XXX $PALANG['pFetchmail_desc_date'] = 'Date of last polling/configuration change'; # XXX $PALANG['pFetchmail_desc_returned_text'] = 'Text message from last polling'; # XXX $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/et.lang0000664000175000017620000006471211636730120017511 0ustar davidpalepurple // $PALANG['YES'] = 'JAH'; $PALANG['NO'] = 'EI'; $PALANG['edit'] = 'Redigeeri'; $PALANG['del'] = 'Kustuta'; $PALANG['exit'] = 'Exit'; # XXX $PALANG['cancel'] = 'Cancel'; # XXX $PALANG['save'] = 'Save'; # XXX $PALANG['confirm'] = 'Oled kindel, et soovid seda kustutada?\n'; $PALANG['confirm_domain'] = 'Oled tõesti kindel, et tahad kustutada kõik kirjed sellele domeenile? Seda tegevust ei saa tagasi võtta!\n'; $PALANG['check_update'] = 'Check for update'; # XXX $PALANG['invalid_parameter'] = 'Invalid parameter!'; # XXX $PALANG['pFooter_logged_as'] = 'Logged as %s'; # XXX $PALANG['pLogin_welcome'] = 'E-posti haldaja, logi siit domeeni administreerimiseks sisse.'; $PALANG['pLogin_username'] = 'Kasutajanimi (e-posti aadress)'; $PALANG['pLogin_password'] = 'Parool'; $PALANG['pLogin_button'] = 'Logi sisse'; $PALANG['pLogin_failed'] = 'Your email address or password are not correct.'; # XXX $PALANG['pLogin_login_users'] = 'Kasutaja, klõpsa siia logimaks sisse kasutaja sektsiooni.'; $PALANG['pMenu_main'] = 'Main'; # XXX $PALANG['pMenu_overview'] = 'Ülevaade'; $PALANG['pMenu_create_alias'] = 'Lisa alias'; $PALANG['pMenu_create_alias_domain'] = 'Add Alias Domain'; # XXX $PALANG['pMenu_create_mailbox'] = 'Lisa postkast'; $PALANG['pMenu_fetchmail'] = 'Fetch Email'; # XXX $PALANG['pMenu_sendmail'] = 'Saada kiri'; $PALANG['pMenu_password'] = 'Parool'; $PALANG['pMenu_viewlog'] = 'Vaata logi'; $PALANG['pMenu_logout'] = 'Logi välja'; $PALANG['pMain_welcome'] = 'Tere tulemast domeeni(de) administreerimise liidesesse!'; $PALANG['pMain_overview'] = 'Loetelu aliastest ja postkastidest. Siin saab neid muuta ja kustutada.'; $PALANG['pMain_create_alias'] = 'Loo uus alias domeenile.'; $PALANG['pMain_create_mailbox'] = 'Loo uus postkast domeenile.'; $PALANG['pMain_sendmail'] = 'Saada kiri äsjaloodud postkasti.'; $PALANG['pMain_password'] = 'Muuda haldamise konto parool.'; $PALANG['pMain_viewlog'] = 'Vaata logi faili.'; $PALANG['pMain_logout'] = 'Logi välja liidesest.'; $PALANG['pOverview_disabled'] = 'Deaktiveeritud'; $PALANG['pOverview_unlimited'] = 'Piiramata'; $PALANG['pOverview_title'] = ':: Valitud domeenid'; $PALANG['pOverview_up_arrow'] = 'Mine üles'; $PALANG['pOverview_right_arrow'] = 'Järgmine leht'; $PALANG['pOverview_left_arrow'] = 'Eelmine leht'; $PALANG['pOverview_alias_domain_title'] = ':: Domain Aliases'; # XXX $PALANG['pOverview_alias_title'] = ':: Alias'; $PALANG['pOverview_mailbox_title'] = ':: Postkastid'; $PALANG['pOverview_button'] = 'Mine'; $PALANG['pOverview_welcome'] = 'Ülevaade domeenist: '; $PALANG['pOverview_alias_domain_aliases'] = 'Alias Domains'; # XXX $PALANG['pOverview_alias_domain_target'] = '%s is an Alias Domain for:'; # XXX $PALANG['pOverview_alias_alias_count'] = 'Aliasi'; $PALANG['pOverview_alias_mailbox_count'] = 'Postkaste'; $PALANG['pOverview_alias_address'] = 'Kellelt'; $PALANG['pOverview_alias_goto'] = 'Kellele'; $PALANG['pOverview_alias_modified'] = 'Viimati muudetud'; $PALANG['pOverview_alias_domain_modified'] = 'Last Modified'; # XXX $PALANG['pOverview_alias_active'] = 'Active'; # XXX $PALANG['pOverview_alias_domain_active'] = 'Active'; # XXX $PALANG['pOverview_alias_edit'] = 'Alias'; # XXX $PALANG['and_x_more'] = '[and %s more...]'; # XXX $PALANG['pOverview_mailbox_username'] = 'E-posti aadress'; $PALANG['pOverview_mailbox_name'] = 'Nimi'; $PALANG['pOverview_mailbox_quota'] = 'Kettaruumi piirang (MB)'; $PALANG['pOverview_mailbox_modified'] = 'Viimati muudetud'; $PALANG['pOverview_mailbox_active'] = 'Aktiivne'; $PALANG['pOverview_vacation_edit'] = 'VACATION IS ON'; # XXX $PALANG['pOverview_vacation_option'] = 'Set Vacation'; # XXX $PALANG['pOverview_get_domain'] = 'Domeen'; $PALANG['pOverview_get_aliases'] = 'Aliased'; $PALANG['pOverview_get_alias_domains'] = 'Domain Aliases'; # XXX $PALANG['pOverview_get_mailboxes'] = 'Postkastid'; $PALANG['pOverview_get_quota'] = 'Postkasti kettaruumi piirang (MB)'; $PALANG['pOverview_get_modified'] = 'Viimati muudetud'; $PALANG['pDelete_delete_error'] = 'Kustutamine ebaõnnestus. Kirje: '; $PALANG['pDelete_delete_success'] = '%s deleted.'; # XXX $PALANG['pDelete_postdelete_error'] = 'Unable to remove mailbox '; # XXX $PALANG['pDelete_domain_error'] = 'Puuduvad õigused. Domeen: '; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = 'Unable to delete alias '; # XXX $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = 'Loo uus alias domeenis.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
ALIAS pole kehtiv!'; $PALANG['pCreate_alias_address_text_error2'] = '
See e-posti aadress eksisteerib juba, palun vali erinev!'; $PALANG['pCreate_alias_address_text_error3'] = '
Oled kasutanud kogu aliaste arvu!'; $PALANG['pCreate_alias_goto'] = 'Kellele'; $PALANG['pCreate_alias_active'] = 'Active'; # XXX $PALANG['pCreate_alias_button'] = 'Lisa alias'; $PALANG['pCreate_alias_goto_text'] = 'Kuhu peab kirja saatma.'; $PALANG['pCreate_alias_goto_text_error'] = 'Kuhu peab kirja saatma.
Kellele pole kehtiv!'; $PALANG['pCreate_alias_result_error'] = 'Aliase lisamine tabelisse ebaõnnestus!'; $PALANG['pCreate_alias_result_success'] = 'Alias lisati aliaste tabelisse!'; $PALANG['pCreate_alias_catchall_text'] = 'Loomaks püüa-kõik aadressi kasuta aliasena "*".
Domeenilt domeenile edasisaatmiseks kasuta kellele väljal "*@domeen.xx".'; $PALANG['pEdit_alias_welcome'] = 'Muuda aliast.
Üks kirje rea kohta.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Aliase muutmine ebaõnnestus!'; $PALANG['pEdit_alias_goto'] = 'Kellele'; $PALANG['pEdit_alias_active'] = 'Active'; # XXX $PALANG['pEdit_alias_goto_text_error1'] = 'Kellele väli on tühi.'; $PALANG['pEdit_alias_goto_text_error2'] = 'Sisestatud e/posti aadress pole kehtiv: '; $PALANG['pEdit_alias_domain_error'] = 'Puuduvad õigused. Domeen: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Deliver to the local mailbox.'; # XXX $PALANG['pEdit_alias_forward_only'] = 'Forward to given email addresses only.'; # XXX $PALANG['pEdit_alias_button'] = 'Muuda alias'; $PALANG['pEdit_alias_result_error'] = 'Aliase muutmine ebaõnnestus!'; $PALANG['pCreate_mailbox_welcome'] = 'Loo uus postkast domeenis.'; $PALANG['pCreate_mailbox_username'] = 'Kasutajanimi'; $PALANG['pCreate_mailbox_username_text_error1'] = '
E-posti aadress pole kehtiv!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Selline e-posti aadress on juba olemas, palun vali erinev!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Oled kasutanud kogu postkastide arvu!'; $PALANG['pCreate_mailbox_password'] = 'Parool'; $PALANG['pCreate_mailbox_password2'] = 'Parool (uuesti)'; $PALANG['pCreate_mailbox_password_text'] = 'Parool POP3/IMAP\'le'; $PALANG['pCreate_mailbox_password_text_error'] = 'Parool POP3/IMAP\'le
Sisestatud paroolid ei kattu!
Või on tühjad!
'; $PALANG['pCreate_mailbox_name'] = 'Nimi'; $PALANG['pCreate_mailbox_name_text'] = 'Täielik nimi'; $PALANG['pCreate_mailbox_quota'] = 'Kettaruumi piirang'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Sisestatud kettaruumi piirang on liiga kõrge!'; $PALANG['pCreate_mailbox_active'] = 'Aktiivne'; $PALANG['pCreate_mailbox_mail'] = 'Loo postkast'; $PALANG['pCreate_mailbox_button'] = 'Lisa postkast'; $PALANG['pCreate_mailbox_result_error'] = 'Postkasti lisamine tabelisse ebaõnnestus!'; $PALANG['pCreate_mailbox_result_success'] = 'Postkast lisati postkastide tabelisse!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'The mailbox has been added to the mailbox table, but none (or only some) of the predefined sub-folders could be created'; # XXX $PALANG['pEdit_mailbox_welcome'] = 'Muuda postkasti.'; $PALANG['pEdit_mailbox_username'] = 'Kasutajanimi'; $PALANG['pEdit_mailbox_username_error'] = 'Postkasti muutmine ebaõnnestus!'; $PALANG['pEdit_mailbox_password'] = 'Uus parool'; $PALANG['pEdit_mailbox_password2'] = 'Uus parool (uuesti)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Sisestatud paroolid ei kattu!'; $PALANG['pEdit_mailbox_name'] = 'Nimi'; $PALANG['pEdit_mailbox_name_text'] = 'Full name'; # XXX $PALANG['pEdit_mailbox_quota'] = 'Kettaruumi piirang'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Sisestatud kettaruumi piirang on liiga kõrge!'; $PALANG['pEdit_mailbox_domain_error'] = 'Puuduvad õigused. Domeen: '; $PALANG['pEdit_mailbox_button'] = 'Muuda postkast'; $PALANG['pEdit_mailbox_result_error'] = 'Postkasti muutmine ebaõnnestus!'; $PALANG['pPassword_welcome'] = 'Muuda kasutajanime parool.'; $PALANG['pPassword_admin'] = 'Kasutajanimi'; $PALANG['pPassword_admin_text_error'] = 'KASUTAJANIMI pole kehtiv!'; $PALANG['pPassword_password_current'] = 'Praegune parool'; $PALANG['pPassword_password_current_text_error'] = 'Praegust parooli ei sisestatud!'; $PALANG['pPassword_password'] = 'Uus parool'; $PALANG['pPassword_password2'] = 'Uus parool (uuesti)'; $PALANG['pPassword_password_text_error'] = 'Sisestatud paroolid ei kattu!
Või on tühjad!
'; $PALANG['pPassword_button'] = 'Muuda parool'; $PALANG['pPassword_result_error'] = 'Parooli muutmine ebaõnnestus!'; $PALANG['pPassword_result_success'] = 'Parool on muudetud!'; $PALANG['pEdit_vacation_set'] = 'Change / Set away message'; # XXX $PALANG['pEdit_vacation_remove'] = 'Remove away message'; # XXX $PALANG['pVacation_result_error'] = 'Unable to update auto response settings!'; # XXX $PALANG['pVacation_result_removed'] = 'Auto response has been removed!'; # XXX $PALANG['pVacation_result_added'] = 'Auto response has been enabled!'; # XXX $PALANG['pViewlog_welcome'] = 'Vaata 10 viimast muudatust domeeniga '; $PALANG['pViewlog_timestamp'] = 'Ajatempel'; $PALANG['pViewlog_username'] = 'Haldaja'; $PALANG['pViewlog_domain'] = 'Domeen'; $PALANG['pViewlog_action'] = 'Toiming'; $PALANG['pViewlog_data'] = 'Andmed'; $PALANG['pViewlog_action_create_mailbox'] = 'create mailbox'; # XXX $PALANG['pViewlog_action_delete_mailbox'] = 'delete mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox'] = 'edit mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox_state'] = 'edit mailbox active'; # XXX $PALANG['pViewlog_action_create_alias'] = 'create alias'; # XXX $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'delete alias'; # XXX $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'edit alias'; # XXX $PALANG['pViewlog_action_edit_alias_state'] = 'edit alias active'; # XXX $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'change password'; # XXX $PALANG['pViewlog_button'] = 'Mine'; $PALANG['pViewlog_result_error'] = 'Logi ei leitud!'; $PALANG['pSendmail_welcome'] = 'Saada kiri.'; $PALANG['pSendmail_admin'] = 'Kellelt'; $PALANG['pSendmail_to'] = 'Kellele'; $PALANG['pSendmail_to_text_error'] = 'Kellele on tühi või ei sisalda kehtivat aadressi!'; $PALANG['pSendmail_subject'] = 'Teema'; $PALANG['pSendmail_subject_text'] = 'Tere tulemast'; $PALANG['pSendmail_body'] = 'Põhitekst'; $PALANG['pSendmail_button'] = 'Saada teade'; $PALANG['pSendmail_result_error'] = 'Postkasti loomine ebaõnnestus!'; # XXX text change - new: Unable to send email! $PALANG['pSendmail_result_success'] = 'Postkast on loodud!'; # XXX text change - new: Email sent! $PALANG['pAdminMenu_list_admin'] = 'Haldajad'; $PALANG['pAdminMenu_list_domain'] = 'Domeenid'; $PALANG['pAdminMenu_list_virtual'] = 'Aliased'; $PALANG['pAdminMenu_viewlog'] = 'Vaata logi'; $PALANG['pAdminMenu_backup'] = 'Varukoopia'; $PALANG['pAdminMenu_create_domain_admins'] = 'Domeeni haldajad'; $PALANG['pAdminMenu_create_admin'] = 'Lisa haldaja'; $PALANG['pAdminMenu_create_domain'] = 'Lisa domeen'; $PALANG['pAdminMenu_create_alias'] = 'Lisa alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Lisa postkast'; $PALANG['pAdminList_admin_domain'] = 'Domeen'; $PALANG['pAdminList_admin_username'] = 'Haldaja'; $PALANG['pAdminList_admin_count'] = 'Domeene'; $PALANG['pAdminList_admin_modified'] = 'Viimati muudetud'; $PALANG['pAdminList_admin_active'] = 'Aktiivne'; $PALANG['pAdminList_domain_domain'] = 'Domeen'; $PALANG['pAdminList_domain_description'] = 'Kirjeldus'; $PALANG['pAdminList_domain_aliases'] = 'Aliased'; $PALANG['pAdminList_domain_mailboxes'] = 'Postkastid'; $PALANG['pAdminList_domain_maxquota'] = 'Maksimaalne kettaruumi piirang (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; $PALANG['pAdminList_domain_modified'] = 'Viimati muudetud'; $PALANG['pAdminList_domain_active'] = 'Aktiivne'; $PALANG['pAdminList_virtual_button'] = 'Mine'; $PALANG['pAdminList_virtual_welcome'] = 'Ülevaade domeenist: '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Aliasi'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Postkaste'; $PALANG['pAdminList_virtual_alias_address'] = 'Kellelt'; $PALANG['pAdminList_virtual_alias_goto'] = 'Kellele'; $PALANG['pAdminList_virtual_alias_modified'] = 'Viimati muudetud'; $PALANG['pAdminList_virtual_mailbox_username'] = 'E-posti aadress'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Nimi'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Kettaruumi piirang (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Viimati muudetud'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Aktiivne'; $PALANG['pAdminCreate_domain_welcome'] = 'Lisa uus domeen'; $PALANG['pAdminCreate_domain_domain'] = 'Domeen'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Selline domeen on juba olemas!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'The domain is invalid!'; # XXX $PALANG['pAdminCreate_domain_description'] = 'Kirjeldus'; $PALANG['pAdminCreate_domain_aliases'] = 'Aliasi'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = keelatud | 0 = piiramatult'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Postkaste'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = keelatud | 0 = piiramatult'; $PALANG['pAdminCreate_domain_maxquota'] = 'Maksimaalne kettaruum'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = keelatud | 0 = piiramatult'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminCreate_domain_transport_text'] = 'Define transport'; # XXX $PALANG['pAdminCreate_domain_defaultaliases'] = 'Lisa vaikimisi aliased'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; # XXX $PALANG['pAdminCreate_domain_backupmx'] = 'E-posti server on varuserver (backup MX)'; $PALANG['pAdminCreate_domain_button'] = 'Lisa domeen'; $PALANG['pAdminCreate_domain_result_error'] = 'Domeeni lisamine ebaõnnestus!'; $PALANG['pAdminCreate_domain_result_success'] = 'Domeen on lisatud!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Unable to remove domain!'; # XXX $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = 'Redigeeri domeeni'; $PALANG['pAdminEdit_domain_domain'] = 'Domeen'; $PALANG['pAdminEdit_domain_description'] = 'Kirjeldus'; $PALANG['pAdminEdit_domain_aliases'] = 'Aliasi'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = keelatud | 0 = piiramatult'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Postkaste'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = keelatud | 0 = piiramatult'; $PALANG['pAdminEdit_domain_maxquota'] = 'Maksimaalne kettaruum'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = keelatud | 0 = piiramatult'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Kirjelda transport'; $PALANG['pAdminEdit_domain_backupmx'] = 'E-posti server on varuserver (backup MX)'; $PALANG['pAdminEdit_domain_active'] = 'Aktiivne'; $PALANG['pAdminEdit_domain_button'] = 'Muuda domeen'; $PALANG['pAdminEdit_domain_result_error'] = 'Domeeni muutmine ebaõnnestus!'; $PALANG['pAdminCreate_admin_welcome'] = 'Lisa uus domeeni haldaja'; $PALANG['pAdminCreate_admin_username'] = 'Haldaja'; $PALANG['pAdminCreate_admin_username_text'] = 'E-posti aadress'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'E-posti aadress
Väljal haldaja pole kehtiv e-posti aadress!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'E-posti aadress
Selline haldaja on juba olemas'; $PALANG['pAdminCreate_admin_password'] = 'Parool'; $PALANG['pAdminCreate_admin_password2'] = 'Parool (uuesti)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Sisestatud paroolid ei kattu!
Või on tühjad!
'; $PALANG['pAdminCreate_admin_button'] = 'Lisa haldaja'; $PALANG['pAdminCreate_admin_result_error'] = 'Haldaja lisamine ebaõnnestus!'; $PALANG['pAdminCreate_admin_result_success'] = 'Haldaja on lisatud!'; $PALANG['pAdminCreate_admin_address'] = 'Domeen'; $PALANG['pAdminEdit_admin_welcome'] = 'Muuda domeeni haldajat'; $PALANG['pAdminEdit_admin_username'] = 'Haldaja'; $PALANG['pAdminEdit_admin_password'] = 'Parool'; $PALANG['pAdminEdit_admin_password2'] = 'Parool (uuesti)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Sisestatud paroolid ei kattu!
Või on tühjad!
'; $PALANG['pAdminEdit_admin_active'] = 'Aktiivne'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super admin'; # XXX $PALANG['pAdminEdit_admin_button'] = 'Muuda haldaja'; $PALANG['pAdminEdit_admin_result_error'] = 'Haldaja muutmine ebaõnnestus!'; $PALANG['pAdminEdit_admin_result_success'] = 'Haldaja on muudetud!'; $PALANG['pUsersLogin_welcome'] = 'Postkasti kasutaja sisse logimine muutmaks parooli ja aliast.'; $PALANG['pUsersLogin_username'] = 'Kasutajanimi (e-posti aadress)'; $PALANG['pUsersLogin_password'] = 'Parool'; $PALANG['pUsersLogin_button'] = 'Logi sisse'; $PALANG['pUsersLogin_username_incorrect'] = 'Kasutajanimi pole õige. Veendu, et sisestatud kasutajanimi on e-posti aadress!'; $PALANG['pUsersLogin_password_incorrect'] = 'Parool pole õige!'; $PALANG['pUsersMenu_vacation'] = 'Automaatne vastus'; $PALANG['pUsersMenu_edit_alias'] = 'Muuda edasisaatmist'; $PALANG['pUsersMenu_password'] = 'Muuda parool'; $PALANG['pUsersMain_vacation'] = 'Määra "kontorist väljas" teade või automaatne vastaja e-posti aadressile.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' is ON, click \'' . $PALANG['pUsersMenu_vacation'] . '\' to ' . $PALANG['edit'] . '/remove'; # XXX $PALANG['pUsersMain_edit_alias'] = 'Muuda e-posti edasisaatmist.'; $PALANG['pUsersMain_password'] = 'Muuda praegust parooli.'; $PALANG['pUsersVacation_welcome'] = 'Automaatne vastus.'; $PALANG['pUsersVacation_welcome_text'] = 'Automaatne vastus on juba seadistatud!'; $PALANG['pUsersVacation_subject'] = 'Teema'; $PALANG['pUsersVacation_subject_text'] = 'Kontorist väljas'; $PALANG['pUsersVacation_body'] = 'Põhitekst'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << kuni . Kiireloomuliste asjade korral palun kontakteeru . I will be away from until . For urgent matters you can contact . EOM; $PALANG['pUsersVacation_button_away'] = 'Olen eemal alates'; $PALANG['pUsersVacation_button_back'] = 'Tulen tagasi'; $PALANG['pUsersVacation_result_error'] = 'Automaatse vastuse uuendamine ebaõnnestus!'; $PALANG['pUsersVacation_result_success'] = 'Automaatne vastus on eemaldatud!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'postkasti loomine'; $PALANG['pCreate_dbLog_createalias'] = 'aliase loomine'; $PALANG['pDelete_dbLog_deletealias'] = 'aliase ksututamine'; $PALANG['pDelete_dbLog_deletemailbox'] = 'postkasti kustutamine'; $PALANG['pEdit_dbLog_editactive'] = 'aktiivne staatuse muutmine'; $PALANG['pEdit_dbLog_editalias'] = 'aliase redigeerimine'; $PALANG['pEdit_dbLog_editmailbox'] = 'postkasti redigeerimine'; $PALANG['pSearch'] = 'otsi'; $PALANG['pSearch_welcome'] = 'Otsi: '; $PALANG['pReturn_to'] = 'Return to'; # XXX $PALANG['pBroadcast_title'] = 'Send broadcast message'; # XXX $PALANG['pBroadcast_from'] = 'From'; # XXX $PALANG['pBroadcast_name'] = 'Your name'; # XXX $PALANG['pBroadcast_subject'] = 'Subject'; # XXX $PALANG['pBroadcast_message'] = 'Message'; # XXX $PALANG['pBroadcast_send'] = 'Send message'; # XXX $PALANG['pBroadcast_success'] = 'Your broadcast message was sent.'; # XXX $PALANG['pAdminMenu_broadcast_message'] = 'Broadcast message'; # XXX $PALANG['pBroadcast_error_empty'] = 'The fields Name, Subject and Message should\'t be empty !'; # XXX $PALANG['pStatus_undeliverable'] = 'maybe UNDELIVERABLE '; # XXX $PALANG['pStatus_custom'] = 'Delivers to '; # XXX $PALANG['pStatus_popimap'] = 'POP/IMAP '; # XXX $PALANG['pPasswordTooShort'] = "Password is too short - requires %s characters"; # XXX $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Fetch mail for:'; # XXX $PALANG['pFetchmail_new_entry'] = 'New entry'; # XXX $PALANG['pFetchmail_database_save_error'] = 'Could not save this entry in the database!'; # XXX $PALANG['pFetchmail_database_save_success'] = 'Entry saved in database.'; # XXX $PALANG['pFetchmail_error_invalid_id'] = 'No entry with ID %s found!'; # XXX $PALANG['pFetchmail_invalid_mailbox'] = 'Invalid mailbox!'; # XXX $PALANG['pFetchmail_server_missing'] = 'Please enter the remote server name!'; # XXX $PALANG['pFetchmail_user_missing'] = 'Please enter the remote username!'; # XXX $PALANG['pFetchmail_password_missing'] = 'Please enter the remote password!'; # XXX $PALANG['pFetchmail_field_id'] = 'ID'; # XXX $PALANG['pFetchmail_field_mailbox'] = 'Mailbox'; # XXX $PALANG['pFetchmail_field_src_server'] = 'Server'; # XXX $PALANG['pFetchmail_field_src_auth'] = 'Auth Type'; # XXX $PALANG['pFetchmail_field_src_user'] = 'User'; # XXX $PALANG['pFetchmail_field_src_password'] = 'Password'; # XXX $PALANG['pFetchmail_field_src_folder'] = 'Folder'; # XXX $PALANG['pFetchmail_field_poll_time'] = 'Poll'; # XXX $PALANG['pFetchmail_field_fetchall'] = 'Fetch All'; # XXX $PALANG['pFetchmail_field_keep'] = 'Keep'; # XXX $PALANG['pFetchmail_field_protocol'] = 'Protocol'; # XXX $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra Options'; # XXX $PALANG['pFetchmail_field_mda'] = 'MDA'; # XXX $PALANG['pFetchmail_field_date'] = 'Date'; # XXX $PALANG['pFetchmail_field_returned_text'] = 'Returned Text'; # XXX $PALANG['pFetchmail_desc_id'] = 'Record ID'; # XXX $PALANG['pFetchmail_desc_mailbox'] = 'Local mailbox'; # XXX $PALANG['pFetchmail_desc_src_server'] = 'Remote Server'; # XXX $PALANG['pFetchmail_desc_src_auth'] = 'Mostly \'password\''; # Translators: Please do NOT translate 'password' here # XXX $PALANG['pFetchmail_desc_src_user'] = 'Remote User'; # XXX $PALANG['pFetchmail_desc_src_password'] = 'Remote Password'; # XXX $PALANG['pFetchmail_desc_src_folder'] = 'Remote Folder'; # XXX $PALANG['pFetchmail_desc_poll_time'] = 'Poll every ... minutes'; # XXX $PALANG['pFetchmail_desc_fetchall'] = 'Retrieve both old (seen) and new messages'; # XXX $PALANG['pFetchmail_desc_keep'] = 'Keep retrieved messages on the remote mailserver'; # XXX $PALANG['pFetchmail_desc_protocol'] = 'Protocol to use'; # XXX $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Extra fetchmail Options'; # XXX $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; # XXX $PALANG['pFetchmail_desc_date'] = 'Date of last polling/configuration change'; # XXX $PALANG['pFetchmail_desc_returned_text'] = 'Text message from last polling'; # XXX $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/es.lang0000664000175000017620000006533211636730120017507 0ustar davidpalepurpleImposible borrar el registro '; $PALANG['pDelete_delete_success'] = '%s borrado.'; $PALANG['pDelete_postdelete_error'] = 'No se pudo eliminar el buzón '; $PALANG['pDelete_domain_error'] = 'Este dominio no le pertenece '; $PALANG['pDelete_domain_alias_error'] = 'Este dominio no te pertenece '; $PALANG['pDelete_alias_error'] = 'No se pudo eliminar el alias '; $PALANG['pCreate_alias_domain_welcome'] = 'Sincronizar direcciones de un dominio a otro.'; $PALANG['pCreate_alias_domain_alias'] = 'Alias de Dominio'; $PALANG['pCreate_alias_domain_alias_text'] = 'El dominio al que llega el email.'; $PALANG['pCreate_alias_domain_target'] = 'Dominio de destino'; $PALANG['pCreate_alias_domain_target_text'] = 'El dominio al que deberían ir los emails.'; $PALANG['pCreate_alias_domain_active'] = 'Activo'; $PALANG['pCreate_alias_domain_button'] = 'Añadir Alias de Dominio'; $PALANG['pCreate_alias_domain_error1'] = 'No estás autorizado a crear la configuración que has elegido.'; $PALANG['pCreate_alias_domain_error2'] = '¡La configuración seleccionada no es válida, por favor elige una diferente!'; $PALANG['pCreate_alias_domain_error3'] = 'Falló la inserción en la base de datos.'; $PALANG['pCreate_alias_domain_error4'] = 'Ya están todos los dominios asignados.'; $PALANG['pCreate_alias_domain_success'] = '¡El alias de dominio se insertó en la tabla!'; $PALANG['pCreate_alias_welcome'] = 'Crear un nuevo alias para el dominio.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
¡El ALIAS no es válido!'; $PALANG['pCreate_alias_address_text_error2'] = '
¡Esta dirección ya existe, elija otra diferente por favor!'; $PALANG['pCreate_alias_address_text_error3'] = '
¡Ha llegado a su límite de creación de alias!'; $PALANG['pCreate_alias_goto'] = 'Destino'; $PALANG['pCreate_alias_active'] = 'Activo'; $PALANG['pCreate_alias_button'] = 'Añadir alias'; $PALANG['pCreate_alias_goto_text'] = 'A donde debe de ser enviado el e-mail.'; $PALANG['pCreate_alias_goto_text_error'] = 'A donde debe de ser enviado el e-mail.
¡El PARA no es válido!'; $PALANG['pCreate_alias_result_error'] = '¡No es posible añadir el alias a la tabla de alias!'; $PALANG['pCreate_alias_result_success'] = '¡El alias ha sido añadido a la tabla de alias!'; $PALANG['pCreate_alias_catchall_text'] = 'Para crear un alias general use "*" como alias.
Para una redirección de dominio a dominio, use "*@domain.tld" como Destino.'; $PALANG['pEdit_alias_welcome'] = 'Edite un alias para su dominio.
Una entrada por línea.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = '¡Imposible de localizar el alias!'; $PALANG['pEdit_alias_goto'] = 'Destino'; $PALANG['pEdit_alias_active'] = 'Activo'; $PALANG['pEdit_alias_goto_text_error1'] = 'No ha introducido nada en el destino'; $PALANG['pEdit_alias_goto_text_error2'] = 'La dirección de e-mail introducida no es válida: '; $PALANG['pEdit_alias_domain_error'] = 'Este dominio no le pertenece: '; $PALANG['pEdit_alias_domain_result_error'] = '¡No se pudo modificar el alias de dominio!'; $PALANG['pEdit_alias_forward_and_store'] = 'Entregar al buzón local.'; $PALANG['pEdit_alias_forward_only'] = 'Reenviar sólo al email especificado.'; $PALANG['pEdit_alias_button'] = 'Editar alias'; $PALANG['pEdit_alias_result_error'] = '¡Imposible modificar el alias!'; $PALANG['pCreate_mailbox_welcome'] = 'Crear un nuevo buzón para su dominio.'; $PALANG['pCreate_mailbox_username'] = 'Usuario'; $PALANG['pCreate_mailbox_username_text_error1'] = '
¡El e-mail no es válido!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
¡Este e-mail ya existe, escoja uno diferente por favor!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
¡Ha llegado al límite de creación de buzones!'; $PALANG['pCreate_mailbox_password'] = 'Contraseña'; $PALANG['pCreate_mailbox_password2'] = 'Contraseña (repetir)'; $PALANG['pCreate_mailbox_password_text'] = 'Contraseña para POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Contraseña para POP3/IMAP
¡Las contraseñas introducidas no coinciden
o están en blanco!
'; $PALANG['pCreate_mailbox_name'] = 'Nombre'; $PALANG['pCreate_mailbox_name_text'] = 'Nombre completo'; $PALANG['pCreate_mailbox_quota'] = 'Cuota'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
¡La cuota especificada es demasiado alta!'; $PALANG['pCreate_mailbox_active'] = 'Activo'; $PALANG['pCreate_mailbox_mail'] = 'Crear buzón'; $PALANG['pCreate_mailbox_button'] = 'Añadir buzón'; $PALANG['pCreate_mailbox_result_error'] = '¡Imposible añadir un buzón a la tabla de buzones!'; $PALANG['pCreate_mailbox_result_success'] = '¡El buzón ha sido añadido a la tabla de buzones!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'The mailbox has been added to the mailbox table, but none (or only some) of the predefined sub-folders could be created'; # XXX $PALANG['pEdit_mailbox_welcome'] = 'Editar un buzón para su dominio.'; $PALANG['pEdit_mailbox_username'] = 'Usuario'; $PALANG['pEdit_mailbox_username_error'] = '¡Imposible localizar el buzón!'; $PALANG['pEdit_mailbox_password'] = 'Nueva contraseña'; $PALANG['pEdit_mailbox_password2'] = 'Nueva contraseña (repetir)'; $PALANG['pEdit_mailbox_password_text_error'] = '¡Las contraseñas introducidas no coinciden!'; $PALANG['pEdit_mailbox_name'] = 'Nombre'; $PALANG['pEdit_mailbox_name_text'] = 'Full name'; # XXX $PALANG['pEdit_mailbox_quota'] = 'Cuota'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
¡La cuota especificada es demasiado alta!'; $PALANG['pEdit_mailbox_domain_error'] = 'Este dominio no le pertenece: '; $PALANG['pEdit_mailbox_button'] = 'Editar buzón'; $PALANG['pEdit_mailbox_result_error'] = '¡Imposible cambiar la contraseña!'; $PALANG['pPassword_welcome'] = 'Cambie su contraseña de login.'; $PALANG['pPassword_admin'] = 'Login'; $PALANG['pPassword_admin_text_error'] = '¡El LOGIN suministrado no coincide con ningún buzón!'; $PALANG['pPassword_password_current'] = 'Contraseña actual'; $PALANG['pPassword_password_current_text_error'] = '¡No ha introducido la contraseña actual!'; $PALANG['pPassword_password'] = 'Nueva contraseña'; $PALANG['pPassword_password2'] = 'Nueva contraseña (repetir)'; $PALANG['pPassword_password_text_error'] = '¡Las contraseñas introducidas no coinciden
o están en blanco!
'; $PALANG['pPassword_button'] = 'Cambiar contraseña'; $PALANG['pPassword_result_error'] = '¡Imposible cambiar la contraseña!'; $PALANG['pPassword_result_success'] = '¡Su contraseña ha sido cambiada!'; $PALANG['pEdit_vacation_set'] = 'Cambiar / Establecer mensaje de ausencia'; $PALANG['pEdit_vacation_remove'] = 'Quitar mensaje de ausencia'; $PALANG['pVacation_result_error'] = '¡Imposible actualizar la configuracióne la respuesta automática!'; $PALANG['pVacation_result_removed'] = '¡Autorespuesta eliminada!'; $PALANG['pVacation_result_added'] = '¡Autorespuesta habilitada!'; $PALANG['pViewlog_welcome'] = 'Ver las últimas 10 acciones para '; $PALANG['pViewlog_timestamp'] = 'Fecha/Hora'; $PALANG['pViewlog_username'] = 'Administrador'; $PALANG['pViewlog_domain'] = 'Dominio'; $PALANG['pViewlog_action'] = 'Acción'; $PALANG['pViewlog_data'] = 'Datos'; $PALANG['pViewlog_action_create_mailbox'] = 'crear buzón'; $PALANG['pViewlog_action_delete_mailbox'] = 'borrar buzón'; $PALANG['pViewlog_action_edit_mailbox'] = 'editar buzón'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'editar buzón activo'; $PALANG['pViewlog_action_create_alias'] = 'crear alias'; $PALANG['pViewlog_action_create_alias_domain'] = 'crear alias de dominio'; $PALANG['pViewlog_action_delete_alias'] = 'borrar alias'; $PALANG['pViewlog_action_delete_alias_domain'] = 'borrar alias de dominio'; $PALANG['pViewlog_action_edit_alias'] = 'editar alias'; $PALANG['pViewlog_action_edit_alias_state'] = 'editar alias activo'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'editar alias de dominio activo'; $PALANG['pViewlog_action_edit_password'] = 'cambiar contraseña'; $PALANG['pViewlog_button'] = 'Ir'; $PALANG['pViewlog_result_error'] = '¡Imposible encontrar los logs!'; $PALANG['pSendmail_welcome'] = 'Enviar un e-mail.'; $PALANG['pSendmail_admin'] = 'De'; $PALANG['pSendmail_to'] = 'Destino'; $PALANG['pSendmail_to_text_error'] = '¡La dirección destino está vacía o es una dirección inválida!'; $PALANG['pSendmail_subject'] = 'Asunto'; $PALANG['pSendmail_subject_text'] = 'Bienvenido'; $PALANG['pSendmail_body'] = 'Cuerpo'; $PALANG['pSendmail_button'] = 'Enviar mensaje'; $PALANG['pSendmail_result_error'] = '¡Imposible enviar el email!'; $PALANG['pSendmail_result_success'] = '¡Email enviado!'; $PALANG['pAdminMenu_list_admin'] = 'Lista de administradores'; $PALANG['pAdminMenu_list_domain'] = 'Lista de dominios'; $PALANG['pAdminMenu_list_virtual'] = 'Lista de direcciones virtuales'; $PALANG['pAdminMenu_viewlog'] = 'Ver Logs'; $PALANG['pAdminMenu_backup'] = 'Backup'; $PALANG['pAdminMenu_create_domain_admins'] = 'Administradores de dominio'; $PALANG['pAdminMenu_create_admin'] = 'Nuevo administrador'; $PALANG['pAdminMenu_create_domain'] = 'Nuevo dominio'; $PALANG['pAdminMenu_create_alias'] = 'Añadir alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Añadir buzón'; $PALANG['pAdminList_admin_domain'] = 'Dominio'; $PALANG['pAdminList_admin_username'] = 'Administrador'; $PALANG['pAdminList_admin_count'] = 'Dominios'; $PALANG['pAdminList_admin_modified'] = 'Última Modificación'; $PALANG['pAdminList_admin_active'] = 'Activo'; $PALANG['pAdminList_domain_domain'] = 'Dominio'; $PALANG['pAdminList_domain_description'] = 'Descripción'; $PALANG['pAdminList_domain_aliases'] = 'Alias'; $PALANG['pAdminList_domain_mailboxes'] = 'Buzones'; $PALANG['pAdminList_domain_maxquota'] = 'Cuota Máxima (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transporte'; $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; # XXX $PALANG['pAdminList_domain_modified'] = 'Última Modificación'; $PALANG['pAdminList_domain_active'] = 'Activo'; $PALANG['pAdminList_virtual_button'] = 'Ir'; $PALANG['pAdminList_virtual_welcome'] = 'Resumen de '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Alias'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Buzones'; $PALANG['pAdminList_virtual_alias_address'] = 'De'; $PALANG['pAdminList_virtual_alias_goto'] = 'Destino'; $PALANG['pAdminList_virtual_alias_modified'] = 'Última Modificación'; $PALANG['pAdminList_virtual_mailbox_username'] = 'E-mail'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Nombre'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Cuota (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Última Modificación'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Activo'; $PALANG['pAdminCreate_domain_welcome'] = 'Añadir nuevo dominio'; $PALANG['pAdminCreate_domain_domain'] = 'Dominio'; $PALANG['pAdminCreate_domain_domain_text_error'] = '¡El dominio ya existe!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = '!El dominio no es válido!'; $PALANG['pAdminCreate_domain_description'] = 'Descripción'; $PALANG['pAdminCreate_domain_aliases'] = 'Alias'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = deshabilitar | 0 = ilimitado'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Buzones'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = deshabilitar | 0 = ilimitado'; $PALANG['pAdminCreate_domain_maxquota'] = 'Cuota máxima'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = deshabilitar | 0 = ilimitado'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminCreate_domain_transport_text'] = 'Definir transport'; # XXX $PALANG['pAdminCreate_domain_defaultaliases'] = 'Añadir alias por defecto'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'El servidor de correo es backup MX'; # XXX $PALANG['pAdminCreate_domain_button'] = 'Añadir dominio'; $PALANG['pAdminCreate_domain_result_error'] = '¡Imposible añadir el dominio!'; $PALANG['pAdminCreate_domain_result_success'] = '¡El dominio ha sido añadido!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = '¡No se pudo eliminar el dominio!'; $PALANG['pAdminDelete_alias_domain_error'] = '¡No se pudo eliminar el alias de dominio!'; $PALANG['pAdminEdit_domain_welcome'] = 'Editar un dominio'; $PALANG['pAdminEdit_domain_domain'] = 'Dominio'; $PALANG['pAdminEdit_domain_description'] = 'Descripción'; $PALANG['pAdminEdit_domain_aliases'] = 'Alias'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = deshabilitar | 0 = ilimitado'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Buzones'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = deshabilitar | 0 = ilimitado'; $PALANG['pAdminEdit_domain_maxquota'] = 'Cuota máxima'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = deshabilitar | 0 = ilimitado'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Definir transport'; # XXX $PALANG['pAdminEdit_domain_backupmx'] = 'El servidor de correo es backup MX'; # XXX $PALANG['pAdminEdit_domain_active'] = 'Activo'; $PALANG['pAdminEdit_domain_button'] = 'Editar dominio'; $PALANG['pAdminEdit_domain_result_error'] = '¡Imposible modificar el dominio!'; $PALANG['pAdminCreate_admin_welcome'] = 'Añadir un nuevo administrador de dominio'; $PALANG['pAdminCreate_admin_username'] = 'Administrador'; $PALANG['pAdminCreate_admin_username_text'] = 'E-mail'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'E-mail
Administrador no es un e-mail válido!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'E-mail
El administrador ya existe o no es válido!'; $PALANG['pAdminCreate_admin_password'] = 'Contraseña'; $PALANG['pAdminCreate_admin_password2'] = 'Contraseña (repetir)'; $PALANG['pAdminCreate_admin_password_text_error'] = '¡Las contraseñas introducidas no coinciden
o están en blanco!
'; $PALANG['pAdminCreate_admin_button'] = 'Añadir administrador'; $PALANG['pAdminCreate_admin_result_error'] = '¡Imposible añadir el administrador!'; $PALANG['pAdminCreate_admin_result_success'] = '¡El administrador ha sido añadido!'; $PALANG['pAdminCreate_admin_address'] = 'Dominio'; $PALANG['pAdminEdit_admin_welcome'] = 'Editar un administrador de dominio'; $PALANG['pAdminEdit_admin_username'] = 'Administrador'; $PALANG['pAdminEdit_admin_password'] = 'Contraseña'; $PALANG['pAdminEdit_admin_password2'] = 'Contraseña (repetir)'; $PALANG['pAdminEdit_admin_password_text_error'] = '¡Las contraseñas introducidas no coinciden
o están en blanco!
'; $PALANG['pAdminEdit_admin_active'] = 'Activo'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super admin'; # XXX $PALANG['pAdminEdit_admin_button'] = 'Editar administrador'; $PALANG['pAdminEdit_admin_result_error'] = '¡Imposible modificar el administrador!'; $PALANG['pAdminEdit_admin_result_success'] = '¡El administrador ha sido modificado!'; $PALANG['pUsersLogin_welcome'] = 'Login de usuarios para cambiar la contraseña y alias.'; $PALANG['pUsersLogin_username'] = 'Login (e-mail)'; $PALANG['pUsersLogin_password'] = 'Contraseña'; $PALANG['pUsersLogin_button'] = 'Login'; $PALANG['pUsersLogin_username_incorrect'] = 'Su login no es correcto. ¡Asegúrese de haber introducido su dirección de e-mail como login!'; $PALANG['pUsersLogin_password_incorrect'] = '¡Su contraseña no es correcta!'; $PALANG['pUsersMenu_vacation'] = 'Respuesta automática'; $PALANG['pUsersMenu_edit_alias'] = 'Cambiar la redirección'; $PALANG['pUsersMenu_password'] = 'Cambiar la contraseña'; $PALANG['pUsersMain_vacation'] = 'Configure un mensaje de "fuera del trabajo" o una respuesta automática para su correo.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' está ACTIVADO, click \'' . $PALANG['pUsersMenu_vacation'] . '\' para ' . $PALANG['edit'] . '/eliminar'; $PALANG['pUsersMain_edit_alias'] = 'Cambie su redirección de correo.'; $PALANG['pUsersMain_password'] = 'Cambie su contraseña.'; $PALANG['pUsersVacation_welcome'] = 'Respuesta automática.'; $PALANG['pUsersVacation_welcome_text'] = '¡Ya dispone de una respuesta automática configurada!'; $PALANG['pUsersVacation_subject'] = 'Asunto'; $PALANG['pUsersVacation_subject_text'] = 'Fuera del trabajo'; $PALANG['pUsersVacation_body'] = 'Mensaje'; $PALANG['pUsersVacation_body_text'] = << hasta . Para asuntos urgentes, puede contactar conmigo en . EOM; $PALANG['pUsersVacation_button_away'] = 'Ausente'; $PALANG['pUsersVacation_button_back'] = 'De vuelta'; $PALANG['pUsersVacation_result_error'] = '¡Imposible actualizar la configuración de su respuesta automática!'; $PALANG['pUsersVacation_result_success'] = '¡Su respuesta automática ha sido borrada!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'crear buzón'; $PALANG['pCreate_dbLog_createalias'] = 'crear alias'; $PALANG['pDelete_dbLog_deletealias'] = 'borrar alias'; $PALANG['pDelete_dbLog_deletemailbox'] = 'borrar buzón'; $PALANG['pEdit_dbLog_editactive'] = 'cambiar estado activo'; $PALANG['pEdit_dbLog_editalias'] = 'editar alias'; $PALANG['pEdit_dbLog_editmailbox'] = 'editar buzón'; $PALANG['pSearch'] = 'buscar'; $PALANG['pSearch_welcome'] = 'Buscando: '; $PALANG['pReturn_to'] = 'Volver a'; $PALANG['pBroadcast_title'] = 'Enviar mensaje a todos'; # XXX $PALANG['pBroadcast_from'] = 'De'; $PALANG['pBroadcast_name'] = 'Tu nombre'; $PALANG['pBroadcast_subject'] = 'Asunto'; $PALANG['pBroadcast_message'] = 'Mensaje'; $PALANG['pBroadcast_send'] = 'Enviar mensaje'; $PALANG['pBroadcast_success'] = 'Se ha enviado el mensaje.'; $PALANG['pAdminMenu_broadcast_message'] = 'Broadcast message'; # XXX $PALANG['pBroadcast_error_empty'] = '¡Los campos Nombre, Asunto y Mensaje no pueden estar vacíos!'; $PALANG['pStatus_undeliverable'] = 'posiblemente NO SE ENTREGÓ'; $PALANG['pStatus_custom'] = 'Enviado a '; $PALANG['pStatus_popimap'] = 'POP/IMAP '; # XXX $PALANG['pPasswordTooShort'] = "La contraseña es demasiado corta - se necesitan %s caracteres"; $PALANG['pInvalidDomainRegex'] = "El nombre de dominio %s es inválido, no se ajusta a la expresión regular"; $PALANG['pInvalidDomainDNS'] = "El dominio %s no es válido, y/o no tiene resolución DNS"; $PALANG['pInvalidMailRegex'] = "La dirección de email no es válidas, no se ajusta a la expresión regular"; $PALANG['pFetchmail_welcome'] = 'Obtener mail para:'; $PALANG['pFetchmail_new_entry'] = 'Nueva entrada'; $PALANG['pFetchmail_database_save_error'] = '¡No se pudo salvar la entrada en la base de datos!'; $PALANG['pFetchmail_database_save_success'] = 'Entrada salvada en la base de datos.'; $PALANG['pFetchmail_error_invalid_id'] = 'No entry with ID %s found!'; # XXX $PALANG['pFetchmail_invalid_mailbox'] = '¡Buzón inválido!'; $PALANG['pFetchmail_server_missing'] = '¡Por favor introduzca el nombre del servidor remoto!'; $PALANG['pFetchmail_user_missing'] = '¡Por favor introduzca el usuario remoto!'; $PALANG['pFetchmail_password_missing'] = '¡Por favor introduzca la contraseña remota!'; $PALANG['pFetchmail_field_id'] = 'ID'; # XXX $PALANG['pFetchmail_field_mailbox'] = 'Buzón'; $PALANG['pFetchmail_field_src_server'] = 'Servidor'; $PALANG['pFetchmail_field_src_auth'] = 'Tipo Autenticación'; $PALANG['pFetchmail_field_src_user'] = 'Usuario'; $PALANG['pFetchmail_field_src_password'] = 'Contraseña'; $PALANG['pFetchmail_field_src_folder'] = 'Carpeta'; $PALANG['pFetchmail_field_poll_time'] = 'Poll'; # XXX $PALANG['pFetchmail_field_fetchall'] = 'Obtener todo'; $PALANG['pFetchmail_field_keep'] = 'Conservar'; $PALANG['pFetchmail_field_protocol'] = 'Protocolo'; $PALANG['pFetchmail_field_usessl'] = 'SSL activado'; $PALANG['pFetchmail_field_extra_options'] = 'Opciones extras'; $PALANG['pFetchmail_field_mda'] = 'MDA'; # XXX $PALANG['pFetchmail_field_date'] = 'Fecha'; $PALANG['pFetchmail_field_returned_text'] = 'Texto Devuelto'; $PALANG['pFetchmail_desc_id'] = 'Record ID'; # XXX $PALANG['pFetchmail_desc_mailbox'] = 'Buzón local'; $PALANG['pFetchmail_desc_src_server'] = 'Servidor Remoto'; $PALANG['pFetchmail_desc_src_auth'] = 'Mostly \'password\''; # Translators: Please do NOT translate 'password' here # XXX $PALANG['pFetchmail_desc_src_user'] = 'Usuario Remoto'; $PALANG['pFetchmail_desc_src_password'] = 'Contraseña Remota'; $PALANG['pFetchmail_desc_src_folder'] = 'Carpeta Remota'; $PALANG['pFetchmail_desc_poll_time'] = 'Obtener cada ... minutos'; $PALANG['pFetchmail_desc_fetchall'] = 'Obtener los mensajes leídos y nuevos'; $PALANG['pFetchmail_desc_keep'] = 'Guardar una copia de los mensajes en el servidor remoto'; $PALANG['pFetchmail_desc_protocol'] = 'Protocolo a usar'; $PALANG['pFetchmail_desc_usessl'] = 'Cifrado SSL'; $PALANG['pFetchmail_desc_extra_options'] = 'Opciones extras para fetchmail'; $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; # XXX $PALANG['pFetchmail_desc_date'] = 'Fecha del último sondeo/cambio en la configuración'; $PALANG['pFetchmail_desc_returned_text'] = 'Mensaje del último sondeo'; $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/index.php0000664000175000017620000000053610715711016020050 0ustar davidpalepurple // Copyright (c) 2002 - 2005 High5! // Licensed under GPL for more info check GPL-LICENSE.TXT // // File: index.php // // Template File: -none- // // Template Variables: // // -none- // // Form POST \ GET Variables: // // -none- // header ("Location: ../login.php"); exit; ?> postfixadmin-2.3.7/languages/de.lang0000664000175000017620000006607611637127400017500 0ustar davidpalepurpleEintrag konnte nicht gelöscht werden '; $PALANG['pDelete_delete_success'] = '%s gelöscht.'; $PALANG['pDelete_postdelete_error'] = 'Mailbox konnte nicht gelöscht werden '; $PALANG['pDelete_domain_error'] = 'Diese Domain gehört nicht Ihnen '; $PALANG['pDelete_domain_alias_error'] = 'Diese Domain gehört nicht Ihnen '; $PALANG['pDelete_alias_error'] = 'Alias konnte nicht gelöscht werden '; $PALANG['pCreate_alias_domain_welcome'] = 'Adressen einer Ihrer Domains auf eine andere Domain weiterleiten.'; $PALANG['pCreate_alias_domain_alias'] = 'Alias-Domain'; $PALANG['pCreate_alias_domain_alias_text'] = 'Die Domain, für die Mails hereinkommen.'; $PALANG['pCreate_alias_domain_target'] = 'Zieldomain'; $PALANG['pCreate_alias_domain_target_text'] = 'Die Domain, an die die Mails gehen sollen.'; $PALANG['pCreate_alias_domain_active'] = 'Aktiv'; $PALANG['pCreate_alias_domain_button'] = 'Alias-Domain hinzufügen'; $PALANG['pCreate_alias_domain_error1'] = 'Sie dürfen die gewählte Konfiguration nicht erstellen.'; $PALANG['pCreate_alias_domain_error2'] = 'Die gewählte Konfiguration ist ungültig, bitte wählen Sie eine andere'; $PALANG['pCreate_alias_domain_error3'] = 'Datenbank-Eintrag fehlgeschlagen.'; $PALANG['pCreate_alias_domain_error4'] = 'Alle Domains sind bereits Alias-Domains.'; $PALANG['pCreate_alias_domain_success'] = 'Die Alias-Domain wurde in der Datenbank eingetragen!'; $PALANG['pCreate_alias_welcome'] = 'Neuen Alias für Ihre Domain anlegen'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
Dieses ALIAS ist nicht erlaubt!'; $PALANG['pCreate_alias_address_text_error2'] = '
Diese eMail-Adresse existiert bereits. Bitte wählen Sie eine andere!'; $PALANG['pCreate_alias_address_text_error3'] = '
Sie haben Ihr Limit für Aliase auf dieser Domain erreicht!'; $PALANG['pCreate_alias_goto'] = 'An'; $PALANG['pCreate_alias_active'] = 'Aktiv'; $PALANG['pCreate_alias_button'] = 'Alias hinzufügen'; $PALANG['pCreate_alias_goto_text'] = 'Wohin soll die eMail weitergeleitet werden?'; $PALANG['pCreate_alias_goto_text_error'] = 'Wohin die eMail weitergeleitet werden soll
Das An-Feld ist falsch!'; $PALANG['pCreate_alias_result_error'] = 'Unmöglich dieses Alias in die Alias-Tabelle einzutragen!'; $PALANG['pCreate_alias_result_success'] = 'Das Alias wurde in die Alias-Tabelle hinzugefügt!'; $PALANG['pCreate_alias_catchall_text'] = 'Um alle Adressen abzudecken benutzen Sie einen "*" als Alias.
Um ganze Domains an andere Domains weiterzuleiten benutzen Sie "*@domain.tld" im "An"-Feld.'; $PALANG['pEdit_alias_welcome'] = 'Ändern Sie einen Alias für Ihre Domain
EIN Eintrag pro Zeile!'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Auffinden des Alias schlug fehl!'; $PALANG['pEdit_alias_goto'] = 'An'; $PALANG['pEdit_alias_active'] = 'Aktiv'; $PALANG['pEdit_alias_goto_text_error1'] = 'Sie haben im "To"-Feld nichts angegeben!'; $PALANG['pEdit_alias_goto_text_error2'] = 'Die angegebene eMail-Adresse ist nicht korrekt: '; $PALANG['pEdit_alias_domain_error'] = 'Diese Domain gehört nicht Ihnen: '; $PALANG['pEdit_alias_domain_result_error'] = 'Alias-Domain kann nicht geändert werden!'; $PALANG['pEdit_alias_forward_and_store'] = 'Mail in der lokalen Mailbox ablegen.'; $PALANG['pEdit_alias_forward_only'] = 'Nur zur angegebenen Adresse weiterleiten.'; $PALANG['pEdit_alias_button'] = 'Alias ändern'; $PALANG['pEdit_alias_result_error'] = 'Ändern des Aliases nicht möglich!'; $PALANG['pCreate_mailbox_welcome'] = 'Legen Sie eine neue Mailbox für Ihre Domain an.'; $PALANG['pCreate_mailbox_username'] = 'Benutzername'; $PALANG['pCreate_mailbox_username_text_error1'] = '
Die EMAIL ist nicht korrekt!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Diese Email-Adresse existiert bereits. Bitte wählen Sie eine andere!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Sie dürfen leider nicht mehr Mailboxen für diese Domain anlegen!'; $PALANG['pCreate_mailbox_password'] = 'Passwort'; $PALANG['pCreate_mailbox_password2'] = 'Passwort (nochmal)'; $PALANG['pCreate_mailbox_password_text'] = 'Passwort für POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Passwort für POP3/IMAP
Die beiden Passwörter sind nicht identisch!
Oder ganz leer!
'; $PALANG['pCreate_mailbox_name'] = 'Name'; $PALANG['pCreate_mailbox_name_text'] = 'Voller Name'; $PALANG['pCreate_mailbox_quota'] = 'Quota'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Das angegebene Quota ist zu hoch!'; $PALANG['pCreate_mailbox_active'] = 'Aktiv'; $PALANG['pCreate_mailbox_mail'] = 'Mailbox anlegen'; $PALANG['pCreate_mailbox_button'] = 'Mailbox hinzufügen'; $PALANG['pCreate_mailbox_result_error'] = 'Unmöglich die Mailbox in die Mailbox-Tabelle einzutragen!'; $PALANG['pCreate_mailbox_result_success'] = 'Die Mailbox wurde in die Mailbox-Tabelle eingetragen!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'Die Mailbox wurde in der Mailbox-Tabelle eingetragen, aber keine (oder nur einige) der vorkonfigurierten Unterordner konnte erstellt werden'; $PALANG['pEdit_mailbox_welcome'] = 'Ändern Sie ihre Mailbox hier.'; $PALANG['pEdit_mailbox_username'] = 'Benutzername'; $PALANG['pEdit_mailbox_username_error'] = 'Unmöglich die Mailbox aufzufinden!'; $PALANG['pEdit_mailbox_password'] = 'Neues Passwort'; $PALANG['pEdit_mailbox_password2'] = 'Neues Passwort (nochmal)'; $PALANG['pEdit_mailbox_password_text_error'] = 'Die beiden Passwörter sind nicht identisch!'; $PALANG['pEdit_mailbox_name'] = 'Name'; $PALANG['pEdit_mailbox_name_text'] = 'Vollständiger Name'; $PALANG['pEdit_mailbox_quota'] = 'Quota'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Das angegebene Quota ist zu hoch!'; $PALANG['pEdit_mailbox_domain_error'] = 'Diese Domain gehört nicht Ihnen: '; $PALANG['pEdit_mailbox_button'] = 'Mailbox editieren'; $PALANG['pEdit_mailbox_result_error'] = 'Mailbox kann nicht geändert werden!'; $PALANG['pPassword_welcome'] = 'Ändern Sie Ihr Login-Passwort.'; $PALANG['pPassword_admin'] = 'Login'; $PALANG['pPassword_admin_text_error'] = 'Das angegebene Login entspricht keiner Mailbox!'; $PALANG['pPassword_password_current'] = 'Jetziges Password'; $PALANG['pPassword_password_current_text_error'] = 'Sie haben Ihr derzeitiges Passwort nicht angegeben!'; $PALANG['pPassword_password'] = 'Neues Passwort'; $PALANG['pPassword_password2'] = 'Neues Password (nochmal)'; $PALANG['pPassword_password_text_error'] = 'Die beiden angegebenen Passwörter sind nicht identische!
Oder leer!
'; $PALANG['pPassword_button'] = 'Passwort ändern'; $PALANG['pPassword_result_error'] = 'Unmöglich das Passwort zu ändern!'; $PALANG['pPassword_result_success'] = 'Ihr Passwort wurde geändert!'; $PALANG['pEdit_vacation_set'] = 'Automatische Antwort ändern / einrichten'; $PALANG['pEdit_vacation_remove'] = 'Automatische Antwort abschalten'; $PALANG['pVacation_result_error'] = 'Änderungen der automatischen Antwort konnten nicht gespeichert werden!'; $PALANG['pVacation_result_removed'] = 'Automatische Antwort wurde abgeschaltet!'; $PALANG['pVacation_result_added'] = 'Automatische Antwort wurde aktiviert!'; $PALANG['pViewlog_welcome'] = 'Zeigt die letzten 10 Aktionen für '; $PALANG['pViewlog_timestamp'] = 'Zeitpunkt'; $PALANG['pViewlog_username'] = 'Admin'; $PALANG['pViewlog_domain'] = 'Domain'; $PALANG['pViewlog_action'] = 'Aktion'; $PALANG['pViewlog_data'] = 'Daten'; $PALANG['pViewlog_action_create_mailbox'] = 'Mailbox erstellen'; $PALANG['pViewlog_action_delete_mailbox'] = 'Mailbox löschen'; $PALANG['pViewlog_action_edit_mailbox'] = 'Mailbox bearbeiten'; $PALANG['pViewlog_action_edit_mailbox_state'] = 'Mailbox Aktiv bearbeiten'; $PALANG['pViewlog_action_create_alias'] = 'Alias erstellen'; $PALANG['pViewlog_action_create_alias_domain'] = 'Alias-Domain erstellen'; $PALANG['pViewlog_action_delete_alias'] = 'Alias löschen'; $PALANG['pViewlog_action_delete_alias_domain'] = 'Alias-Domain löschen'; $PALANG['pViewlog_action_edit_alias'] = 'Alias bearbeiten'; $PALANG['pViewlog_action_edit_alias_state'] = 'Alias Aktiv bearbeiten'; $PALANG['pViewlog_action_edit_alias_domain_state'] = 'Alias-Domain Aktiv bearbeiten'; $PALANG['pViewlog_action_edit_password'] = 'Passwort ändern'; $PALANG['pViewlog_button'] = 'Los'; $PALANG['pViewlog_result_error'] = 'Kann keine Einträge finden!'; $PALANG['pSendmail_welcome'] = 'eMail versenden.'; $PALANG['pSendmail_admin'] = 'Von'; $PALANG['pSendmail_to'] = 'An'; $PALANG['pSendmail_to_text_error'] = 'Das "An"-Feld ist leer bzw. ungültig!'; $PALANG['pSendmail_subject'] = 'Betreff'; $PALANG['pSendmail_subject_text'] = 'Willkommen'; $PALANG['pSendmail_body'] = 'Text'; $PALANG['pSendmail_button'] = 'Versende Nachricht'; $PALANG['pSendmail_result_error'] = 'Mail konnte nicht gesendet werden!'; $PALANG['pSendmail_result_success'] = 'Mail gesendet!'; $PALANG['pAdminMenu_list_admin'] = 'Admin Liste'; $PALANG['pAdminMenu_list_domain'] = 'Domain Liste'; $PALANG['pAdminMenu_list_virtual'] = 'Virtual Liste'; $PALANG['pAdminMenu_viewlog'] = 'Log ansehen'; $PALANG['pAdminMenu_backup'] = 'Sicherung'; $PALANG['pAdminMenu_create_domain_admins'] = 'Domain Admins'; $PALANG['pAdminMenu_create_admin'] = 'Neuer Admin'; $PALANG['pAdminMenu_create_domain'] = 'Neue Domain'; $PALANG['pAdminMenu_create_alias'] = 'Alias hinzufügen'; $PALANG['pAdminMenu_create_mailbox'] = 'Mailbox hinzufügen'; $PALANG['pAdminList_admin_domain'] = 'Domain'; $PALANG['pAdminList_admin_username'] = 'Admin'; $PALANG['pAdminList_admin_count'] = 'Domains'; $PALANG['pAdminList_admin_modified'] = 'zuletzt geändert'; $PALANG['pAdminList_admin_active'] = 'Aktiv'; $PALANG['pAdminList_domain_domain'] = 'Domain'; $PALANG['pAdminList_domain_description'] = 'Beschreibung'; $PALANG['pAdminList_domain_aliases'] = 'Aliase'; $PALANG['pAdminList_domain_mailboxes'] = 'Mailboxen'; $PALANG['pAdminList_domain_maxquota'] = 'Max Quota (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; $PALANG['pAdminList_domain_modified'] = 'zuletzt geändert'; $PALANG['pAdminList_domain_active'] = 'Aktiv'; $PALANG['pAdminList_virtual_button'] = 'Los'; $PALANG['pAdminList_virtual_welcome'] = 'Überblick für '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Aliase'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Mailboxen'; $PALANG['pAdminList_virtual_alias_address'] = 'Von'; $PALANG['pAdminList_virtual_alias_goto'] = 'An'; $PALANG['pAdminList_virtual_alias_modified'] = 'zuletzt geändert'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Email'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Name'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Quota (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'zuletzt geändert'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Aktiv'; $PALANG['pAdminCreate_domain_welcome'] = 'Domain hinzufügen'; $PALANG['pAdminCreate_domain_domain'] = 'Domain'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Diese Domain existiert bereits!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'Diese Domain ist ungültig!'; $PALANG['pAdminCreate_domain_description'] = 'Beschreibung'; $PALANG['pAdminCreate_domain_aliases'] = 'Aliase'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = ausschalten | 0 = kein Limit'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Mailboxen'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = ausschalten | 0 = kein Limit'; $PALANG['pAdminCreate_domain_maxquota'] = 'Max Quota'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = ausschalten | 0 = kein Limit'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; $PALANG['pAdminCreate_domain_transport_text'] = 'Define transport'; $PALANG['pAdminCreate_domain_defaultaliases'] = 'Standard-Aliase hinzufügen'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; $PALANG['pAdminCreate_domain_backupmx'] = 'Mail server is backup MX'; $PALANG['pAdminCreate_domain_button'] = 'Domain hinzufügen'; $PALANG['pAdminCreate_domain_result_error'] = 'Konnte Domain nicht anlegen!'; $PALANG['pAdminCreate_domain_result_success'] = 'Domain wurde angelegt!'; $PALANG['pAdminDelete_admin_error'] = 'Admin kann nicht gelöscht werden!'; $PALANG['pAdminDelete_domain_error'] = 'Domain konnte nicht gelöscht werden!'; $PALANG['pAdminDelete_alias_domain_error'] = 'Alias-Domain konnte nicht gelöscht werden!'; $PALANG['pAdminEdit_domain_welcome'] = 'Domain editieren'; $PALANG['pAdminEdit_domain_domain'] = 'Domain'; $PALANG['pAdminEdit_domain_description'] = 'Beschreibung'; $PALANG['pAdminEdit_domain_aliases'] = 'Aliase'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = ausschalten | 0 = kein Limit'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Mailboxen'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = ausschalten | 0 = kein Limit'; $PALANG['pAdminEdit_domain_maxquota'] = 'Max Quota'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = ausschalten | 0 = kein Limit'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; $PALANG['pAdminEdit_domain_transport_text'] = 'Define transport'; $PALANG['pAdminEdit_domain_backupmx'] = 'Mail server is backup MX'; $PALANG['pAdminEdit_domain_active'] = 'Aktiv'; $PALANG['pAdminEdit_domain_button'] = 'Domain editieren'; $PALANG['pAdminEdit_domain_result_error'] = 'Konnte Domain nicht editieren!'; $PALANG['pAdminCreate_admin_welcome'] = 'Neuen Domain-Admin hinzufügen'; $PALANG['pAdminCreate_admin_username'] = 'Admin'; $PALANG['pAdminCreate_admin_username_text'] = 'Email Adresse'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Email Adresse
Admin-Adresse ist keine echte Email-Adresse!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Email Adresse
Der Admin existiert bereits bzw. ist nicht korrekt'; $PALANG['pAdminCreate_admin_password'] = 'Passwort'; $PALANG['pAdminCreate_admin_password2'] = 'Passwort (nochmal)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Die angegebenen Passwörter sind nicht identisch
Oder leer!
'; $PALANG['pAdminCreate_admin_button'] = 'Admin hinzufügen'; $PALANG['pAdminCreate_admin_result_error'] = 'Konnte den Admin nicht anlegen!'; $PALANG['pAdminCreate_admin_result_success'] = 'Admin angelegt!'; $PALANG['pAdminCreate_admin_address'] = 'Domain'; $PALANG['pAdminEdit_admin_welcome'] = 'Domain Admin editieren'; $PALANG['pAdminEdit_admin_username'] = 'Admin'; $PALANG['pAdminEdit_admin_password'] = 'Passwort'; $PALANG['pAdminEdit_admin_password2'] = 'Passwort (nochmal)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Die beiden Passwörter sind nicht identisch
Oder leer!
'; $PALANG['pAdminEdit_admin_active'] = 'Aktiv'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super-Admin'; $PALANG['pAdminEdit_admin_button'] = 'Admin editieren'; $PALANG['pAdminEdit_admin_result_error'] = 'Konnte Admin nicht ändern'; $PALANG['pAdminEdit_admin_result_success'] = 'Admin geändert!'; $PALANG['pUsersLogin_welcome'] = 'Benutzer bitte hier einloggen, um Weiterleitungen bzw. das Passwort zu ändern.'; $PALANG['pUsersLogin_username'] = 'Login (email)'; $PALANG['pUsersLogin_password'] = 'Passwort'; $PALANG['pUsersLogin_button'] = 'Login'; $PALANG['pUsersLogin_username_incorrect'] = 'Falscher Login! Bitte benutzen Sie ihre Email-Adresse als Login'; $PALANG['pUsersLogin_password_incorrect'] = 'Falsches Passwort!'; $PALANG['pUsersMenu_vacation'] = 'Automatische Antwort'; $PALANG['pUsersMenu_edit_alias'] = 'Weiterleitung ändern'; $PALANG['pUsersMenu_password'] = 'Passwort ändern'; $PALANG['pUsersMain_vacation'] = 'Geben Sie eine "Automatische Antwort" ein. Sinnvoll z.B. während Sie im Urlaub sind'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' ist aktiv, \'' . $PALANG['pUsersMenu_vacation'] . '\' anklicken zum Bearbeiten oder Abschalten'; $PALANG['pUsersMain_edit_alias'] = 'Ändern Sie Ihre Weiterleitung.'; $PALANG['pUsersMain_password'] = 'Ändern Sie Ihr Passwort.'; $PALANG['pUsersVacation_welcome'] = 'Automatische Antwort.'; $PALANG['pUsersVacation_welcome_text'] = 'Sie haben schon eine Automatische Antwort konfiguriert!'; $PALANG['pUsersVacation_subject'] = 'Betreff'; $PALANG['pUsersVacation_subject_text'] = 'Ich bin weg...'; $PALANG['pUsersVacation_body'] = 'Nachricht'; $PALANG['pUsersVacation_body_text'] = << bis nicht zu Hause / im Büro. In dringenden Fällen setzen Sie sich bitte mit in Verbindung. Vielen Dank für Ihr Verständnis. EOM; $PALANG['pUsersVacation_button_away'] = 'Ich gehe weg'; $PALANG['pUsersVacation_button_back'] = 'Ich bin zurück'; $PALANG['pUsersVacation_result_error'] = 'Konnte Ihre Automatische Antwort nicht einstellen!'; $PALANG['pUsersVacation_result_success'] = 'Ihre Automatische Antwort wurde gelöscht!'; $PALANG['pUsersVacation_activefrom'] = 'Aktiv ab dem'; $PALANG['pUsersVacation_activeuntil'] = 'Aktiv bis zum'; $PALANG['pCreate_dbLog_createmailbox'] = 'Mailbox hinzufügen'; $PALANG['pCreate_dbLog_createalias'] = 'Alias hinzufügen'; $PALANG['pDelete_dbLog_deletealias'] = 'Alias lüschen'; $PALANG['pDelete_dbLog_deletemailbox'] = 'Mailbox löschen'; $PALANG['pEdit_dbLog_editactive'] = 'Aktiv-Status ändern'; $PALANG['pEdit_dbLog_editalias'] = 'Alias bearbeiten'; $PALANG['pEdit_dbLog_editmailbox'] = 'Mailbox bearbeiten'; $PALANG['pSearch'] = 'suche'; $PALANG['pSearch_welcome'] = 'Suche nach: '; $PALANG['pReturn_to'] = 'Zurück zu'; $PALANG['pBroadcast_title'] = 'Rundmail senden'; $PALANG['pBroadcast_from'] = 'Von'; $PALANG['pBroadcast_name'] = 'Ihr Name'; $PALANG['pBroadcast_subject'] = 'Betreff'; $PALANG['pBroadcast_message'] = 'Nachricht'; $PALANG['pBroadcast_send'] = 'Nachricht senden'; $PALANG['pBroadcast_success'] = 'Ihre Rundmail wurde gesendet.'; $PALANG['pAdminMenu_broadcast_message'] = 'Rundmail'; $PALANG['pBroadcast_error_empty'] = 'Die Felder Name, Betreff und Nachricht dürfen nicht leer sein!'; $PALANG['pStatus_undeliverable'] = 'möglicherweise UNZUSTELLBAR '; $PALANG['pStatus_custom'] = 'Zustellung an '; $PALANG['pStatus_popimap'] = 'POP/IMAP '; $PALANG['pPasswordTooShort'] = "Das Passwort ist zu kurz - mindestens %s Zeichen benötigt"; $PALANG['pInvalidDomainRegex'] = "Ungültiger Domainname %s - Überprüfung per RegEx fehlgeschlagen"; $PALANG['pInvalidDomainDNS'] = "Ungültige Domain %s - nicht per DNS auflösbar"; $PALANG['pInvalidMailRegex'] = "Ungültige Mailadresse - Überprüfung per RegEx fehlgeschlagen"; $PALANG['pFetchmail_welcome'] = 'E-Mail Abruf für: '; $PALANG['pFetchmail_new_entry'] = 'Neuer Eintrag'; $PALANG['pFetchmail_database_save_error'] = 'Eintrag konnte nicht in der Datenbank gespeichert werden!'; $PALANG['pFetchmail_database_save_success'] = 'Eintrag wurde in der Datenbank gespeichert'; $PALANG['pFetchmail_error_invalid_id'] = 'Kein Eintrag mit ID %s gefunden!'; $PALANG['pFetchmail_invalid_mailbox'] = 'Ungültiges Postfach!'; $PALANG['pFetchmail_server_missing'] = 'Bitte geben Sie den Namen des Servers ein!'; $PALANG['pFetchmail_user_missing'] = 'Bitte geben Sie den Benutzernamen ein!'; $PALANG['pFetchmail_password_missing'] = 'Bitte geben Sie das Passwort ein!'; $PALANG['pFetchmail_field_id'] = 'ID'; $PALANG['pFetchmail_field_mailbox'] = 'Mailbox'; $PALANG['pFetchmail_field_src_server'] = 'Server'; $PALANG['pFetchmail_field_src_auth'] = 'Anmeldemethode'; $PALANG['pFetchmail_field_src_user'] = 'Benutzername'; $PALANG['pFetchmail_field_src_password'] = 'Passwort'; $PALANG['pFetchmail_field_src_folder'] = 'Ordner'; $PALANG['pFetchmail_field_poll_time'] = 'Abruf'; $PALANG['pFetchmail_field_fetchall'] = 'Alle abholen'; $PALANG['pFetchmail_field_keep'] = 'Behalten'; $PALANG['pFetchmail_field_protocol'] = 'Protokoll'; $PALANG['pFetchmail_field_usessl'] = 'SSL aktiv'; $PALANG['pFetchmail_field_extra_options'] = 'Zusätzliche Optionen'; $PALANG['pFetchmail_field_mda'] = 'MDA'; $PALANG['pFetchmail_field_date'] = 'Datum'; $PALANG['pFetchmail_field_returned_text'] = 'Zurückgegebener Text'; $PALANG['pFetchmail_desc_id'] = 'Eintrags-ID'; $PALANG['pFetchmail_desc_mailbox'] = 'Lokales Postfach'; $PALANG['pFetchmail_desc_src_server'] = 'Entfernter Server'; $PALANG['pFetchmail_desc_src_auth'] = 'Normalerweise \'password\''; $PALANG['pFetchmail_desc_src_user'] = 'Entfernter Benutzername'; $PALANG['pFetchmail_desc_src_password'] = 'Entferntes Passwort'; $PALANG['pFetchmail_desc_src_folder'] = 'Entfernter Ordner'; $PALANG['pFetchmail_desc_poll_time'] = 'Mailabruf alle ... Minuten'; $PALANG['pFetchmail_desc_fetchall'] = 'Sowohl alte (gelesene) als auch neue Nachrichten abholen'; $PALANG['pFetchmail_desc_keep'] = 'Abgeholte Nachrichten auf dem entfernten Server lassen'; $PALANG['pFetchmail_desc_protocol'] = 'Zu verwendendes Protokoll'; $PALANG['pFetchmail_desc_usessl'] = 'Verschlüsselung mit SSL'; $PALANG['pFetchmail_desc_extra_options'] = 'Zusätzliche fetchmail-Optionen'; $PALANG['pFetchmail_desc_mda'] = 'Programm zur Mailauslieferung'; $PALANG['pFetchmail_desc_date'] = 'Datum des letzten Mailabrufs/Konfigurationsänderung'; $PALANG['pFetchmail_desc_returned_text'] = 'Textausgabe des letzten Mailabrufs'; $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/languages/is.lang0000664000175000017620000006640211636730120017512 0ustar davidpalepurpleGet ekki eytt færslunni '; $PALANG['pDelete_delete_success'] = '%s deleted.'; # XXX $PALANG['pDelete_postdelete_error'] = 'Unable to remove mailbox '; # XXX $PALANG['pDelete_domain_error'] = 'Þetta er ekki þitt lén '; $PALANG['pDelete_domain_alias_error'] = 'This domain is not yours '; # XXX $PALANG['pDelete_alias_error'] = 'Unable to delete alias '; # XXX $PALANG['pCreate_alias_domain_welcome'] = 'Mirror addresses of one of your domains to another.'; # XXX $PALANG['pCreate_alias_domain_alias'] = 'Alias Domain'; # XXX $PALANG['pCreate_alias_domain_alias_text'] = 'The domain that mails come in for.'; # XXX $PALANG['pCreate_alias_domain_target'] = 'Target Domain'; # XXX $PALANG['pCreate_alias_domain_target_text'] = 'The domain where mails should go to.'; # XXX $PALANG['pCreate_alias_domain_active'] = 'Active'; # XXX $PALANG['pCreate_alias_domain_button'] = 'Add Alias Domain'; # XXX $PALANG['pCreate_alias_domain_error1'] = 'You are not allowed to create the chosen configuration.'; # XXX $PALANG['pCreate_alias_domain_error2'] = 'The chosen configuration is invalid, please choose a different one!'; # XXX $PALANG['pCreate_alias_domain_error3'] = 'Database insert failed.'; # XXX $PALANG['pCreate_alias_domain_error4'] = 'All domains are already aliased.'; # XXX $PALANG['pCreate_alias_domain_success'] = 'The domain alias has been added to the alias domain table!'; # XXX $PALANG['pCreate_alias_welcome'] = 'Útbúa nýjan alias fyrir þitt lén.'; $PALANG['pCreate_alias_address'] = 'Alias'; $PALANG['pCreate_alias_address_text_error1'] = '
Aliasinn er ekki í lagi!'; $PALANG['pCreate_alias_address_text_error2'] = '
Þetta pósthólf er nú þegar til, veldu annað!'; $PALANG['pCreate_alias_address_text_error3'] = '
Þú hefur stofnað þann fjölda pósthólfa sem þú hefur heimild til!'; $PALANG['pCreate_alias_goto'] = 'Til'; $PALANG['pCreate_alias_active'] = 'Active'; # XXX $PALANG['pCreate_alias_button'] = 'Bæta við alias'; $PALANG['pCreate_alias_goto_text'] = 'Þangað sem pósturinn á að sendast.'; $PALANG['pCreate_alias_goto_text_error'] = 'Þangað sem pósturinn þarf að sendast.
Til línan er ekki gild!'; $PALANG['pCreate_alias_result_error'] = 'Get ekki bætt við alias í alias töflu!'; $PALANG['pCreate_alias_result_success'] = 'Nýr alias hefur verið bætt við alias töfluna!'; $PALANG['pCreate_alias_catchall_text'] = 'Til að útbúa alias fyrir öll netföng í léninu, þá geturðu útbúið "*" alias.
Til að áframsenda með alias á annað lén eða pósthólf, notaðu "*@domain.tld í til.'; $PALANG['pEdit_alias_welcome'] = 'Breyta alias í léninu.
Ein færsla í einu.'; $PALANG['pEdit_alias_address'] = 'Alias'; $PALANG['pEdit_alias_address_error'] = 'Get ekki fundið aliasinn!'; $PALANG['pEdit_alias_goto'] = 'To'; $PALANG['pEdit_alias_active'] = 'Active'; # XXX $PALANG['pEdit_alias_goto_text_error1'] = 'þú gafst ekki upp neitt í Til'; $PALANG['pEdit_alias_goto_text_error2'] = 'Pósthólfið sem þú reynir að nota er ekki til: '; $PALANG['pEdit_alias_domain_error'] = 'Þú átt ekki þetta lén: '; $PALANG['pEdit_alias_domain_result_error'] = 'Unable to modify the alias domain!'; # XXX $PALANG['pEdit_alias_forward_and_store'] = 'Deliver to the local mailbox.'; # XXX $PALANG['pEdit_alias_forward_only'] = 'Forward to given email addresses only.'; # XXX $PALANG['pEdit_alias_button'] = 'Breyta Alias'; $PALANG['pEdit_alias_result_error'] = 'Get ekki breytt alias!'; $PALANG['pCreate_mailbox_welcome'] = 'Create a new local mailbox for your domain.'; # XXX $PALANG['pCreate_mailbox_username'] = 'notandanafn'; $PALANG['pCreate_mailbox_username_text_error1'] = '
Netfangið er ekki til!'; $PALANG['pCreate_mailbox_username_text_error2'] = '
Þetta pósthólf er til núþegar, veldu þér annað!'; $PALANG['pCreate_mailbox_username_text_error3'] = '
Þú hefur stofnað þau póstholf sem þú hefur heimild til!'; $PALANG['pCreate_mailbox_password'] = 'Lykilorð'; $PALANG['pCreate_mailbox_password2'] = 'Lykilorð (aftur)'; $PALANG['pCreate_mailbox_password_text'] = 'Lykilorð til að opna POP3/IMAP'; $PALANG['pCreate_mailbox_password_text_error'] = 'Lykilorð fyrir POP3/IMAP
Lykilorðin sem þú skrifaðir inn passa ekki saman!
Eða þú gafst ekkert lykilorð upp!
'; $PALANG['pCreate_mailbox_name'] = 'Nafn'; $PALANG['pCreate_mailbox_name_text'] = 'Fullt nafn'; $PALANG['pCreate_mailbox_quota'] = 'kvóti'; $PALANG['pCreate_mailbox_quota_text'] = 'MB'; $PALANG['pCreate_mailbox_quota_text_error'] = 'MB
Kvótinn sem þú skilgreindir er meiri en heimild þín gefur!'; $PALANG['pCreate_mailbox_active'] = 'Virkur'; $PALANG['pCreate_mailbox_mail'] = 'Stofna pósthólf'; $PALANG['pCreate_mailbox_button'] = 'bæta við pósthólfi'; $PALANG['pCreate_mailbox_result_error'] = 'Get ekki bætt við pósthólfi í mailbox töfluna!'; $PALANG['pCreate_mailbox_result_success'] = 'Pósthólfinu hefur verið bætt við mailbox töfluna!'; $PALANG['pCreate_mailbox_result_succes_nosubfolders'] = 'The mailbox has been added to the mailbox table, but none (or only some) of the predefined sub-folders could be created'; # XXX $PALANG['pEdit_mailbox_welcome'] = 'Breyta pósthólfi i léninu þínu.'; $PALANG['pEdit_mailbox_username'] = 'Auðkenni'; $PALANG['pEdit_mailbox_username_error'] = 'Finn ekki pósthólfið!'; $PALANG['pEdit_mailbox_password'] = 'Nýtt lykilorð'; $PALANG['pEdit_mailbox_password2'] = 'Nýja lykilorðið aftur'; $PALANG['pEdit_mailbox_password_text_error'] = 'Lykilorðið sem þú skrifaðir inn passar ekki saman!'; $PALANG['pEdit_mailbox_name'] = 'Nafn'; $PALANG['pEdit_mailbox_name_text'] = 'Full name'; # XXX $PALANG['pEdit_mailbox_quota'] = 'kvóti'; $PALANG['pEdit_mailbox_quota_text'] = 'MB'; $PALANG['pEdit_mailbox_quota_text_error'] = 'MB
Kvótinn sem þú skilgreindir er of hár fyrir heimildina þína!'; $PALANG['pEdit_mailbox_domain_error'] = 'Þetta lén er ekki á þínum vegum: '; $PALANG['pEdit_mailbox_button'] = 'Breyta pósthólfi'; $PALANG['pEdit_mailbox_result_error'] = 'Get ekki breytt lykilorðinu!'; $PALANG['pPassword_welcome'] = 'Breyta auðkenninu þínu til að tengjast.'; $PALANG['pPassword_admin'] = 'Tengjast'; $PALANG['pPassword_admin_text_error'] = 'Auðkennið sem þú gafst upp, passar ekki við pósthólfið!'; $PALANG['pPassword_password_current'] = 'gamla lykilorðið'; $PALANG['pPassword_password_current_text_error'] = 'Þú gafst ekki upp núverandi lykilorð þitt!'; $PALANG['pPassword_password'] = 'Nýtt lykilorð'; $PALANG['pPassword_password2'] = 'Nýtt lykilorð (aftur)'; $PALANG['pPassword_password_text_error'] = 'Lykilorðin sem þú gafst upp passa ekki saman!
Eða þú gefur upp tómt lykilorð!
'; $PALANG['pPassword_button'] = 'Breyta lykilorði'; $PALANG['pPassword_result_error'] = 'Get ekki breytt lykilorði!'; $PALANG['pPassword_result_success'] = 'Lykilorðinu hefur verið breytt!'; $PALANG['pEdit_vacation_set'] = 'Change / Set away message'; # XXX $PALANG['pEdit_vacation_remove'] = 'Remove away message'; # XXX $PALANG['pVacation_result_error'] = 'Unable to update auto response settings!'; # XXX $PALANG['pVacation_result_removed'] = 'Auto response has been removed!'; # XXX $PALANG['pVacation_result_added'] = 'Auto response has been enabled!'; # XXX $PALANG['pViewlog_welcome'] = 'Skoða síðustu 10 aðgerðir fyrir '; $PALANG['pViewlog_timestamp'] = 'Tími'; $PALANG['pViewlog_username'] = 'kerfisstjóri'; $PALANG['pViewlog_domain'] = 'lén'; $PALANG['pViewlog_action'] = 'aðgerð'; $PALANG['pViewlog_data'] = 'gögn'; $PALANG['pViewlog_action_create_mailbox'] = 'create mailbox'; # XXX $PALANG['pViewlog_action_delete_mailbox'] = 'delete mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox'] = 'edit mailbox'; # XXX $PALANG['pViewlog_action_edit_mailbox_state'] = 'edit mailbox active'; # XXX $PALANG['pViewlog_action_create_alias'] = 'create alias'; # XXX $PALANG['pViewlog_action_create_alias_domain'] = 'create alias domain'; # XXX $PALANG['pViewlog_action_delete_alias'] = 'delete alias'; # XXX $PALANG['pViewlog_action_delete_alias_domain'] = 'delete alias domain'; # XXX $PALANG['pViewlog_action_edit_alias'] = 'edit alias'; # XXX $PALANG['pViewlog_action_edit_alias_state'] = 'edit alias active'; # XXX $PALANG['pViewlog_action_edit_alias_domain_state'] = 'edit alias domain active'; # XXX $PALANG['pViewlog_action_edit_password'] = 'change password'; # XXX $PALANG['pViewlog_button'] = 'Áfram'; $PALANG['pViewlog_result_error'] = 'Get ekki fundið log skráningu!'; $PALANG['pSendmail_welcome'] = 'sendu tölvupóst.'; $PALANG['pSendmail_admin'] = 'frá'; $PALANG['pSendmail_to'] = 'til'; $PALANG['pSendmail_to_text_error'] = 'til er tómt eða ekki uppgefið gilt netfang!'; $PALANG['pSendmail_subject'] = 'Efni bréfs'; $PALANG['pSendmail_subject_text'] = 'Velkomin'; $PALANG['pSendmail_body'] = 'Meginmál'; $PALANG['pSendmail_button'] = 'Senda skilaboð'; $PALANG['pSendmail_result_error'] = 'Get ekki búið til nýtt pósthólf!'; # XXX text change - new: Unable to send email! $PALANG['pSendmail_result_success'] = 'Pósthólfið hefur verið stofnað!'; # XXX text change - new: Email sent! $PALANG['pAdminMenu_list_admin'] = 'Kerfisstjóralisti'; $PALANG['pAdminMenu_list_domain'] = 'Lénalisti'; $PALANG['pAdminMenu_list_virtual'] = 'Virtual Listi'; $PALANG['pAdminMenu_viewlog'] = 'Skoða Log'; $PALANG['pAdminMenu_backup'] = 'Afritun'; $PALANG['pAdminMenu_create_domain_admins'] = 'Lén kerfisstjórar'; $PALANG['pAdminMenu_create_admin'] = 'Nýr kerfisstjóri'; $PALANG['pAdminMenu_create_domain'] = 'Nýtt lén'; $PALANG['pAdminMenu_create_alias'] = 'Bæta við alias'; $PALANG['pAdminMenu_create_mailbox'] = 'Bæta við pósthólfi'; $PALANG['pAdminList_admin_domain'] = 'Lén'; $PALANG['pAdminList_admin_username'] = 'Notandi'; $PALANG['pAdminList_admin_count'] = 'Lén'; $PALANG['pAdminList_admin_modified'] = 'Síðast breytt'; $PALANG['pAdminList_admin_active'] = 'Virkt'; $PALANG['pAdminList_domain_domain'] = 'Lén'; $PALANG['pAdminList_domain_description'] = 'Lýsing'; $PALANG['pAdminList_domain_aliases'] = 'Aliasar'; $PALANG['pAdminList_domain_mailboxes'] = 'Póstbox'; $PALANG['pAdminList_domain_maxquota'] = 'Hám. kvóti (MB)'; $PALANG['pAdminList_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminList_domain_backupmx'] = 'Backup MX'; # XXX $PALANG['pAdminList_domain_modified'] = 'Síðast breytt'; $PALANG['pAdminList_domain_active'] = 'Virkt'; $PALANG['pAdminList_virtual_button'] = 'Áfram'; $PALANG['pAdminList_virtual_welcome'] = 'Yfirlit fyrir '; $PALANG['pAdminList_virtual_alias_alias_count'] = 'Aliasar'; $PALANG['pAdminList_virtual_alias_mailbox_count'] = 'Póstbox'; $PALANG['pAdminList_virtual_alias_address'] = 'Frá'; $PALANG['pAdminList_virtual_alias_goto'] = 'Til'; $PALANG['pAdminList_virtual_alias_modified'] = 'Síðast breytt'; $PALANG['pAdminList_virtual_mailbox_username'] = 'Email'; $PALANG['pAdminList_virtual_mailbox_name'] = 'Nafn'; $PALANG['pAdminList_virtual_mailbox_quota'] = 'Kvóti (MB)'; $PALANG['pAdminList_virtual_mailbox_modified'] = 'Síðast breytt'; $PALANG['pAdminList_virtual_mailbox_active'] = 'Virkt'; $PALANG['pAdminCreate_domain_welcome'] = 'Bæta við léni'; $PALANG['pAdminCreate_domain_domain'] = 'Lén'; $PALANG['pAdminCreate_domain_domain_text_error'] = 'Lénið er til nú þegar!'; $PALANG['pAdminCreate_domain_domain_text_error2'] = 'The domain is invalid!'; # XXX $PALANG['pAdminCreate_domain_description'] = 'Lýsing'; $PALANG['pAdminCreate_domain_aliases'] = 'Aliasar'; $PALANG['pAdminCreate_domain_aliases_text'] = '-1 = óvirkt | 0 = ótakmarkað'; $PALANG['pAdminCreate_domain_mailboxes'] = 'Póstbox'; $PALANG['pAdminCreate_domain_mailboxes_text'] = '-1 = óvirkt | 0 = ótakmarkað'; $PALANG['pAdminCreate_domain_maxquota'] = 'Hámarks kvóti'; $PALANG['pAdminCreate_domain_maxquota_text'] = 'MB
-1 = óvirkt | 0 = ótakmarkað'; $PALANG['pAdminCreate_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminCreate_domain_transport_text'] = 'Define transport'; # XXX $PALANG['pAdminCreate_domain_defaultaliases'] = 'Setja sjálfgefinn póstalias'; $PALANG['pAdminCreate_domain_defaultaliases_text'] = ''; # XXX $PALANG['pAdminCreate_domain_backupmx'] = 'Mail server is backup MX'; $PALANG['pAdminCreate_domain_button'] = 'Bæta við léni'; $PALANG['pAdminCreate_domain_result_error'] = 'Get ekki bætt við léni!'; $PALANG['pAdminCreate_domain_result_success'] = 'Lén hefur verið bætt inn!'; $PALANG['pAdminDelete_admin_error'] = 'Unable to delete admin!'; # XXX $PALANG['pAdminDelete_domain_error'] = 'Unable to remove domain!'; # XXX $PALANG['pAdminDelete_alias_domain_error'] = 'Unable to remove domain alias!'; # XXX $PALANG['pAdminEdit_domain_welcome'] = 'Breyta léni'; $PALANG['pAdminEdit_domain_domain'] = 'Lén'; $PALANG['pAdminEdit_domain_description'] = 'Lýsing'; $PALANG['pAdminEdit_domain_aliases'] = 'Aliasar'; $PALANG['pAdminEdit_domain_aliases_text'] = '-1 = óvirkt | 0 = ótakmarkað'; $PALANG['pAdminEdit_domain_mailboxes'] = 'Póstbox'; $PALANG['pAdminEdit_domain_mailboxes_text'] = '-1 = óvirkt | 0 = ótakmarkað'; $PALANG['pAdminEdit_domain_maxquota'] = 'Hámarks kvóti'; $PALANG['pAdminEdit_domain_maxquota_text'] = 'MB
-1 = óvirkt | 0 = ótakmarkað'; $PALANG['pAdminEdit_domain_transport'] = 'Transport'; # XXX $PALANG['pAdminEdit_domain_transport_text'] = 'Define transport'; # XXX $PALANG['pAdminEdit_domain_backupmx'] = 'Mail server is backup MX'; # XXX $PALANG['pAdminEdit_domain_active'] = 'Virkt'; $PALANG['pAdminEdit_domain_button'] = 'Breyta léni'; $PALANG['pAdminEdit_domain_result_error'] = 'Get ekki breytt léni!'; $PALANG['pAdminCreate_admin_welcome'] = 'Bæta nýju léni við'; $PALANG['pAdminCreate_admin_username'] = 'Kerfisstjóri'; $PALANG['pAdminCreate_admin_username_text'] = 'Póstfang'; $PALANG['pAdminCreate_admin_username_text_error1'] = 'Póstfang
Kerfisstjóri er ekki rétt póstfang!'; $PALANG['pAdminCreate_admin_username_text_error2'] = 'Póstfang
Kerfisstjóri er til nú þegar eða er ekki leyfilegt'; $PALANG['pAdminCreate_admin_password'] = 'Lykilorð'; $PALANG['pAdminCreate_admin_password2'] = 'Lykilorð (aftur)'; $PALANG['pAdminCreate_admin_password_text_error'] = 'Lykilorðið sem þú gafst upp passar ekki!
Eða var tómt!
'; $PALANG['pAdminCreate_admin_button'] = 'Bæta við kerfisstjóra'; $PALANG['pAdminCreate_admin_result_error'] = 'Get ekki bætt við kerfisstjóra!'; $PALANG['pAdminCreate_admin_result_success'] = 'Kerfisstjórinn hefur verið skráður!'; $PALANG['pAdminCreate_admin_address'] = 'Lén'; $PALANG['pAdminEdit_admin_welcome'] = 'Breyta kerfisstjóra léns'; $PALANG['pAdminEdit_admin_username'] = 'Kerfisstjóri'; $PALANG['pAdminEdit_admin_password'] = 'Lykilorð'; $PALANG['pAdminEdit_admin_password2'] = 'Lykilorð (aftur)'; $PALANG['pAdminEdit_admin_password_text_error'] = 'Lykilorðið sem þú gafst upp passar ekki!
Eða var tómt!
'; $PALANG['pAdminEdit_admin_active'] = 'Virkt'; $PALANG['pAdminEdit_admin_super_admin'] = 'Super admin'; # XXX $PALANG['pAdminEdit_admin_button'] = 'Breyta kerfisstjóra'; $PALANG['pAdminEdit_admin_result_error'] = 'Get ekki breytt kerfisstjóra!'; $PALANG['pAdminEdit_admin_result_success'] = 'Kerfisstjórinn hefur verið breyttur!'; $PALANG['pUsersLogin_welcome'] = 'Pósthólf notenda til að tengjast svo hægt er að breyta lykilorði eða alias.'; $PALANG['pUsersLogin_username'] = 'Innskrá (email)'; $PALANG['pUsersLogin_password'] = 'Lykilorð'; $PALANG['pUsersLogin_button'] = 'Innskrá'; $PALANG['pUsersLogin_username_incorrect'] = 'Innskráning þín er röng, gaktu úr skugga um að þú tengist með réttu póstfangi (email address)!'; $PALANG['pUsersLogin_password_incorrect'] = 'Lykilorð þitt er rangt!'; $PALANG['pUsersMenu_vacation'] = 'Sjálfvirk svörun'; $PALANG['pUsersMenu_edit_alias'] = 'Breyta áframsendingu'; $PALANG['pUsersMenu_password'] = 'Breyta lykilorði'; $PALANG['pUsersMain_vacation'] = 'Setja "er ekki við" skilaboð sem sjálfvikt svörun í pósthólfið þitt.'; $PALANG['pUsersMain_vacationSet'] = $PALANG['pUsersMenu_vacation'] . ' is ON, click \'' . $PALANG['pUsersMenu_vacation'] . '\' to ' . $PALANG['edit'] . '/remove'; # XXX $PALANG['pUsersMain_edit_alias'] = 'Breyta áframsendingu póstfangs. (email forward).'; # XXX $PALANG['pUsersMain_password'] = 'Breyta núverandi lykilorði.'; $PALANG['pUsersVacation_welcome'] = 'sjálfvirk skilaboð.'; $PALANG['pUsersVacation_welcome_text'] = 'Þú hefur nú þegar skilgreint sjálfvirk skilaboð!'; $PALANG['pUsersVacation_subject'] = 'Meginmál - Subject'; $PALANG['pUsersVacation_subject_text'] = 'Er ekki við - Out of Office'; $PALANG['pUsersVacation_body'] = 'Meginmál'; # XXX text changed to 'Message' $PALANG['pUsersVacation_body_text'] = << og til . I will be away from until . Ef mikið liggur við, geturðu haft samaband við . For urgent matters you can contact . EOM; $PALANG['pUsersVacation_button_away'] = 'Verð í burtu'; $PALANG['pUsersVacation_button_back'] = 'Kem aftur'; $PALANG['pUsersVacation_result_error'] = 'Get ekki uppfært sjálfvirk skilaboð þín!'; $PALANG['pUsersVacation_result_success'] = 'Sjálfvirk skilaboð þín (svar) hefur verið fjarlægt!'; $PALANG['pUsersVacation_activefrom'] = 'Active from'; # XXX $PALANG['pUsersVacation_activeuntil'] = 'Active until'; # XXX $PALANG['pCreate_dbLog_createmailbox'] = 'create mailbox'; # XXX $PALANG['pCreate_dbLog_createalias'] = 'create alias'; # XXX $PALANG['pDelete_dbLog_deletealias'] = 'delete alias'; # XXX $PALANG['pDelete_dbLog_deletemailbox'] = 'delete mailbox'; # XXX $PALANG['pEdit_dbLog_editactive'] = 'change active state'; # XXX $PALANG['pEdit_dbLog_editalias'] = 'edit alias'; # XXX $PALANG['pEdit_dbLog_editmailbox'] = 'edit mailbox'; # XXX $PALANG['pSearch'] = 'search'; # XXX $PALANG['pSearch_welcome'] = 'Searching for: '; # XXX $PALANG['pReturn_to'] = 'Return to'; # XXX $PALANG['pBroadcast_title'] = 'Send broadcast message'; # XXX $PALANG['pBroadcast_from'] = 'From'; # XXX $PALANG['pBroadcast_name'] = 'Your name'; # XXX $PALANG['pBroadcast_subject'] = 'Subject'; # XXX $PALANG['pBroadcast_message'] = 'Message'; # XXX $PALANG['pBroadcast_send'] = 'Send message'; # XXX $PALANG['pBroadcast_success'] = 'Your broadcast message was sent.'; # XXX $PALANG['pAdminMenu_broadcast_message'] = 'Broadcast message'; # XXX $PALANG['pBroadcast_error_empty'] = 'The fields Name, Subject and Message should\'t be empty !'; # XXX $PALANG['pStatus_undeliverable'] = 'maybe UNDELIVERABLE '; # XXX $PALANG['pStatus_custom'] = 'Delivers to '; # XXX $PALANG['pStatus_popimap'] = 'POP/IMAP '; # XXX $PALANG['pPasswordTooShort'] = "Password is too short - requires %s characters"; # XXX $PALANG['pInvalidDomainRegex'] = "Invalid domain name %s, fails regexp check"; # XXX $PALANG['pInvalidDomainDNS'] = "Invalid domain %s, and/or not discoverable in DNS"; # XXX $PALANG['pInvalidMailRegex'] = "Invalid email address, fails regexp check"; # XXX $PALANG['pFetchmail_welcome'] = 'Fetch mail for:'; # XXX $PALANG['pFetchmail_new_entry'] = 'New entry'; # XXX $PALANG['pFetchmail_database_save_error'] = 'Could not save this entry in the database!'; # XXX $PALANG['pFetchmail_database_save_success'] = 'Entry saved in database.'; # XXX $PALANG['pFetchmail_error_invalid_id'] = 'No entry with ID %s found!'; # XXX $PALANG['pFetchmail_invalid_mailbox'] = 'Invalid mailbox!'; # XXX $PALANG['pFetchmail_server_missing'] = 'Please enter the remote server name!'; # XXX $PALANG['pFetchmail_user_missing'] = 'Please enter the remote username!'; # XXX $PALANG['pFetchmail_password_missing'] = 'Please enter the remote password!'; # XXX $PALANG['pFetchmail_field_id'] = 'ID'; # XXX $PALANG['pFetchmail_field_mailbox'] = 'Mailbox'; # XXX $PALANG['pFetchmail_field_src_server'] = 'Server'; # XXX $PALANG['pFetchmail_field_src_auth'] = 'Auth Type'; # XXX $PALANG['pFetchmail_field_src_user'] = 'User'; # XXX $PALANG['pFetchmail_field_src_password'] = 'Password'; # XXX $PALANG['pFetchmail_field_src_folder'] = 'Folder'; # XXX $PALANG['pFetchmail_field_poll_time'] = 'Poll'; # XXX $PALANG['pFetchmail_field_fetchall'] = 'Fetch All'; # XXX $PALANG['pFetchmail_field_keep'] = 'Keep'; # XXX $PALANG['pFetchmail_field_protocol'] = 'Protocol'; # XXX $PALANG['pFetchmail_field_usessl'] = 'SSL active'; # XXX $PALANG['pFetchmail_field_extra_options'] = 'Extra Options'; # XXX $PALANG['pFetchmail_field_mda'] = 'MDA'; # XXX $PALANG['pFetchmail_field_date'] = 'Date'; # XXX $PALANG['pFetchmail_field_returned_text'] = 'Returned Text'; # XXX $PALANG['pFetchmail_desc_id'] = 'Record ID'; # XXX $PALANG['pFetchmail_desc_mailbox'] = 'Local mailbox'; # XXX $PALANG['pFetchmail_desc_src_server'] = 'Remote Server'; # XXX $PALANG['pFetchmail_desc_src_auth'] = 'Mostly \'password\''; # Translators: Please do NOT translate 'password' here # XXX $PALANG['pFetchmail_desc_src_user'] = 'Remote User'; # XXX $PALANG['pFetchmail_desc_src_password'] = 'Remote Password'; # XXX $PALANG['pFetchmail_desc_src_folder'] = 'Remote Folder'; # XXX $PALANG['pFetchmail_desc_poll_time'] = 'Poll every ... minutes'; # XXX $PALANG['pFetchmail_desc_fetchall'] = 'Retrieve both old (seen) and new messages'; # XXX $PALANG['pFetchmail_desc_keep'] = 'Keep retrieved messages on the remote mailserver'; # XXX $PALANG['pFetchmail_desc_protocol'] = 'Protocol to use'; # XXX $PALANG['pFetchmail_desc_usessl'] = 'SSL encryption'; # XXX $PALANG['pFetchmail_desc_extra_options'] = 'Extra fetchmail Options'; # XXX $PALANG['pFetchmail_desc_mda'] = 'Mail Delivery Agent'; # XXX $PALANG['pFetchmail_desc_date'] = 'Date of last polling/configuration change'; # XXX $PALANG['pFetchmail_desc_returned_text'] = 'Text message from last polling'; # XXX $PALANG['please_keep_this_as_last_entry'] = ''; # needed for language-check.sh /* vim: set expandtab ft=php softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/create-admin.php0000664000175000017620000000357110724535105017331 0ustar davidpalepurple postfixadmin-2.3.7/functions.inc.php0000664000175000017620000021266412301121426017553 0ustar davidpalepurple'; foreach($supported_languages as $lang => $lang_name) { if ($lang == $current_lang) { $selected = ' selected="selected"'; } else { $selected = ''; } $selector .= ""; } $selector .= ""; return $selector; } // // check_string // Action: checks if a string is valid and returns TRUE if this is the case. // Call: check_string (string var) // function check_string ($var) { if (preg_match ('/^([A-Za-z0-9 ]+)+$/', $var)) { return true; } else { return false; } } // // check_domain // Action: Checks if domain is valid and returns TRUE if this is the case. // Call: check_domain (string domain) // // TODO: make check_domain able to handle as example .local domains function check_domain ($domain) { global $CONF; global $PALANG; if (!preg_match ('/^([-0-9A-Z]+\.)+' . '([0-9A-Z]){2,13}$/i', ($domain))) { flash_error(sprintf($PALANG['pInvalidDomainRegex'], htmlentities($domain))); return false; } if (isset($CONF['emailcheck_resolve_domain']) && 'YES' == $CONF['emailcheck_resolve_domain'] && 'WINDOWS'!=(strtoupper(substr(php_uname('s'), 0, 7)))) { // Look for an AAAA, A, or MX record for the domain if(function_exists('checkdnsrr')) { // AAAA (IPv6) is only available in PHP v. >= 5 if (version_compare(phpversion(), "5.0.0", ">=")) { if (checkdnsrr($domain,'AAAA')) return true; } if (checkdnsrr($domain,'A')) return true; if (checkdnsrr($domain,'MX')) return true; flash_error(sprintf($PALANG['pInvalidDomainDNS'], htmlentities($domain))); return false; } else { flash_error("emailcheck_resolve_domain is enabled, but function (checkdnsrr) missing!"); } } return true; } /** * check_email * Checks if an email is valid - if it is, return true, else false. * @param String $email - a string that may be an email address. * @return boolean true if it's an email address, else false. * TODO: make check_email able to handle already added domains */ function check_email ($email) { global $CONF; global $PALANG; $ce_email=$email; //strip the vacation domain out if we are using it //and change from blah#foo.com@autoreply.foo.com to blah@foo.com if ($CONF['vacation'] == 'YES') { $vacation_domain = $CONF['vacation_domain']; $ce_email = preg_replace("/@$vacation_domain/", '', $ce_email); $ce_email = preg_replace("/#/", '@', $ce_email); } // Perform non-domain-part sanity checks if (!preg_match ('/^[-!#$%&\'*+\\.\/0-9=?A-Z^_{|}~]+' . '@' . '[^@]+$/i', $ce_email)) { flash_error($PALANG['pInvalidMailRegex']); return false; } // Determine domain name $matches=array(); if (!preg_match('|@(.+)$|',$ce_email,$matches)) { flash_error($PALANG['pInvalidMailRegex']); return false; } $domain=$matches[1]; # check domain name return check_domain($domain); } /** * Clean a string, escaping any meta characters that could be * used to disrupt an SQL string. i.e. "'" => "\'" etc. * * @param String (or Array) * @return String (or Array) of cleaned data, suitable for use within an SQL * statement. */ function escape_string ($string) { global $CONF; // if the string is actually an array, do a recursive cleaning. // Note, the array keys are not cleaned. if(is_array($string)) { $clean = array(); foreach(array_keys($string) as $row) { $clean[$row] = escape_string($string[$row]); } return $clean; } if (get_magic_quotes_gpc ()) { $string = stripslashes($string); } if (!is_numeric($string)) { $link = db_connect(); if ($CONF['database_type'] == "mysql") { $escaped_string = mysql_real_escape_string($string, $link); } if ($CONF['database_type'] == "mysqli") { $escaped_string = mysqli_real_escape_string($link, $string); } if ($CONF['database_type'] == "pgsql") { // php 5.2+ allows for $link to be specified. if (version_compare(phpversion(), "5.2.0", ">=")) { $escaped_string = pg_escape_string($link, $string); } else { $escaped_string = pg_escape_string($string); } } } else { $escaped_string = $string; } return $escaped_string; } /** * safeget * Action: get value from $_GET[$param], or $default if $_GET[$param] is not set * Call: $param = safeget('param') # replaces $param = $_GET['param'] * - or - * $param = safeget('param', 'default') * * @param String parameter name. * @param String (optional) - default value if key is not set. * @return String */ function safeget ($param, $default="") { $retval=$default; if (isset($_GET[$param])) $retval=$_GET[$param]; return $retval; } /** * safepost - similar to safeget() * @see safeget() * @param String parameter name * @param String (optional) default value (defaults to "") * @return String - value in $_POST[$param] or $default * same as safeget, but for $_POST */ function safepost ($param, $default="") { $retval=$default; if (isset($_POST[$param])) $retval=$_POST[$param]; return $retval; } /** * safeserver * @see safeget() * @param String $param * @param String $default (optional) * @return String value from $_SERVER[$param] or $default */ function safeserver ($param, $default="") { $retval=$default; if (isset($_SERVER[$param])) $retval=$_SERVER[$param]; return $retval; } /** * safecookie * @see safeget() * @param String $param * @param String $default (optional) * @return String value from $_COOKIE[$param] or $default */ function safecookie ($param, $default="") { $retval=$default; if (isset($_COOKIE[$param])) $retval=$_COOKIE[$param]; return $retval; } // // get_domain_properties // Action: Get all the properties of a domain. // Call: get_domain_properties (string domain) // function get_domain_properties ($domain) { global $CONF; global $table_alias, $table_mailbox, $table_domain; $list = array (); $result = db_query ("SELECT COUNT(*) FROM $table_alias WHERE domain='$domain'"); $row = db_row ($result['result']); $list['alias_count'] = $row[0]; $result = db_query ("SELECT COUNT(*) FROM $table_mailbox WHERE domain='$domain'"); $row = db_row ($result['result']); $list['mailbox_count'] = $row[0]; $result = db_query ("SELECT SUM(quota) FROM $table_mailbox WHERE domain='$domain'"); $row = db_row ($result['result']); $list['quota_sum'] = $row[0]; $list['alias_count'] = $list['alias_count'] - $list['mailbox_count']; $list['alias_pgindex']=array (); $list['mbox_pgindex']=array (); $list['mbox_pgindex_count'] = 0; //while loop to figure index names. use page_size and loop of queries $i=0; $current=0; $page_size = (int) $CONF['page_size']; if ($page_size < 1) die ("\$CONF['page_size'] = '$page_size' is invalid (it may only contain digits and must be >= 1)"); $tmpstr=""; $idxlabel=""; $list['alias_pgindex_count'] = 0; if ( $list['alias_count'] > $page_size ) { while ( $current < $list['alias_count'] ) { $limitSql=('pgsql'==$CONF['database_type']) ? "1 OFFSET $current" : "$current, 1"; $query = "SELECT $table_alias.address FROM $table_alias LEFT JOIN $table_mailbox ON $table_alias.address=$table_mailbox.username WHERE ($table_alias.domain='$domain' AND $table_mailbox.maildir IS NULL) ORDER BY $table_alias.address LIMIT $limitSql"; $result = db_query ("$query"); $row = db_array ($result['result']); $tmpstr = $row['address']; //get first 2 chars $idxlabel = $tmpstr[0] . $tmpstr[1] . "-"; ($current + $page_size - 1 <= $list['alias_count']) ? $current = $current + $page_size - 1 : $current = $list['alias_count'] - 1; $limitSql=('pgsql'==$CONF['database_type']) ? "1 OFFSET $current" : "$current, 1"; $query = "SELECT $table_alias.address FROM $table_alias LEFT JOIN $table_mailbox ON $table_alias.address=$table_mailbox.username WHERE ($table_alias.domain='$domain' AND $table_mailbox.maildir IS NULL) ORDER BY $table_alias.address LIMIT $limitSql"; $result = db_query ("$query"); $row = db_array ($result['result']); $tmpstr = $row['address']; $idxlabel = $idxlabel . $tmpstr[0] . $tmpstr[1]; $current = $current + 1; $list['alias_pgindex'][]=$idxlabel; $i++; } $list['alias_pgindex_count']=$i; } $i=0; $current=0; $page_size = $CONF['page_size']; $tmpstr=""; $idxlabel=""; if ( $list['mailbox_count'] > $page_size ) { while ( $current < $list['mailbox_count'] ) { $limitSql=('pgsql'==$CONF['database_type']) ? "1 OFFSET $current" : "$current, 1"; $query = "SELECT $table_mailbox.username FROM $table_mailbox WHERE $table_mailbox.domain='$domain' ORDER BY $table_mailbox.username LIMIT $limitSql"; $result = db_query ("$query"); $row = db_array ($result['result']); $tmpstr = $row['username']; //get first 2 chars $idxlabel = $tmpstr[0] . $tmpstr[1] . "-"; ($current + $page_size - 1 <= $list['mailbox_count']) ? $current = $current + $page_size - 1 : $current = $list['mailbox_count'] - 1; $limitSql=('pgsql'==$CONF['database_type']) ? "1 OFFSET $current" : "$current, 1"; $query = "SELECT $table_mailbox.username FROM $table_mailbox WHERE $table_mailbox.domain='$domain' ORDER BY $table_mailbox.username LIMIT $limitSql"; $result = db_query ("$query"); $row = db_array ($result['result']); $tmpstr = $row['username']; $idxlabel = $idxlabel . $tmpstr[0] . $tmpstr[1]; $current = $current + 1; $list['mbox_pgindex'][]=$idxlabel; $i++; } $list['mbox_pgindex_count']=$i; } // end mod $query="SELECT * FROM $table_domain WHERE domain='$domain'"; if ('pgsql'==$CONF['database_type']) { $query=" SELECT *, EXTRACT(epoch FROM created) AS uts_created, EXTRACT(epoch FROM modified) AS uts_modified FROM $table_domain WHERE domain='$domain' "; } $result = db_query ($query); $row = db_array ($result['result']); $list['description'] = $row['description']; $list['aliases'] = $row['aliases']; $list['mailboxes'] = $row['mailboxes']; $list['maxquota'] = $row['maxquota']; $list['quota'] = $row['quota']; $list['transport'] = $row['transport']; $list['backupmx'] = $row['backupmx']; $list['created'] = $row['created']; $list['modified'] = $row['modified']; $list['active'] = $row['active']; if ($CONF['database_type'] == "pgsql") { $list['active']=('t'==$row['active']) ? 1 : 0; $list['backupmx']=('t'==$row['backupmx']) ? 1 : 0; $list['created']= gmstrftime('%c %Z',$row['uts_created']); $list['modified']= gmstrftime('%c %Z',$row['uts_modified']); } else { $list['active'] = $row['active']; $list['backupmx'] = $row['backupmx']; } return $list; } // // get_mailbox_properties // Action: Get all the properties of a mailbox. // Call: get_mailbox_properties (string mailbox) // function get_mailbox_properties ($username) { global $CONF; global $table_mailbox; $query="SELECT * FROM $table_mailbox WHERE username='$username'"; if ('pgsql'==$CONF['database_type']) { $query=" SELECT *, EXTRACT(epoch FROM created) AS uts_created, EXTRACT(epoch FROM modified) AS uts_modified FROM $table_mailbox WHERE username='$username' "; } $result = db_query ($query); $row = db_array ($result['result']); $list['name'] = $row['name']; $list['maildir'] = $row['maildir']; $list['quota'] = $row['quota']; $list['domain'] = $row['domain']; $list['created'] = $row['created']; $list['modified'] = $row['modified']; $list['active'] = $row['active']; if ($CONF['database_type'] == "pgsql") { $list['active']=('t'==$row['active']) ? 1 : 0; $list['created']= gmstrftime('%c %Z',$row['uts_created']); $list['modified']= gmstrftime('%c %Z',$row['uts_modified']); } else { $list['active'] = $row['active']; } return $list; } // // check_alias // Action: Checks if the domain is still able to create aliases. // Call: check_alias (string domain) // function check_alias ($domain) { $limit = get_domain_properties ($domain); if ($limit['aliases'] == 0) { # 0 = unlimited, -1 = disabled return true; } if ($limit['aliases'] < 0) { return false; } if ($limit['alias_count'] >= $limit['aliases']) { return false; } else { return true; } } // // check_mailbox // Action: Checks if the domain is still able to create mailboxes. // Call: check_mailbox (string domain) // function check_mailbox ($domain) { $limit = get_domain_properties ($domain); /* -1 = disable, 0 = unlimited */ if ($limit['mailboxes'] == 0) { return true; } if ($limit['mailboxes'] < 0) { return false; } if ($limit['mailbox_count'] >= $limit['mailboxes']) { return false; } else { return true; } } // // check_quota // Action: Checks if the user is creating a mailbox with the correct quota // Call: check_quota (string domain) // function check_quota ($quota, $domain) { $limit = get_domain_properties ($domain); if ($limit['maxquota'] == 0) { return true; } if (($limit['maxquota'] < 0) and ($quota < 0)) { return true; } if (($limit['maxquota'] > 0) and ($quota == 0)) { return false; } if ($quota > $limit['maxquota']) { return false; } else { return true; } } // // multiply_quota // Action: Recalculates the quota from bytes to MBs (multiply, *) // Call: multiply_quota (string $quota) // function multiply_quota ($quota) { global $CONF; if ($quota == -1) return $quota; $value = $quota * $CONF['quota_multiplier']; return $value; } // // divide_quota // Action: Recalculates the quota from MBs to bytes (divide, /) // Call: divide_quota (string $quota) // function divide_quota ($quota) { global $CONF; if ($quota == -1) return $quota; $value = round($quota / $CONF['quota_multiplier'],2); return $value; } // // check_owner // Action: Checks if the admin is the owner of the domain (or global-admin) // Call: check_owner (string admin, string domain) // function check_owner ($username, $domain) { global $table_domain_admins; $result = db_query ("SELECT 1 FROM $table_domain_admins WHERE username='$username' AND (domain='$domain' OR domain='ALL') AND active='1'"); if ($result['rows'] != 1) { if ($result['rows'] > 1) { # "ALL" + specific domain permissions. 2.3 doesn't create such entries, but they are available as leftover from older versions flash_error("Permission check returned more than one result. Please go to 'edit admin' for your username and press the save " . "button once to fix the database. If this doesn't help, open a bugreport."); } return false; } else { return true; } } // // check_alias_owner // Action: Checks if the admin is the owner of the alias. // Call: check_alias_owner (string admin, string alias) // function check_alias_owner ($username, $alias) { global $CONF; if (authentication_has_role('global-admin')) return true; $tmp = preg_split('/\@/', $alias); if (($CONF['special_alias_control'] == 'NO') && array_key_exists($tmp[0], $CONF['default_aliases'])) { return false; } else { return true; } } /** * List domains for an admin user. * @param String $username * @return array of domain names. */ function list_domains_for_admin ($username) { global $CONF; global $table_domain, $table_domain_admins; $list = array (); // does $username need escaping here? $active_sql = db_get_boolean(True); $backupmx_sql = db_get_boolean(False); $query = "SELECT $table_domain.domain, $table_domain_admins.username FROM $table_domain LEFT JOIN $table_domain_admins ON $table_domain.domain=$table_domain_admins.domain WHERE $table_domain_admins.username='$username' AND $table_domain.active='$active_sql' AND $table_domain.backupmx='$backupmx_sql' ORDER BY $table_domain_admins.domain"; $result = db_query ($query); if ($result['rows'] > 0) { $i = 0; while ($row = db_array ($result['result'])) { $list[$i] = $row['domain']; $i++; } } return $list; } // // list_domains // Action: List all available domains. // Call: list_domains () // function list_domains () { global $table_domain; $list = array(); $result = db_query ("SELECT domain FROM $table_domain WHERE domain!='ALL' ORDER BY domain"); if ($result['rows'] > 0) { $i = 0; while ($row = db_array ($result['result'])) { $list[$i] = $row['domain']; $i++; } } return $list; } // // admin_exist // Action: Checks if the admin already exists. // Call: admin_exist (string admin) // function admin_exist ($username) { $result = db_query ("SELECT 1 FROM " . table_by_key ('admin') . " WHERE username='$username'"); if ($result['rows'] != 1) { return false; } else { return true; } } // // domain_exist // Action: Checks if the domain already exists. // Call: domain_exist (string domain) // function domain_exist ($domain) { global $table_domain; $result = db_query("SELECT 1 FROM $table_domain WHERE domain='$domain'"); if ($result['rows'] != 1) { return false; } else { return true; } } // // list_admins // Action: Lists all the admins // Call: list_admins () // // was admin_list_admins // function list_admins () { global $table_admin; $list = ""; $result = db_query ("SELECT username FROM $table_admin ORDER BY username"); if ($result['rows'] > 0) { $i = 0; while ($row = db_array ($result['result'])) { $list[$i] = $row['username']; $i++; } } return $list; } // // get_admin_properties // Action: Get all the admin properties. // Call: get_admin_properties (string admin) // function get_admin_properties ($username) { global $CONF; global $table_admin, $table_domain_admins; $list = array (); $result = db_query ("SELECT * FROM $table_domain_admins WHERE username='$username' AND domain='ALL'"); if ($result['rows'] == 1) { $list['domain_count'] = 'ALL'; } else { $result = db_query ("SELECT COUNT(*) FROM $table_domain_admins WHERE username='$username'"); $row = db_row ($result['result']); $list['domain_count'] = $row[0]; } $query = "SELECT * FROM $table_admin WHERE username='$username'"; if ('pgsql'==$CONF['database_type']) { $query=" SELECT *, EXTRACT(epoch FROM created) AS uts_created, EXTRACT (epoch FROM modified) AS uts_modified FROM $table_admin WHERE username='$username' "; } $result = db_query ($query); $row = db_array ($result['result']); $list['created'] = $row['created']; $list['modified'] = $row['modified']; $list['active'] = $row['active']; if ('pgsql'==$CONF['database_type']) { $list['active'] = ('t'==$row['active']) ? 1 : 0; $list['created']= gmstrftime('%c %Z',$row['uts_created']); $list['modified']= gmstrftime('%c %Z',$row['uts_modified']); } return $list; } // // encode_header // Action: Encode a string according to RFC 1522 for use in headers if it contains 8-bit characters. // Call: encode_header (string header, string charset) // function encode_header ($string, $default_charset = "utf-8") { if (strtolower ($default_charset) == 'iso-8859-1') { $string = str_replace ("\240",' ',$string); } $j = strlen ($string); $max_l = 75 - strlen ($default_charset) - 7; $aRet = array (); $ret = ''; $iEncStart = $enc_init = false; $cur_l = $iOffset = 0; for ($i = 0; $i < $j; ++$i) { switch ($string{$i}) { case '=': case '<': case '>': case ',': case '?': case '_': if ($iEncStart === false) { $iEncStart = $i; } $cur_l+=3; if ($cur_l > ($max_l-2)) { $aRet[] = substr ($string,$iOffset,$iEncStart-$iOffset); $aRet[] = "=?$default_charset?Q?$ret?="; $iOffset = $i; $cur_l = 0; $ret = ''; $iEncStart = false; } else { $ret .= sprintf ("=%02X",ord($string{$i})); } break; case '(': case ')': if ($iEncStart !== false) { $aRet[] = substr ($string,$iOffset,$iEncStart-$iOffset); $aRet[] = "=?$default_charset?Q?$ret?="; $iOffset = $i; $cur_l = 0; $ret = ''; $iEncStart = false; } break; case ' ': if ($iEncStart !== false) { $cur_l++; if ($cur_l > $max_l) { $aRet[] = substr ($string,$iOffset,$iEncStart-$iOffset); $aRet[] = "=?$default_charset?Q?$ret?="; $iOffset = $i; $cur_l = 0; $ret = ''; $iEncStart = false; } else { $ret .= '_'; } } break; default: $k = ord ($string{$i}); if ($k > 126) { if ($iEncStart === false) { // do not start encoding in the middle of a string, also take the rest of the word. $sLeadString = substr ($string,0,$i); $aLeadString = explode (' ',$sLeadString); $sToBeEncoded = array_pop ($aLeadString); $iEncStart = $i - strlen ($sToBeEncoded); $ret .= $sToBeEncoded; $cur_l += strlen ($sToBeEncoded); } $cur_l += 3; // first we add the encoded string that reached it's max size if ($cur_l > ($max_l-2)) { $aRet[] = substr ($string,$iOffset,$iEncStart-$iOffset); $aRet[] = "=?$default_charset?Q?$ret?= "; $cur_l = 3; $ret = ''; $iOffset = $i; $iEncStart = $i; } $enc_init = true; $ret .= sprintf ("=%02X", $k); } else { if ($iEncStart !== false) { $cur_l++; if ($cur_l > $max_l) { $aRet[] = substr ($string,$iOffset,$iEncStart-$iOffset); $aRet[] = "=?$default_charset?Q?$ret?="; $iEncStart = false; $iOffset = $i; $cur_l = 0; $ret = ''; } else { $ret .= $string{$i}; } } } break; } } if ($enc_init) { if ($iEncStart !== false) { $aRet[] = substr ($string,$iOffset,$iEncStart-$iOffset); $aRet[] = "=?$default_charset?Q?$ret?="; } else { $aRet[] = substr ($string,$iOffset); } $string = implode ('',$aRet); } return $string; } // // generate_password // Action: Generates a random password // Call: generate_password () // function generate_password () { global $CONF; //check that password length is sensible $length = (int) $CONF['min_password_length']; if ($length < 5 || $length > 32) { $length = 8; } // define possible characters $possible = "2345678923456789abcdefghijkmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ"; # skip 0 and 1 to avoid confusion with O and l // add random characters to $password until $length is reached $password = ""; while (strlen($password) < $length) { // pick a random character from the possible ones $char = substr($possible, mt_rand(0, strlen($possible)-1), 1); // we don't want this character if it's already in the password if (!strstr($password, $char)) { $password .= $char; } } return $password; } /** * Encrypt a password, using the apparopriate hashing mechanism as defined in * config.inc.php ($CONF['encrypt']). * When wanting to compare one pw to another, it's necessary to provide the salt used - hence * the second parameter ($pw_db), which is the existing hash from the DB. * * @param string $pw * @param string $encrypted password * @return string encrypted password. */ function pacrypt ($pw, $pw_db="") { global $CONF; $pw = stripslashes($pw); $password = ""; $salt = ""; if ($CONF['encrypt'] == 'md5crypt') { $split_salt = preg_split ('/\$/', $pw_db); if (isset ($split_salt[2])) { $salt = $split_salt[2]; } $password = md5crypt ($pw, $salt); } elseif ($CONF['encrypt'] == 'md5') { $password = md5($pw); } elseif ($CONF['encrypt'] == 'system') { if (preg_match("/\\$1\\$/", $pw_db)) { $split_salt = preg_split ('/\$/', $pw_db); $salt = "\$1\$${split_salt[2]}\$"; } else { if (strlen($pw_db) == 0) { $salt = substr (md5 (mt_rand ()), 0, 2); } else { $salt = substr ($pw_db, 0, 2); } } $password = crypt ($pw, $salt); } elseif ($CONF['encrypt'] == 'cleartext') { $password = $pw; } // See https://sourceforge.net/tracker/?func=detail&atid=937966&aid=1793352&group_id=191583 // this is apparently useful for pam_mysql etc. elseif ($CONF['encrypt'] == 'mysql_encrypt') { $pw = escape_string($pw); if ($pw_db!="") { $salt=escape_string(substr($pw_db,0,2)); $res=db_query("SELECT ENCRYPT('".$pw."','".$salt."');"); } else { $res=db_query("SELECT ENCRYPT('".$pw."');"); } $l = db_row($res["result"]); $password = $l[0]; } elseif ($CONF['encrypt'] == 'authlib') { $flavor = $CONF['authlib_default_flavor']; $salt = substr(create_salt(), 0, 2); # courier-authlib supports only two-character salts if(preg_match('/^{.*}/', $pw_db)) { // we have a flavor in the db -> use it instead of default flavor $result = preg_split('/[{}]/', $pw_db, 3); # split at { and/or } $flavor = $result[1]; $salt = substr($result[2], 0, 2); } if(stripos($flavor, 'md5raw') === 0) { $password = '{' . $flavor . '}' . md5($pw); } elseif(stripos($flavor, 'md5') === 0) { $password = '{' . $flavor . '}' . base64_encode(md5($pw, TRUE)); } elseif(stripos($flavor, 'crypt') === 0) { $password = '{' . $flavor . '}' . crypt($pw, $salt); } elseif(stripos($flavor, 'SHA') === 0) { $password = '{' . $flavor . '}' . base64_encode(sha1($pw, TRUE)); } else { die("authlib_default_flavor '" . $flavor . "' unknown. Valid flavors are 'md5raw', 'md5', 'SHA' and 'crypt'"); } } elseif (preg_match("/^dovecot:/", $CONF['encrypt'])) { $split_method = preg_split ('/:/', $CONF['encrypt']); $method = strtoupper($split_method[1]); if (! preg_match("/^[A-Z0-9-]+$/", $method)) { die("invalid dovecot encryption method"); } # TODO: check against a fixed list? if (strtolower($method) == 'md5-crypt') die("\$CONF['encrypt'] = 'dovecot:md5-crypt' will not work because dovecotpw generates a random salt each time. Please use \$CONF['encrypt'] = 'md5crypt' instead."); $dovecotpw = "dovecotpw"; if (!empty($CONF['dovecotpw'])) $dovecotpw = $CONF['dovecotpw']; # Use proc_open call to avoid safe_mode problems and to prevent showing plain password in process table $spec = array( 0 => array("pipe", "r"), // stdin 1 => array("pipe", "w"), // stdout 2 => array("pipe", "w"), // stderr ); $pipe = proc_open("$dovecotpw '-s' $method", $spec, $pipes); if (!$pipe) { die("can't proc_open $dovecotpw"); } else { // use dovecot's stdin, it uses getpass() twice // Write pass in pipe stdin fwrite($pipes[0], $pw . "\n", 1+strlen($pw)); usleep(1000); fwrite($pipes[0], $pw . "\n", 1+strlen($pw)); fclose($pipes[0]); // Read hash from pipe stdout $password = fread($pipes[1], "200"); if ( !preg_match('/^\{' . $method . '\}/', $password)) { $stderr_output = stream_get_contents($pipes[2]); error_log('dovecotpw password encryption failed.'); error_log('STDERR output: ' . $stderr_output); die("can't encrypt password with dovecotpw, see error log for details"); } fclose($pipes[1]); fclose($pipes[2]); proc_close($pipe); $password = trim(str_replace('{' . $method . '}', '', $password)); } } else { die ('unknown/invalid $CONF["encrypt"] setting: ' . $CONF['encrypt']); } $password = escape_string ($password); return $password; } // // md5crypt // Action: Creates MD5 encrypted password // Call: md5crypt (string cleartextpassword) // function md5crypt ($pw, $salt="", $magic="") { $MAGIC = "$1$"; if ($magic == "") $magic = $MAGIC; if ($salt == "") $salt = create_salt (); $slist = explode ("$", $salt); if ($slist[0] == "1") $salt = $slist[1]; $salt = substr ($salt, 0, 8); $ctx = $pw . $magic . $salt; $final = hex2bin (md5 ($pw . $salt . $pw)); for ($i=strlen ($pw); $i>0; $i-=16) { if ($i > 16) { $ctx .= substr ($final,0,16); } else { $ctx .= substr ($final,0,$i); } } $i = strlen ($pw); while ($i > 0) { if ($i & 1) $ctx .= chr (0); else $ctx .= $pw[0]; $i = $i >> 1; } $final = hex2bin (md5 ($ctx)); for ($i=0;$i<1000;$i++) { $ctx1 = ""; if ($i & 1) { $ctx1 .= $pw; } else { $ctx1 .= substr ($final,0,16); } if ($i % 3) $ctx1 .= $salt; if ($i % 7) $ctx1 .= $pw; if ($i & 1) { $ctx1 .= substr ($final,0,16); } else { $ctx1 .= $pw; } $final = hex2bin (md5 ($ctx1)); } $passwd = ""; $passwd .= to64 (((ord ($final[0]) << 16) | (ord ($final[6]) << 8) | (ord ($final[12]))), 4); $passwd .= to64 (((ord ($final[1]) << 16) | (ord ($final[7]) << 8) | (ord ($final[13]))), 4); $passwd .= to64 (((ord ($final[2]) << 16) | (ord ($final[8]) << 8) | (ord ($final[14]))), 4); $passwd .= to64 (((ord ($final[3]) << 16) | (ord ($final[9]) << 8) | (ord ($final[15]))), 4); $passwd .= to64 (((ord ($final[4]) << 16) | (ord ($final[10]) << 8) | (ord ($final[5]))), 4); $passwd .= to64 (ord ($final[11]), 2); return "$magic$salt\$$passwd"; } function create_salt () { srand ((double) microtime ()*1000000); $salt = substr (md5 (rand (0,9999999)), 0, 8); return $salt; } /**/ if (!function_exists('hex2bin')) { # PHP around 5.3.8 includes hex2bin as native function - http://php.net/hex2bin function hex2bin ($str) { $len = strlen ($str); $nstr = ""; for ($i=0;$i<$len;$i+=2) { $num = sscanf (substr ($str,$i,2), "%x"); $nstr.=chr ($num[0]); } return $nstr; } /**/ } function to64 ($v, $n) { $ITOA64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; $ret = ""; while (($n - 1) >= 0) { $n--; $ret .= $ITOA64[$v & 0x3f]; $v = $v >> 6; } return $ret; } // // smtp_mail // Action: Sends email to new account. // Call: smtp_mail (string To, string From, string Data) // TODO: Replace this with something decent like PEAR::Mail or Zend_Mail. function smtp_mail ($to, $from, $data) { global $CONF; $smtpd_server = $CONF['smtp_server']; $smtpd_port = $CONF['smtp_port']; $smtp_server = $_SERVER["SERVER_NAME"]; $errno = "0"; $errstr = "0"; $timeout = "30"; $fh = @fsockopen ($smtpd_server, $smtpd_port, $errno, $errstr, $timeout); if (!$fh) { return false; } else { $res = smtp_get_response($fh); fputs ($fh, "EHLO $smtp_server\r\n"); $res = smtp_get_response($fh); fputs ($fh, "MAIL FROM:<$from>\r\n"); $res = smtp_get_response($fh); fputs ($fh, "RCPT TO:<$to>\r\n"); $res = smtp_get_response($fh); fputs ($fh, "DATA\r\n"); $res = smtp_get_response($fh); fputs ($fh, "$data\r\n.\r\n"); $res = smtp_get_response($fh); fputs ($fh, "QUIT\r\n"); $res = smtp_get_response($fh); fclose ($fh); } return true; } // // smtp_get_response // Action: Get response from mail server // Call: smtp_get_response (string FileHandle) // function smtp_get_response ($fh) { $res =''; do { $line = fgets($fh, 256); $res .= $line; } while (preg_match("/^\d\d\d\-/", $line)); return $res; } $DEBUG_TEXT = "\n

\n Please check the documentation and website for more information.\n

\n Postfix Admin
\n Forums "; /** * db_connect * Action: Makes a connection to the database if it doesn't exist * Call: db_connect () * Optional parameter: $ignore_errors = TRUE, used by setup.php * * Return value: * a) without $ignore_errors or $ignore_errors == 0 * - $link - the database connection -OR- * - call die() in case of connection problems * b) with $ignore_errors == TRUE * array($link, $error_text); */ function db_connect ($ignore_errors = 0) { global $CONF; global $DEBUG_TEXT; if ($ignore_errors != 0) $DEBUG_TEXT = ''; $error_text = ''; $link = 0; if ($CONF['database_type'] == "mysql") { if (function_exists ("mysql_connect")) { $link = @mysql_connect ($CONF['database_host'], $CONF['database_user'], $CONF['database_password']) or $error_text .= ("

DEBUG INFORMATION:
Connect: " . mysql_error () . "$DEBUG_TEXT"); if ($link) { @mysql_query("SET CHARACTER SET utf8",$link); @mysql_query("SET COLLATION_CONNECTION='utf8_general_ci'",$link); $succes = @mysql_select_db ($CONF['database_name'], $link) or $error_text .= ("

DEBUG INFORMATION:
MySQL Select Database: " . mysql_error () . "$DEBUG_TEXT"); } } else { $error_text .= "

DEBUG INFORMATION:
MySQL 3.x / 4.0 functions not available! (php5-mysql installed?)
database_type = 'mysql' in config.inc.php, are you using a different database? $DEBUG_TEXT"; } } elseif ($CONF['database_type'] == "mysqli") { if (function_exists ("mysqli_connect")) { $link = @mysqli_connect ($CONF['database_host'], $CONF['database_user'], $CONF['database_password']) or $error_text .= ("

DEBUG INFORMATION:
Connect: " . mysqli_connect_error () . "$DEBUG_TEXT"); if ($link) { @mysqli_query($link,"SET CHARACTER SET utf8"); @mysqli_query($link,"SET COLLATION_CONNECTION='utf8_general_ci'"); $success = @mysqli_select_db ($link, $CONF['database_name']) or $error_text .= ("

DEBUG INFORMATION:
MySQLi Select Database: " . mysqli_error ($link) . "$DEBUG_TEXT"); } } else { $error_text .= "

DEBUG INFORMATION:
MySQL 4.1 functions not available! (php5-mysqli installed?)
database_type = 'mysqli' in config.inc.php, are you using a different database? $DEBUG_TEXT"; } } elseif ($CONF['database_type'] == "pgsql") { if (function_exists ("pg_pconnect")) { if(!isset($CONF['database_port'])) { $CONF['database_port'] = '5432'; } $connect_string = "host=" . $CONF['database_host'] . " port=" . $CONF['database_port'] . " dbname=" . $CONF['database_name'] . " user=" . $CONF['database_user'] . " password=" . $CONF['database_password']; $link = @pg_pconnect ($connect_string) or $error_text .= ("

DEBUG INFORMATION:
Connect: failed to connect to database. $DEBUG_TEXT"); if ($link) pg_set_client_encoding($link, 'UNICODE'); } else { $error_text .= "

DEBUG INFORMATION:
PostgreSQL functions not available! (php5-pgsql installed?)
database_type = 'pgsql' in config.inc.php, are you using a different database? $DEBUG_TEXT"; } } else { $error_text = "

DEBUG INFORMATION:
Invalid \$CONF['database_type']! Please fix your config.inc.php! $DEBUG_TEXT"; } if ($ignore_errors) { return array($link, $error_text); } elseif ($error_text != "") { print $error_text; die(); } elseif ($link) { return $link; } else { print "DEBUG INFORMATION:
\n"; print "Connect: Unable to connect to database
\n"; print "
\n"; print "Make sure that you have set the correct database type in the config.inc.php file
\n"; print $DEBUG_TEXT; die(); } } /** * Returns the appropriate boolean value for the database. * Currently only PostgreSQL and MySQL are supported. * @param boolean $bool (REQUIRED) * @return String or int as appropriate. */ function db_get_boolean($bool) { if(!is_bool($bool)) { die("Invalid usage of 'db_get_boolean($bool)'"); } global $CONF; if($CONF['database_type']=='pgsql') { // return either true or false (unquoted strings) if($bool) { return 't'; } return 'f'; } elseif($CONF['database_type'] == 'mysql' || $CONF['database_type'] == 'mysqli') { if($bool) { return 1; } return 0; } } // // db_query // Action: Sends a query to the database and returns query result and number of rows // Call: db_query (string query) // Optional parameter: $ignore_errors = TRUE, used by upgrade.php // function db_query ($query, $ignore_errors = 0) { global $CONF; global $DEBUG_TEXT; $result = ""; $number_rows = ""; static $link; $error_text = ""; if ($ignore_errors) $DEBUG_TEXT = ""; if (!is_resource($link)) $link = db_connect (); if ($CONF['database_type'] == "mysql") $result = @mysql_query ($query, $link) or $error_text = "

DEBUG INFORMATION:
Invalid query: " . mysql_error($link) . "$DEBUG_TEXT"; if ($CONF['database_type'] == "mysqli") $result = @mysqli_query ($link, $query) or $error_text = "

DEBUG INFORMATION:
Invalid query: " . mysqli_error($link) . "$DEBUG_TEXT"; if ($CONF['database_type'] == "pgsql") { $result = @pg_query ($link, $query) or $error_text = "

DEBUG INFORMATION:
Invalid query: " . pg_last_error() . "$DEBUG_TEXT"; } if ($error_text != "" && $ignore_errors == 0) die($error_text); if ($error_text == "") { if (preg_match("/^SELECT/i", trim($query))) { // if $query was a SELECT statement check the number of rows with [database_type]_num_rows (). if ($CONF['database_type'] == "mysql") $number_rows = mysql_num_rows ($result); if ($CONF['database_type'] == "mysqli") $number_rows = mysqli_num_rows ($result); if ($CONF['database_type'] == "pgsql") $number_rows = pg_num_rows ($result); } else { // if $query was something else, UPDATE, DELETE or INSERT check the number of rows with // [database_type]_affected_rows (). if ($CONF['database_type'] == "mysql") $number_rows = mysql_affected_rows ($link); if ($CONF['database_type'] == "mysqli") $number_rows = mysqli_affected_rows ($link); if ($CONF['database_type'] == "pgsql") $number_rows = pg_affected_rows ($result); } } $return = array ( "result" => $result, "rows" => $number_rows, "error" => $error_text ); return $return; } // db_row // Action: Returns a row from a table // Call: db_row (int result) // function db_row ($result) { global $CONF; $row = ""; if ($CONF['database_type'] == "mysql") $row = mysql_fetch_row ($result); if ($CONF['database_type'] == "mysqli") $row = mysqli_fetch_row ($result); if ($CONF['database_type'] == "pgsql") $row = pg_fetch_row ($result); return $row; } // db_array // Action: Returns a row from a table // Call: db_array (int result) // function db_array ($result) { global $CONF; $row = ""; if ($CONF['database_type'] == "mysql") $row = mysql_fetch_array ($result); if ($CONF['database_type'] == "mysqli") $row = mysqli_fetch_array ($result); if ($CONF['database_type'] == "pgsql") $row = pg_fetch_array ($result); return $row; } // db_assoc // Action: Returns a row from a table // Call: db_assoc(int result) // function db_assoc ($result) { global $CONF; $row = ""; if ($CONF['database_type'] == "mysql") $row = mysql_fetch_assoc ($result); if ($CONF['database_type'] == "mysqli") $row = mysqli_fetch_assoc ($result); if ($CONF['database_type'] == "pgsql") $row = pg_fetch_assoc ($result); return $row; } // // db_delete // Action: Deletes a row from a specified table // Call: db_delete (string table, string where, string delete) // function db_delete ($table,$where,$delete) { # $table = table_by_key($table); # intentionally disabled to avoid breaking delete.php in 2.3.x # This makes the behaviour of this function incorrect, but delete.php is the only file in 2.3.x calling db_delete and expects this (wrong) behaviour. $query = "DELETE FROM $table WHERE " . escape_string($where) . "='" . escape_string($delete) . "'"; $result = db_query ($query); if ($result['rows'] >= 1) { return $result['rows']; } else { return true; } } /** * db_insert * Action: Inserts a row from a specified table * Call: db_insert (string table, array values) * @param String $table - table name * @param array - key/value map of data to insert into the table. * @param array (optional) - array of fields to set to now() * @return int - number of inserted rows */ function db_insert ($table, $values, $timestamp = array()) { $table = table_by_key ($table); foreach(array_keys($values) as $key) { $values[$key] = "'" . escape_string($values[$key]) . "'"; } foreach($timestamp as $key) { $values[$key] = "now()"; } $sql_values = "(" . implode(",",escape_string(array_keys($values))).") VALUES (".implode(",",$values).")"; $result = db_query ("INSERT INTO $table $sql_values"); return $result['rows']; } /** * db_update * Action: Updates a specified table * Call: db_update (string table, array values, string where) * @param String $table - table name * @param String - WHERE condition * @param array - key/value map of data to insert into the table. * @param array (optional) - array of fields to set to now() * @return int - number of updated rows */ function db_update ($table, $where, $values, $timestamp = array()) { $table = table_by_key ($table); foreach(array_keys($values) as $key) { $sql_values[$key] = escape_string($key) . "='" . escape_string($values[$key]) . "'"; } foreach($timestamp as $key) { $sql_values[$key] = escape_string($key) . "=now()"; } $sql="UPDATE $table SET ".implode(",",$sql_values)." WHERE $where"; $result = db_query ($sql); return $result['rows']; } /** * db_log * Action: Logs actions from admin * Call: db_log (string username, string domain, string action, string data) * Possible actions are: * 'create_alias' * 'create_alias_domain' * 'create_mailbox' * 'delete_alias' * 'delete_alias_domain' * 'delete_mailbox' * 'edit_alias' * 'edit_alias_state' * 'edit_alias_domain_state' * 'edit_mailbox' * 'edit_mailbox_state' * 'edit_password' */ function db_log ($username,$domain,$action,$data) { global $CONF; global $table_log; $REMOTE_ADDR = $_SERVER['REMOTE_ADDR']; $action_list = array('create_alias', 'create_alias_domain', 'delete_alias', 'delete_alias_domain', 'edit_alias', 'create_mailbox', 'delete_mailbox', 'edit_mailbox', 'edit_alias_state', 'edit_alias_domain_state', 'edit_mailbox_state', 'edit_password'); if(!in_array($action, $action_list)) { die("Invalid log action : $action"); // could do with something better? } if ($CONF['logging'] == 'YES') { $logdata = array( 'username' => "$username ($REMOTE_ADDR)", 'domain' => $domain, 'action' => $action, 'data' => $data, ); $result = db_insert('log', $logdata, array('timestamp') ); #$result = db_query ("INSERT INTO $table_log (timestamp,username,domain,action,data) VALUES (NOW(),'$username ($REMOTE_ADDR)','$domain','$action','$data')"); if ($result != 1) { return false; } else { return true; } } } /** * db_in_clause * Action: builds and returns the "field in(x, y)" clause for database queries * Call: db_in_clause (string field, array values) */ function db_in_clause($field, $values) { return " $field IN ('" . implode("','",escape_string(array_values($values))) . "') "; } // // table_by_key // Action: Return table name for given key // Call: table_by_key (string table_key) // function table_by_key ($table_key) { global $CONF; $table = $CONF['database_prefix'].$CONF['database_tables'][$table_key]; if (empty($table)) $table = $table_key; return $table; } /* Called after a mailbox has been created in the DBMS. Returns: boolean. */ function mailbox_postcreation($username,$domain,$maildir,$quota) { if (empty($username) || empty($domain) || empty($maildir)) { trigger_error('In '.__FUNCTION__.': empty username, domain and/or maildir parameter',E_USER_ERROR); return FALSE; } global $CONF; $confpar='mailbox_postcreation_script'; if (!isset($CONF[$confpar]) || empty($CONF[$confpar])) return TRUE; $cmdarg1=escapeshellarg($username); $cmdarg2=escapeshellarg($domain); $cmdarg3=escapeshellarg($maildir); if ($quota <= 0) $quota = 0; $cmdarg4=escapeshellarg($quota); $command=$CONF[$confpar]." $cmdarg1 $cmdarg2 $cmdarg3 $cmdarg4"; $retval=0; $output=array(); $firstline=''; $firstline=exec($command,$output,$retval); if (0!=$retval) { error_log("Running $command yielded return value=$retval, first line of output=$firstline"); print '

WARNING: Problems running mailbox postcreation script!

'; return FALSE; } return TRUE; } /* Called after a mailbox has been altered in the DBMS. Returns: boolean. */ function mailbox_postedit($username,$domain,$maildir,$quota) { if (empty($username) || empty($domain) || empty($maildir)) { trigger_error('In '.__FUNCTION__.': empty username, domain and/or maildir parameter',E_USER_ERROR); return FALSE; } global $CONF; $confpar='mailbox_postedit_script'; if (!isset($CONF[$confpar]) || empty($CONF[$confpar])) return TRUE; $cmdarg1=escapeshellarg($username); $cmdarg2=escapeshellarg($domain); $cmdarg3=escapeshellarg($maildir); if ($quota <= 0) $quota = 0; $cmdarg4=escapeshellarg($quota); $command=$CONF[$confpar]." $cmdarg1 $cmdarg2 $cmdarg3 $cmdarg4"; $retval=0; $output=array(); $firstline=''; $firstline=exec($command,$output,$retval); if (0!=$retval) { error_log("Running $command yielded return value=$retval, first line of output=$firstline"); print '

WARNING: Problems running mailbox postedit script!

'; return FALSE; } return TRUE; } /* Called after a mailbox has been deleted in the DBMS. Returns: boolean. */ function mailbox_postdeletion($username,$domain) { global $CONF; $confpar='mailbox_postdeletion_script'; if (!isset($CONF[$confpar]) || empty($CONF[$confpar])) { return true; } if (empty($username) || empty($domain)) { print '

Warning: empty username and/or domain parameter.

'; return false; } $cmdarg1=escapeshellarg($username); $cmdarg2=escapeshellarg($domain); $command=$CONF[$confpar]." $cmdarg1 $cmdarg2"; $retval=0; $output=array(); $firstline=''; $firstline=exec($command,$output,$retval); if (0!=$retval) { error_log("Running $command yielded return value=$retval, first line of output=$firstline"); print '

WARNING: Problems running mailbox postdeletion script!

'; return FALSE; } return TRUE; } /* Called after a domain has been added in the DBMS. Returns: boolean. */ function domain_postcreation($domain) { global $CONF; $confpar='domain_postcreation_script'; if (!isset($CONF[$confpar]) || empty($CONF[$confpar])) { return true; } if (empty($domain)) { print '

Warning: empty domain parameter.

'; return false; } $cmdarg1=escapeshellarg($domain); $command=$CONF[$confpar]." $cmdarg1"; $retval=0; $output=array(); $firstline=''; $firstline=exec($command,$output,$retval); if (0!=$retval) { error_log("Running $command yielded return value=$retval, first line of output=$firstline"); print '

WARNING: Problems running domain postcreation script!

'; return FALSE; } return TRUE; } /* Called after a domain has been deleted in the DBMS. Returns: boolean. */ function domain_postdeletion($domain) { global $CONF; $confpar='domain_postdeletion_script'; if (!isset($CONF[$confpar]) || empty($CONF[$confpar])) { return true; } if (empty($domain)) { print '

Warning: empty domain parameter.

'; return false; } $cmdarg1=escapeshellarg($domain); $command=$CONF[$confpar]." $cmdarg1"; $retval=0; $output=array(); $firstline=''; $firstline=exec($command,$output,$retval); if (0!=$retval) { error_log("Running $command yielded return value=$retval, first line of output=$firstline"); print '

WARNING: Problems running domain postdeletion script!

'; return FALSE; } return TRUE; } /* Called after an alias_domain has been deleted in the DBMS. Returns: boolean. */ function alias_domain_postdeletion($alias_domain) { global $CONF; $confpar='alias_domain_postdeletion_script'; if (!isset($CONF[$confpar]) || empty($CONF[$confpar])) { return true; } if (empty($alias_domain)) { print '

Warning: empty alias_domain parameter.

'; return false; } $cmdarg1=escapeshellarg($alias_domain); $command=$CONF[$confpar]." $cmdarg1"; $retval=0; $output=array(); $firstline=''; $firstline=exec($command,$output,$retval); if (0!=$retval) { error_log("Running $command yielded return value=$retval, first line of output=$firstline"); print '

WARNING: Problems running alias_domain postdeletion script!

'; return FALSE; } return TRUE; } /* Called by mailbox_postcreation() after a mailbox has been created. Immediately returns, unless configuration indicates that one or more sub-folders should be created. Triggers E_USER_ERROR if configuration error is detected. If IMAP login fails, the problem is logged to the system log (such as /var/log/httpd/error_log), and the function returns FALSE. Returns FALSE on all other errors, or TRUE if everything succeeds. Doesn't clean up, if only some of the folders could be created. */ function create_mailbox_subfolders($login,$cleartext_password) { global $CONF; if (empty($login)) { trigger_error('In '.__FUNCTION__.': empty $login',E_USER_ERROR); return FALSE; } if (!isset($CONF['create_mailbox_subdirs']) || empty($CONF['create_mailbox_subdirs'])) return TRUE; if (!is_array($CONF['create_mailbox_subdirs'])) { trigger_error('create_mailbox_subdirs must be an array',E_USER_ERROR); return FALSE; } if (!isset($CONF['create_mailbox_subdirs_host']) || empty($CONF['create_mailbox_subdirs_host'])) { trigger_error('An IMAP/POP server host ($CONF["create_mailbox_subdirs_host"]) must be configured, if sub-folders are to be created',E_USER_ERROR); return FALSE; } $s_host=$CONF['create_mailbox_subdirs_host']; $s_prefix=$CONF['create_mailbox_subdirs_prefix']; $s_options=''; $s_port=''; if ( isset($CONF['create_mailbox_subdirs_hostoptions']) && !empty($CONF['create_mailbox_subdirs_hostoptions']) ) { if (!is_array($CONF['create_mailbox_subdirs_hostoptions'])) { trigger_error('The $CONF["create_mailbox_subdirs_hostoptions"] parameter must be an array',E_USER_ERROR); return FALSE; } foreach ($CONF['create_mailbox_subdirs_hostoptions'] as $o) { $s_options.='/'.$o; } } if (isset($CONF['create_mailbox_subdirs_hostport']) && !empty($CONF['create_mailbox_subdirs_hostport'])) { $s_port=$CONF['create_mailbox_subdirs_hostport']; if (intval($s_port)!=$s_port) { trigger_error('The $CONF["create_mailbox_subdirs_hostport"] parameter must be an integer',E_USER_ERROR); return FALSE; } $s_port=':'.$s_port; } $s='{'.$s_host.$s_port.$s_options.'}'; sleep(1); # give the mail triggering the mailbox creation a chance to do its job $i=@imap_open($s,$login,$cleartext_password); if (FALSE==$i) { error_log('Could not log into IMAP/POP server: '.imap_last_error()); return FALSE; } foreach($CONF['create_mailbox_subdirs'] as $f) { $f='{'.$s_host.'}'.$s_prefix.$f; $res=imap_createmailbox($i,$f); if (!$res) { error_log('Could not create IMAP folder $f: '.imap_last_error()); @imap_close($i); return FALSE; } @imap_subscribe($i,$f); } @imap_close($i); return TRUE; } // // gen_show_status // Action: Return a string of colored  's that indicate // the if an alias goto has an error or is sent to // addresses list in show_custom_domains // Call: gen_show_status (string alias_address) // function gen_show_status ($show_alias) { global $CONF, $table_alias; $stat_string = ""; $show_alias = escape_string($show_alias); $stat_goto = ""; $stat_result = db_query ("SELECT goto FROM $table_alias WHERE address='$show_alias'"); if ($stat_result['rows'] > 0) { $row = db_row ($stat_result['result']); $stat_goto = $row[0]; } // UNDELIVERABLE CHECK if ( $CONF['show_undeliverable'] == 'YES' ) { $gotos=array(); $gotos=explode(',',$stat_goto); $undel_string=""; //make sure this alias goes somewhere known $stat_ok = 1; while ( ($g=array_pop($gotos)) && $stat_ok ) { $stat_catchall = substr($g,strpos($g,"@")); $stat_delimiter = ""; if (!empty($CONF['recipient_delimiter'])) { $delimiter = preg_quote($CONF['recipient_delimiter'], "/"); $stat_delimiter = preg_replace('/' .$delimiter. '[^' .$delimiter. ']*@/', "@", $g); $stat_delimiter = "OR address = '$stat_delimiter'"; } $stat_result = db_query ("SELECT address FROM $table_alias WHERE address = '$g' OR address = '$stat_catchall' $stat_delimiter"); if ($stat_result['rows'] == 0) { $stat_ok = 0; } if ( $stat_ok == 0 ) { $stat_domain = substr($g,strpos($g,"@")+1); $stat_vacdomain = substr($stat_domain,strpos($stat_domain,"@")+1); if ( $stat_vacdomain == $CONF['vacation_domain'] ) { $stat_ok = 1; break; } for ($i=0; $i < sizeof($CONF['show_undeliverable_exceptions']);$i++) { if ( $stat_domain == $CONF['show_undeliverable_exceptions'][$i] ) { $stat_ok = 1; break; } } } } // while if ( $stat_ok == 0 ) { $stat_string .= "" . $CONF['show_status_text'] . " "; } else { $stat_string .= $CONF['show_status_text'] . " "; } } else { $stat_string .= $CONF['show_status_text'] . " "; } // POP/IMAP CHECK if ( $CONF['show_popimap'] == 'YES' ) { $stat_delimiter = ""; if (!empty($CONF['recipient_delimiter'])) { $delimiter = preg_quote($CONF['recipient_delimiter'], "/"); $stat_delimiter = preg_replace('/' .$delimiter. '[^' .$delimiter. '@]*@/', "@", $stat_goto); $stat_delimiter = ',' . $stat_delimiter; } //if the address passed in appears in its own goto field, its POP/IMAP if ( preg_match ('/,' . $show_alias . ',/', ',' . $stat_goto . $stat_delimiter . ',') ) { $stat_string .= "" . $CONF['show_status_text'] . " "; } else { $stat_string .= $CONF['show_status_text'] . " "; } } // CUSTOM DESTINATION CHECK if ( count($CONF['show_custom_domains']) > 0 ) { for ($i = 0; $i < sizeof ($CONF['show_custom_domains']); $i++) { if (preg_match ('/^.*' . $CONF['show_custom_domains'][$i] . '.*$/', $stat_goto)) { $stat_string .= "" . $CONF['show_status_text'] . " "; } else { $stat_string .= $CONF['show_status_text'] . " "; } } } else { $stat_string .= "; "; } // $stat_string .= "    " . // "    "; return $stat_string; } /* Called by create-admin.php and setup.php Returns: array( 'error' => 0, # 0 on success, otherwise > 0 'tMessage' => '', # success / failure message 'pAdminCreate_admin_username_text' => '', # help text / error message for username 'pAdminCreate_admin_password_text' => '' # error message for username ) */ function create_admin($fUsername, $fPassword, $fPassword2, $fDomains, $no_generate_password=0) { global $PALANG; global $CONF; $error = 0; $tMessage = ''; $pAdminCreate_admin_username_text = ''; $pAdminCreate_admin_password_text = ''; if (!check_email ($fUsername)) { $error = 1; $pAdminCreate_admin_username_text = $PALANG['pAdminCreate_admin_username_text_error1']; } if (empty ($fUsername) or admin_exist ($fUsername)) { $error = 1; $pAdminCreate_admin_username_text = $PALANG['pAdminCreate_admin_username_text_error2']; } if (empty ($fPassword) or empty ($fPassword2) or ($fPassword != $fPassword2)) { if (empty ($fPassword) and empty ($fPassword2) and $CONF['generate_password'] == "YES" && $no_generate_password == 0) { $fPassword = generate_password (); } else { $error = 1; $pAdminCreate_admin_username_text = $PALANG['pAdminCreate_admin_username_text']; $pAdminCreate_admin_password_text = $PALANG['pAdminCreate_admin_password_text_error']; } } if ($error != 1) { $password = pacrypt($fPassword); $pAdminCreate_admin_username_text = $PALANG['pAdminCreate_admin_username_text']; $result = db_query ("INSERT INTO " . table_by_key('admin') . " (username,password,created,modified) VALUES ('$fUsername','$password',NOW(),NOW())"); if ($result['rows'] != 1) { $tMessage = $PALANG['pAdminCreate_admin_result_error'] . "
($fUsername)
"; } else { if (!empty ($fDomains[0])) { for ($i = 0; $i < sizeof ($fDomains); $i++) { $domain = escape_string($fDomains[$i]); $result = db_query ("INSERT INTO " . table_by_key ('domain_admins') . " (username,domain,created) VALUES ('$fUsername','$domain',NOW())"); } } $tMessage = $PALANG['pAdminCreate_admin_result_success'] . "
($fUsername"; if ($CONF['generate_password'] == "YES" && $no_generate_password == 0) { $tMessage .= " / $fPassword)
"; } else { if ($CONF['show_password'] == "YES" && $no_generate_password == 0) { $tMessage .= " / $fPassword)
"; } else { $tMessage .= ")
"; } } } } # TODO: should we log creation, editing and deletion of admins? # Note: needs special handling in viewlog, because domain is empty # db_log ($SESSID_USERNAME, '', 'create_admin', "$fUsername"); return array( $error, $tMessage, $pAdminCreate_admin_username_text, $pAdminCreate_admin_password_text ); } /* Convert $CONF['whatever'] to boolean (obviously only useful for settings that can be YES or NO) Returns: TRUE (on YES/yes) or FALSE (on NO/no/not set/unknown value) */ function boolconf($setting) { global $CONF; if (!isset($CONF[$setting])) { # not set # TODO: show/log error message on unknown settings? return false; } elseif (strtoupper($CONF[$setting]) == 'YES') { # YES return true; } else { # NO, unknown value # TODO: show/log error message on unknown value? return false; } } $table_admin = table_by_key ('admin'); $table_alias = table_by_key ('alias'); $table_alias_domain = table_by_key ('alias_domain'); $table_domain = table_by_key ('domain'); $table_domain_admins = table_by_key ('domain_admins'); $table_log = table_by_key ('log'); $table_mailbox = table_by_key ('mailbox'); $table_vacation = table_by_key ('vacation'); $table_vacation_notification = table_by_key('vacation_notification'); $table_quota = table_by_key ('quota'); $table_quota2 = table_by_key ('quota2'); /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ postfixadmin-2.3.7/viewlog.php0000664000175000017620000000435211374073727016463 0ustar davidpalepurple 0)) $fDomain = $list_domains[0]; } elseif ($_SERVER['REQUEST_METHOD'] == "POST") { if (isset ($_POST['fDomain'])) $fDomain = escape_string ($_POST['fDomain']); } else { die('Unknown request method'); } if (! (check_owner ($SESSID_USERNAME, $fDomain) || authentication_has_role('global-admin'))) { $error = 1; $tMessage = $PALANG['pViewlog_result_error']; } // we need to initialize $tLog as an array! $tLog = array(); if ($error != 1) { $query = "SELECT timestamp,username,domain,action,data FROM $table_log WHERE domain='$fDomain' ORDER BY timestamp DESC LIMIT 10"; if ('pgsql'==$CONF['database_type']) { $query = "SELECT extract(epoch from timestamp) as timestamp,username,domain,action,data FROM $table_log WHERE domain='$fDomain' ORDER BY timestamp DESC LIMIT 10"; } $result=db_query($query); if ($result['rows'] > 0) { while ($row = db_array ($result['result'])) { if ('pgsql'==$CONF['database_type']) { $row['timestamp']=gmstrftime('%c %Z',$row['timestamp']); } $tLog[] = $row; } } } include ("templates/header.php"); include ("templates/menu.php"); include ("templates/viewlog.php"); include ("templates/footer.php"); /* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/logout.php0000664000175000017620000000132211146027202016272 0ustar davidpalepurple postfixadmin-2.3.7/create-alias.php0000664000175000017620000001366311703401073017327 0ustar davidpalepurple"; $tMessage .= $PALANG['pEdit_alias_goto_text_error2'] . htmlentities($address) . "
"; } } $goto = implode(',', $new_aliases); $fGoto = escape_string($goto); // End check alias mail if (empty($fGoto)) { $error = 1; $tAddress = escape_string ($_POST['fAddress']); $tGoto = $fGoto; $tDomain = $fDomain; $pCreate_alias_goto_text = $PALANG['pCreate_alias_goto_text_error']; } if (escape_string($_POST['fAddress']) == "*") { $fAddress = "@" . escape_string ($_POST['fDomain']); } $result = db_query ("SELECT * FROM $table_alias WHERE address='$fAddress'"); if ($result['rows'] == 1) { $error = 1; $tAddress = escape_string ($_POST['fAddress']); $tGoto = $fGoto; $tDomain = $fDomain; $pCreate_alias_address_text = $PALANG['pCreate_alias_address_text_error2']; } if ($fActive == "on") { $sqlActive = db_get_boolean(True); } else { $sqlActive = db_get_boolean(False); } if ($error != 1) { if (preg_match('/^\*@(.*)$/', $fGoto, $match)) { $fGoto = "@" . $match[1]; } $result = db_query ("INSERT INTO $table_alias (address,goto,domain,created,modified,active) VALUES ('$fAddress','$fGoto','$fDomain',NOW(),NOW(),'$sqlActive')"); if ($result['rows'] != 1) { $tDomain = $fDomain; $tMessage = $PALANG['pCreate_alias_result_error'] . "
($fAddress -> $fGoto)
\n"; } else { db_log ($SESSID_USERNAME, $fDomain, 'create_alias', "$fAddress -> $fGoto"); $tDomain = $fDomain; $tMessage = $PALANG['pCreate_alias_result_success'] . "
($fAddress -> $fGoto)
\n"; } } else { # on error $tAddress = htmlentities($_POST['fAddress']); $tGoto = htmlentities($_POST['fGoto']); $tDomain = htmlentities($_POST['fDomain']); } } include ("templates/header.php"); include ("templates/menu.php"); include ("templates/create-alias.php"); include ("templates/footer.php"); /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ ?> postfixadmin-2.3.7/create-mailbox.php0000664000175000017620000002154512264551556017706 0ustar davidpalepurple($fUsername -> $fUsername)
"; } // apparently uppercase usernames really confuse some IMAP clients. $fUsername = strtolower($fUsername); $local_part = ''; if(preg_match('/^(.*)@/', $fUsername, $matches)) { $local_part = $matches[1]; } $result = db_query ("INSERT INTO $table_mailbox (username,password,name,maildir,local_part,quota,domain,created,modified,active) VALUES ('$fUsername','$password','$fName','$maildir','$local_part','$quota','$fDomain',NOW(),NOW(),'$sqlActive')"); if ($result['rows'] != 1 || !mailbox_postcreation($fUsername,$fDomain,$maildir, $quota)) { $tDomain = $fDomain; $tMessage .= $PALANG['pCreate_mailbox_result_error'] . "
($fUsername)
"; db_query('ROLLBACK'); } else { db_query('COMMIT'); db_log ($SESSID_USERNAME, $fDomain, 'create_mailbox', "$fUsername"); $tDomain = $fDomain; $tQuota = $CONF['maxquota']; if ($fMail == "on") { $fTo = $fUsername; $fFrom = $SESSID_USERNAME; $fHeaders = "To: " . $fTo . "\n"; $fHeaders .= "From: " . $fFrom . "\n"; $fHeaders .= "Subject: " . encode_header ($PALANG['pSendmail_subject_text']) . "\n"; $fHeaders .= "MIME-Version: 1.0\n"; $fHeaders .= "Content-Type: text/plain; charset=utf-8\n"; $fHeaders .= "Content-Transfer-Encoding: 8bit\n"; $fHeaders .= $CONF['welcome_text']; if (!smtp_mail ($fTo, $fFrom, $fHeaders)) { $tMessage .= "
" . $PALANG['pSendmail_result_error'] . "
"; } else { $tMessage .= "
" . $PALANG['pSendmail_result_success'] . "
"; } } $tShowpass = ""; if ( $tPassGenerated == 1 || $CONF['show_password'] == "YES") $tShowpass = " / $fPassword"; if (create_mailbox_subfolders($fUsername,$fPassword)) { $tMessage .= $PALANG['pCreate_mailbox_result_success'] . "
($fUsername$tShowpass)"; } else { $tMessage .= $PALANG['pCreate_mailbox_result_succes_nosubfolders'] . "
($fUsername$tShowpass)"; } } } } include ("templates/header.php"); include ("templates/menu.php"); include ("templates/create-mailbox.php"); include ("templates/footer.php"); /* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/templates/0000775000175000017620000000000012301477471016263 5ustar davidpalepurplepostfixadmin-2.3.7/templates/broadcast-message.php0000664000175000017620000000233010724603034022347 0ustar davidpalepurple

'.$PALANG['pBroadcast_error_empty'].'

' ; } ?>
postfixadmin-2.3.7/templates/users_main.php0000664000175000017620000000200310724603034021125 0ustar davidpalepurple postfixadmin-2.3.7/templates/edit-alias.php0000664000175000017620000000160311505376253021011 0ustar davidpalepurple

 
 
postfixadmin-2.3.7/templates/create-alias-domain.php0000664000175000017620000000357011043164227022572 0ustar davidpalepurple
0) { ?> 0) { ?>

/>  
'; } print $tMessage; if ($error) { print ''; } ?>
postfixadmin-2.3.7/templates/users_menu.php0000664000175000017620000000154710724603034021161 0ustar davidpalepurple

\n"; include ("../motd-users.txt"); print ""; } ?> postfixadmin-2.3.7/templates/message.php0000664000175000017620000000016110724603034020407 0ustar davidpalepurple postfixadmin-2.3.7/templates/edit-vacation.php0000664000175000017620000000310611703114423021511 0ustar davidpalepurple

 
 
 
postfixadmin-2.3.7/templates/viewlog.php0000664000175000017620000000434110724603034020443 0ustar davidpalepurple
0) { print "\n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; for ($i = 0; $i < sizeof ($tLog); $i++) { if ((is_array ($tLog) and sizeof ($tLog) > 0)) { $log_data = $tLog[$i]['data']; $data_length = strlen ($log_data); if ($data_length > 35) $log_data = substr ($log_data, 0, 35) . " ..."; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; } } print "

".$PALANG['pViewlog_welcome']." ".$fDomain."

" . $PALANG['pViewlog_timestamp'] . "" . $PALANG['pViewlog_username'] . "" . $PALANG['pViewlog_domain'] . "" . $PALANG['pViewlog_action'] . "" . $PALANG['pViewlog_data'] . "
" . $tLog[$i]['timestamp'] . "" . $tLog[$i]['username'] . "" . $tLog[$i]['domain'] . "" . $PALANG['pViewlog_action_'.$tLog[$i]['action'] ] . "" . $log_data . "
\n"; } ?> postfixadmin-2.3.7/templates/users_vacation.php0000664000175000017620000000254710735267175022040 0ustar davidpalepurple

 
 
postfixadmin-2.3.7/templates/create-alias.php0000664000175000017620000000332411505375604021330 0ustar davidpalepurple

@
 
postfixadmin-2.3.7/templates/create-mailbox.php0000664000175000017620000000535211266724441021676 0ustar davidpalepurple " . $PALANG['pAdminMenu_list_virtual'] . ""; } ?>

@
 
 
 
postfixadmin-2.3.7/templates/users_login.php0000664000175000017620000000210311772403007021314 0ustar davidpalepurple

postfixadmin-2.3.7/templates/admin_edit-domain.php0000664000175000017620000000613011121546044022326 0ustar davidpalepurple

 
 
/>  
/>  
postfixadmin-2.3.7/templates/password.php0000664000175000017620000000246210724603034020633 0ustar davidpalepurple

 
postfixadmin-2.3.7/templates/login.php0000664000175000017620000000232411772403007020100 0ustar davidpalepurple

postfixadmin-2.3.7/templates/header.php0000664000175000017620000000406311146027202020214 0ustar davidpalepurple \n"; } else { print "\n"; } ?> Postfix Admin - <?php print $_SERVER['HTTP_HOST']; ?>
\n"; } else { print "\n"; } if (($CONF['show_header_text'] == "YES") and ($CONF['header_text'])) { print "

" . $CONF['header_text'] . "

\n"; } ?>
'; foreach($_SESSION['flash']['info'] as $msg) { echo "
  • $msg
  • "; } echo ''; } if(isset($_SESSION['flash']['error'])) { echo '
      '; foreach($_SESSION['flash']['error'] as $msg) { echo "
    • $msg
    • "; } echo '
    '; } /* nuke it from orbit. It's the only way to be sure. */ $_SESSION['flash'] = array(); } /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ ?> postfixadmin-2.3.7/templates/users_edit-alias.php0000664000175000017620000000325211156543362022233 0ustar davidpalepurple

     
     
      />
    />
    postfixadmin-2.3.7/templates/admin_list-admin.php0000664000175000017620000000377110724603034022206 0ustar davidpalepurple 0) { print "\n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; for ($i = 0; $i < sizeof ($list_admins); $i++) { if ((is_array ($list_admins) and sizeof ($list_admins) > 0)) { print " \n"; print " "; if ($admin_properties[$i]['domain_count'] == 'ALL') $admin_properties[$i]['domain_count'] = $PALANG['pAdminEdit_admin_super_admin']; print " "; print " "; $active = ($admin_properties[$i]['active'] == 1) ? $PALANG['YES'] : $PALANG['NO']; print " "; print " "; print " "; print " \n"; } } print "
    " . $PALANG['pAdminList_admin_username'] . "" . $PALANG['pAdminList_admin_count'] . "" . $PALANG['pAdminList_admin_modified'] . "" . $PALANG['pAdminList_admin_active'] . " 
    " . $list_admins[$i] . "" . $admin_properties[$i]['domain_count'] . "" . $admin_properties[$i]['modified'] . "" . $active . "" . $PALANG['edit'] . "" . $PALANG['del'] . "
    \n"; print "

    " . $PALANG['pAdminMenu_create_admin'] . "\n"; } /* vim: set ft=php expandtab softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/templates/footer.php0000664000175000017620000000144011770676341020277 0ustar davidpalepurple

    postfixadmin-2.3.7/templates/main.php0000664000175000017620000000266711306601262017722 0ustar davidpalepurple postfixadmin-2.3.7/templates/menu.php0000664000175000017620000000724711703061220017734 0ustar davidpalepurple
  • $title$submenu
  • "; return "
  • $title$submenu
  • "; } authentication_has_role('global-admin'); echo "\n"; print "

    "; # TODO if (authentication_has_role('global-admin')) { $motd_file = "motd-admin.txt"; } else { $motd_file = "motd.txt"; } if (file_exists (realpath ($motd_file))) { print "
    \n"; include ($motd_file); print "
    "; } # IE can't handle :hover dropdowns correctly. It needs some JS instead. ?> postfixadmin-2.3.7/templates/overview-get.php0000664000175000017620000000510310724603034021407 0ustar davidpalepurple
    \n"; print " \n"; print "

    ".$PALANG['pOverview_title']."

    "; print " "; print " \n"; print " " . $PALANG['pOverview_get_domain'] . "\n"; print " " . $PALANG['pOverview_get_aliases'] . "\n"; print " " . $PALANG['pOverview_get_mailboxes'] . "\n"; if ($CONF['quota'] == 'YES') print " " . $PALANG['pOverview_get_quota'] . "\n"; print " \n"; for ($i = 0; $i < sizeof ($list_domains); $i++) { if ((is_array ($list_domains) and sizeof ($list_domains) > 0)) { $limit = get_domain_properties ($list_domains[$i]); if ($limit['aliases'] == 0) $limit['aliases'] = $PALANG['pOverview_unlimited']; if ($limit['mailboxes'] == 0) $limit['mailboxes'] = $PALANG['pOverview_unlimited']; if ($limit['maxquota'] == 0) $limit['maxquota'] = $PALANG['pOverview_unlimited']; if ($limit['aliases'] < 0) $limit['aliases'] = $PALANG['pOverview_disabled']; if ($limit['mailboxes'] < 0) $limit['mailboxes'] = $PALANG['pOverview_disabled']; if ($limit['maxquota'] < 0) $limit['maxquota'] = $PALANG['pOverview_disabled']; print " \n"; print " " . $list_domains[$i] . "\n"; print " " . $limit['alias_count'] . " / " . $limit['aliases'] . "\n"; print " " . $limit['mailbox_count'] . " / " . $limit['mailboxes'] . "\n"; if ($CONF['quota'] == 'YES') print " " . $limit['maxquota'] . "\n"; print " \n"; } } print "\n"; ?> postfixadmin-2.3.7/templates/admin_create-admin.php0000664000175000017620000000352410724603034022472 0ustar davidpalepurple

     
     
    postfixadmin-2.3.7/templates/sendmail.php0000664000175000017620000000243110724603034020561 0ustar davidpalepurple

     
     
     
     
    postfixadmin-2.3.7/templates/admin_list-domain.php0000664000175000017620000001016511712564312022363 0ustar davidpalepurple
    0) { print "\n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; if ($CONF['quota'] == 'YES') print " \n"; if ($CONF['transport'] == 'YES') print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; # for ($i = 0; $i < sizeof ($domain_properties); $i++) foreach(array_keys($domain_properties) as $i) { if ((is_array ($domain_properties) and sizeof ($domain_properties) > 0)) { print " \n"; print ""; print ""; print ""; print ""; if ($CONF['quota'] == 'YES') { print " \n"; } if ($CONF['transport'] == 'YES') print ""; $backupmx = ($domain_properties[$i]['backupmx'] == db_get_boolean(true)) ? $PALANG['YES'] : $PALANG['NO']; print ""; print ""; $active = ($domain_properties[$i]['active'] == db_get_boolean(true)) ? $PALANG['YES'] : $PALANG['NO']; print ""; print ""; print ""; print "\n"; } } print "
    " . $PALANG['pAdminList_domain_domain'] . "" . $PALANG['pAdminList_domain_description'] . "" . $PALANG['pAdminList_domain_aliases'] . "" . $PALANG['pAdminList_domain_mailboxes'] . "" . $PALANG['pAdminList_domain_maxquota'] . "" . $PALANG['pAdminList_domain_transport'] . "" . $PALANG['pAdminList_domain_backupmx'] . "" . $PALANG['pAdminList_domain_modified'] . "" . $PALANG['pAdminList_domain_active'] . " 
    " . $domain_properties[$i]['domain'] . "" . htmlentities($domain_properties[$i]['description'], ENT_QUOTES, 'UTF-8') . "" . $domain_properties[$i]['alias_count'] . " / " . $domain_properties[$i]['aliases'] . "" . $domain_properties[$i]['mailbox_count'] . " / " . $domain_properties[$i]['mailboxes'] . ""; if ($domain_properties[$i]['maxquota'] == 0) { print $PALANG['pOverview_unlimited']; } elseif ($domain_properties[$i]['maxquota'] < 0) { print $PALANG['pOverview_disabled']; } else { print $domain_properties[$i]['maxquota']; } print "" . $domain_properties[$i]['transport'] . "$backupmx" . $domain_properties[$i]['modified'] . "" . $active . "" . $PALANG['edit'] . "" . $PALANG['del'] . "
    \n"; } echo "

    {$PALANG['pAdminMenu_create_domain']}"; ?> postfixadmin-2.3.7/templates/admin_create-domain.php0000664000175000017620000000652111703111761022650 0ustar davidpalepurple

     
    />
    />  
    postfixadmin-2.3.7/templates/admin_edit-admin.php0000664000175000017620000000400510724603034022147 0ustar davidpalepurple

    :  
    :
    :  
    : />  
    : />  
    postfixadmin-2.3.7/templates/search.php0000664000175000017620000002215211230654312020232 0ustar davidpalepurple
    '; print '

    :
    0) { print "\n"; print " \n"; print " "; print " "; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; for ($i = 0; $i < sizeof ($tAlias); $i++) { if ((is_array ($tAlias) and sizeof ($tAlias) > 0)) { print " \n"; //highlight search string $tAlias[$i]['display_address'] = $tAlias[$i]['address']; if ($fSearch != "" && stristr($tAlias[$i]['display_address'],$fSearch)) { $new_address = str_ireplace($fSearch, "" . $fSearch . "", $tAlias[$i]['display_address']); $tAlias[$i]['display_address'] = $new_address; } print " \n"; if ($fSearch != "" && stristr($tAlias[$i]['goto'],$fSearch)) { $new_goto = str_ireplace($fSearch, "" . $fSearch . "", $tAlias[$i]['goto']); $tAlias[$i]['goto'] = $new_goto; } print " \n"; print " \n"; if ($CONF['special_alias_control'] == 'YES' || authentication_has_role('global-admin')) { $active = ($tAlias[$i]['active'] == 1) ? $PALANG['YES'] : $PALANG['NO']; print " \n"; print " \n"; print " \n"; } else { if (check_alias_owner ($SESSID_USERNAME, $tAlias[$i]['address'])) { $active = ($tAlias[$i]['active'] == 1) ? $PALANG['YES'] : $PALANG['NO']; print " \n"; print " \n"; print " \n"; } else { print " \n"; print " \n"; } } print " \n"; } } print "

    ".$PALANG['pOverview_alias_title']."

    " . $PALANG['pOverview_alias_address'] . "" . $PALANG['pOverview_alias_goto'] . "" . $PALANG['pOverview_alias_modified'] . "" . $PALANG['pOverview_alias_active'] . " 
    " . $tAlias[$i]['display_address'] . "" . preg_replace ("/,/", "
    ", $tAlias[$i]['goto']) . "
    " . $tAlias[$i]['modified'] . "" . $active . "" . $PALANG['edit'] . "" . $PALANG['del'] . "" . $active . "" . $PALANG['edit'] . "" . $PALANG['del'] . "  
    \n"; } if (sizeof ($tMailbox) > 0) { print "\n"; print " \n"; print " "; print " "; print " \n"; print " \n"; print " \n"; if ($CONF['quota'] == 'YES') print " \n"; print " \n"; print " \n"; print " \n"; $colspan=2; if ($CONF['vacation_control_admin'] == 'YES') $colspan=$colspan+1; if ($CONF['alias_control_admin'] == 'YES') $colspan=$colspan+1; if (authentication_has_role('global-admin') && $CONF['alias_control'] == 'YES') { $colspan = 3; } print " \n"; print " \n"; for ($i = 0; $i < sizeof ($tMailbox); $i++) { if ((is_array ($tMailbox) and sizeof ($tMailbox) > 0)) { print " \n"; $tMailbox[$i]['display_username'] = $tMailbox[$i]['username']; if ($fSearch != "" && stristr($tMailbox[$i]['display_username'],$fSearch)) { $new_name = str_ireplace($fSearch, "" . $fSearch . "", $tMailbox[$i]['display_username']); $tMailbox[$i]['display_username'] = $new_name; } print " \n"; if ($fSearch != "" && stristr($tMailbox[$i]['name'],$fSearch)) { $new_name = str_ireplace($fSearch, "" . $fSearch . "", $tMailbox[$i]['name']); $tMailbox[$i]['name'] = $new_name; } print " \n"; if ($CONF['quota'] == 'YES') print " \n"; print " \n"; $active = ($tMailbox[$i]['active'] == 1) ? $PALANG['YES'] : $PALANG['NO']; print " \n"; $has_alias_control = 0; # temporary variable to simplify admin vs. superadmin code if (authentication_has_role('global-admin')) { if ($CONF['alias_control'] == 'YES') $has_alias_control = 1; } else { if ($CONF['alias_control_admin'] == 'YES') $has_alias_control = 1; } if ($CONF['vacation_control_admin'] == 'YES') { $v_active = ($tMailbox[$i]['v_active'] == 1) ? $PALANG['pOverview_vacation_edit'] : $PALANG['pOverview_vacation_option']; print " \n"; } if ($has_alias_control == 1) { print " \n"; } print " \n"; print " \n"; print " \n"; } } print "

    ".$PALANG['pOverview_mailbox_title']."

    " . $PALANG['pOverview_mailbox_username'] . "" . $PALANG['pOverview_mailbox_name'] . "" . $PALANG['pOverview_mailbox_quota'] . "" . $PALANG['pOverview_mailbox_modified'] . "" . $PALANG['pOverview_mailbox_active'] . "  
    " . $tMailbox[$i]['display_username'] . "" . $tMailbox[$i]['name'] . "" . divide_quota ($tMailbox[$i]['quota']) . "" . $tMailbox[$i]['modified'] . "" . $active . "" . $v_active . "" . $PALANG['pOverview_alias_edit'] . "" . $PALANG['edit'] . "" . $PALANG['del'] . "
    \n"; } # vim: ts=3 expandtab ft=php ?> postfixadmin-2.3.7/templates/list-virtual.php0000664000175000017620000005123011712564312021430 0ustar davidpalepurple

    :
    \n"; if (boolconf('alias_domain')) { # XXX: the following block misses one intention level if ((sizeof ($tAliasDomains) > 0) || (is_array ($tTargetDomain) )) { print "\n"; print " \n"; print " "; print " "; if(sizeof ($tAliasDomains) > 0) { print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; for ($i = 0; $i < sizeof ($tAliasDomains); $i++) { print " \n"; print " \n"; print " \n"; $active = ($tAliasDomains[$i]['active'] == 1) ? $PALANG['YES'] : $PALANG['NO']; # TODO: change all edit-*.php scripts not to require the domain parameter (and extract it from the address). This avoids superflous problems when using search. print " \n"; print " \n"; print " \n"; } } if(is_array($tTargetDomain)) { print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; $active = ($tTargetDomain['active'] == 1) ? $PALANG['YES'] : $PALANG['NO']; print " \n"; print " \n"; print " \n"; } print "

    " . $PALANG['pOverview_alias_domain_title'] . "

    " . sprintf($PALANG['pOverview_alias_domain_aliases'], $fDomain) . "" . $PALANG['pOverview_alias_domain_modified'] . "" . $PALANG['pOverview_alias_domain_active'] . " 
    " . $tAliasDomains[$i]['alias_domain'] . "" . $tAliasDomains[$i]['modified'] . "" . $active . "" . $PALANG['del'] . "
    " . sprintf($PALANG['pOverview_alias_domain_target'], $fDomain) . "" . $PALANG['pOverview_alias_domain_modified'] . "" . $PALANG['pOverview_alias_domain_active'] . " 
    " . $tTargetDomain['target_domain'] . "" . $tTargetDomain['modified'] . "" . $active . "" . $PALANG['del'] . "
    \n"; } # XXX: the above block misses one intention level if (!is_array($tTargetDomain)) { # TODO: don't print create link if no domains are left for aliasing print "

    " . $PALANG['pMenu_create_alias_domain'] . "\n"; } } if (sizeof ($tAlias) > 0) { print "\n"; print " \n"; print " "; print " "; print " \n"; if ($CONF['show_status'] == 'YES') { print "\n"; } print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; for ($i = 0; $i < sizeof ($tAlias); $i++) { if ((is_array ($tAlias) and sizeof ($tAlias) > 0)) { print " \n"; if ($CONF['show_status'] == 'YES') { print " \n"; } print " \n"; if ($CONF['alias_goto_limit'] > 0) { print " \n"; } else { print " \n"; } print " \n"; # TODO: merge superadmin / domain admin code if (authentication_has_role('global-admin')) { # superadmin code $active = ($tAlias[$i]['active'] == 1) ? $PALANG['YES'] : $PALANG['NO']; print " \n"; print " \n"; print " \n"; } else { # domain admin code if ($CONF['special_alias_control'] == 'YES') { $active = ($tAlias[$i]['active'] == 1) ? $PALANG['YES'] : $PALANG['NO']; print " \n"; print " \n"; print " \n"; } else { if ( check_alias_owner ($SESSID_USERNAME, $tAlias[$i]['address'])) { $active = ($tAlias[$i]['active'] == 1) ? $PALANG['YES'] : $PALANG['NO']; print " \n"; print " \n"; print " \n"; } else { //this is a special alias, show status only, don't allow changes $active = ($tAlias[$i]['active'] == 1) ? $PALANG['YES'] : $PALANG['NO']; print " \n"; print " \n"; print " \n"; } } # end diff } print " \n"; } } print "

    " . $PALANG['pOverview_alias_title'] . "

    " . $PALANG['pOverview_alias_address'] . "" . $PALANG['pOverview_alias_goto'] . "" . $PALANG['pOverview_alias_modified'] . "" . $PALANG['pOverview_alias_active'] . " 
    " . gen_show_status($tAlias[$i]['address']) . "" . searchhl($tAlias[$i]['address']) . "" . searchhl(preg_replace ( "/,/", "
    ", preg_replace( '/^(([^,]+,){'.$CONF['alias_goto_limit'].'})[^,]+,.*/', '$1' . sprintf( $PALANG['and_x_more'], (substr_count ($tAlias[$i]['goto'], ',') - $CONF['alias_goto_limit'] + 1) ), $tAlias[$i]['goto'] ) )) . "
    " . searchhl(preg_replace ("/,/", "
    ", $tAlias[$i]['goto'])) . "
    " . $tAlias[$i]['modified'] . "" . $active . "" . $PALANG['edit'] . "" . $PALANG['del'] . "" . $active . "" . $PALANG['edit'] . "" . $PALANG['del'] . "" . $active . "" . $PALANG['edit'] . "" . $PALANG['del'] . "" . $active . "  
    \n"; } if($tCanAddAlias) { print "

    " . $PALANG['pMenu_create_alias'] . "\n"; } if (sizeof ($tMailbox) > 0) { print "

    \n
    "; if ( $limit['mbox_pgindex_count'] ) print "".$PALANG['pOverview_mailbox_title']."  "; ($tDisplay_back_show == 1) ? $highlight_at = $tDisplay_back / $CONF['page_size'] + 1 : $highlight_at = 0; for ($i = 0; $i < $limit['mbox_pgindex_count']; $i++) { if ( $i == $highlight_at ) { print "" . $limit['mbox_pgindex'][$i] . "\n"; } else { print "" . $limit['mbox_pgindex'][$i] . "\n"; } } print ""; if ($tDisplay_back_show == 1) { print "\""\n"; } if ($tDisplay_up_show == 1) { print "\""\n"; } if ($tDisplay_next_show == 1) { print "\""\n"; } print "
    \n"; $colspan=8; if ($CONF['vacation_control_admin'] == 'YES') $colspan=$colspan+1; if ($CONF['alias_control_admin'] == 'YES') $colspan=$colspan+1; if ($display_mailbox_aliases) $colspan=$colspan+1; print "\n"; print " \n"; print " "; print " "; print " \n"; if ($CONF['show_status'] == 'YES') { print "\n"; } print " \n"; if ($display_mailbox_aliases) print " \n"; print " \n"; if ($CONF['quota'] == 'YES') print " \n"; print " \n"; print " \n"; $colspan = $colspan - 6; print " \n"; print " \n"; for ($i = 0; $i < sizeof ($tMailbox); $i++) { if ((is_array ($tMailbox) and sizeof ($tMailbox) > 0)) { print " \n"; if ($CONF['show_status'] == 'YES') { print " \n"; } print " \n"; if ($display_mailbox_aliases) { # print " \n"; print " \n"; } print " \n"; if ($CONF['quota'] == 'YES') { print " \n"; } print " \n"; $active = ($tMailbox[$i]['active'] == 1) ? $PALANG['YES'] : $PALANG['NO']; print " \n"; if ($CONF['vacation_control_admin'] == 'YES' && $CONF['vacation'] == 'YES') { $v_active_int = $tMailbox[$i]['v_active']; if($v_active_int !== -1) { if($v_active_int == 1) { $v_active = $PALANG['pOverview_vacation_edit']; } else { $v_active = $PALANG['pOverview_vacation_option']; } print "\n"; } else { // can't tell vacation state - broken pgsql query echo "\n"; } } $edit_aliases=0; if ( (! authentication_has_role('global-admin')) && $CONF['alias_control_admin'] == 'YES') $edit_aliases = 1; if ( authentication_has_role('global-admin') && $CONF['alias_control'] == 'YES') $edit_aliases = 1; if ($edit_aliases == 1) { print " \n"; } print " \n"; print " \n"; print " \n"; } } print "

    " . $PALANG['pOverview_mailbox_title'] . "

    " . $PALANG['pOverview_mailbox_username'] . "" . $PALANG['pOverview_alias_goto'] . "" . $PALANG['pOverview_mailbox_name'] . "" . $PALANG['pOverview_mailbox_quota'] . "" . $PALANG['pOverview_mailbox_modified'] . "" . $PALANG['pOverview_mailbox_active'] . " 
    " . gen_show_status($tMailbox[$i]['username']) . "" . searchhl($tMailbox[$i]['username']) . "" . searchhl($tMailbox[$i]['goto']) . ""; if ($tMailbox[$i]['goto_mailbox'] == 1) { print "Mailbox"; # TODO: make translatable } else { print "Forward only"; # TODO: make translatable } if (count($tMailbox[$i]['goto_other']) > 0) print "
    "; print searchhl(join("
    ", $tMailbox[$i]['goto_other'])); # TODO: honor $CONF['alias_goto_limit'] print "
    " . htmlentities($tMailbox[$i]['name'], ENT_QUOTES, 'UTF-8') . ""; if ($tMailbox[$i]['quota'] == 0) { print $PALANG['pOverview_unlimited']; } elseif ($tMailbox[$i]['quota'] < 0) { print $PALANG['pOverview_disabled']; } else { if (boolconf('used_quotas')) print divide_quota ($tMailbox[$i]['current']).'/'; print divide_quota ($tMailbox[$i]['quota']); } print "" . $tMailbox[$i]['modified'] . "" . $active . "" . $v_active . "   " . $PALANG['pOverview_alias_edit'] . "" . $PALANG['edit'] . "" . $PALANG['del'] . "
    \n"; print "
    \n"; if ($tDisplay_back_show == 1) { print "\""\n"; } if ($tDisplay_up_show == 1) { print "\""\n"; } if ($tDisplay_next_show == 1) { print "\""\n"; } print "
    \n"; } if($tCanAddMailbox) { print "

    " . $PALANG['pMenu_create_mailbox'] . "\n"; } if ($CONF['show_status'] == 'YES' && $CONF['show_status_key'] == 'YES') { print "

    "; if ($CONF['show_undeliverable'] == 'YES') { print " " . $CONF['show_status_text'] . "=" . $PALANG['pStatus_undeliverable'] . "\n"; } if ($CONF['show_popimap'] == 'YES') { print " " . $CONF['show_status_text'] . "=" . $PALANG['pStatus_popimap'] . "\n"; } if ( count($CONF['show_custom_domains']) > 0 ) { for ($i = 0; $i < sizeof ($CONF['show_custom_domains']); $i++) { print " " . $CONF['show_status_text'] . "=" . $PALANG['pStatus_custom'] . $CONF['show_custom_domains'][$i] . "\n"; } } } /* vim: set ft=php expandtab softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/templates/fetchmail.php0000664000175000017620000001415611703401073020725 0ustar davidpalepurple '; echo '

    '; print fetchmail_edit_row($formvars); } else { # display mode print '
    '; print ''; print "\n"; print " \n"; print " \n"; print " \n"; print " \n"; foreach($headers as $row){ list($editible,$view,$type,$title,$comment)=$row; print " \n"; } print ""; print ""; print " \n"; if (sizeof ($tFmail) > 0){ foreach($tFmail as $row){ print " \n"; foreach($row as $key=>$val){ if (!isset($fm_struct[$key])) continue; # TODO: not really nice, but avoids undefined index warnings ;-) list($editible,$view,$type)=$fm_struct[$key]; if ($view){ $func="_listview_".$type; print " \n"; } } print ""; print " \n"; print " \n"; } } print "

    ".$PALANG['pFetchmail_welcome'].$user_domains."

    " . $title . "  
    " . htmlentities(function_exists($func)?$func($val):$val) . "" . $PALANG['edit'] . "" . $PALANG['del'] . "
    "; print "

    \n"; print "

    \n"; print "
    \n"; print "

    ".$PALANG['pFetchmail_new_entry']."

    \n"; } # end display mode function fetchmail_edit_row($data=array()){ global $fm_struct,$fm_defaults,$PALANG; $id=$data["id"]; $_id=$data["id"]*100+1; $ret=""; $ret .= ''; # TODO: $formvars possibly contains db-specific boolean values # TODO: no problems with MySQL, to be tested with PgSQL # TODO: undefined values may also occour foreach($fm_struct as $key=>$struct){ list($editible,$view,$type)=$struct; $title = $PALANG['pFetchmail_field_' . $key]; $comment = $PALANG['pFetchmail_desc_' . $key]; if ($editible){ $ret.=""; $ret.="\n"; } elseif($view){ $func="_view_".$type; $val=isset($data[$key]) ?(function_exists($func) ?$func($data[$key]) :nl2br($data[$key]) ) :"--x--"; $ret.=""; $ret.="\n"; } } $ret.="\n"; $ret.="

    ' . $PALANG['pMenu_fetchmail'] . '

    "; $func="_edit_".$type; if (! function_exists($func)) $func="_edit_text"; $val=isset($data[$key]) ?$data[$key] :(! is_array($fm_defaults[$key]) ?$fm_defaults[$key] :'' ); $fm_defaults_key = ""; if (isset($fm_defaults[$key])) $fm_defaults_key = $fm_defaults[$key]; $ret.=$func($_id++,$key,$fm_defaults_key,$val); $ret.=" ${comment}
    ${title}: ".$val; $ret.=" ${comment}
      "; if ($id){ $ret.=""; } $ret.="
    \n"; $ret.="

    \n"; $ret.="\n"; $ret.="\n"; return $ret; } function _edit_text($id,$key,$def_vals,$val=""){ $val=htmlspecialchars($val); return ""; } function _edit_password($id,$key,$def_vals,$val=""){ $val=preg_replace("{.}","*",$val); return ""; } function _edit_num($id,$key,$def_vals,$val=""){ $val=(int)($val); return ""; } function _edit_bool($id,$key,$def_vals,$val=""){ $ret="${val}"; } function _edit_enum($id,$key,$def_vals,$val=""){ $ret="   />   postfixadmin-2.3.7/templates/users_password.php0000664000175000017620000000263311167650536022067 0ustar davidpalepurple

     
    postfixadmin-2.3.7/password.php0000664000175000017620000000533011146027202016626 0ustar davidpalepurple postfixadmin-2.3.7/login.php0000664000175000017620000000603111434212643016100 0ustar davidpalepurple' . $PALANG['pLogin_failed'] . '
    '; } } else { $error = 1; $tMessage = '' . $PALANG['pLogin_failed'] . ''; } if ($error != 1) { session_regenerate_id(); $_SESSION['sessid'] = array(); $_SESSION['sessid']['username'] = $fUsername; $_SESSION['sessid']['roles'] = array(); $_SESSION['sessid']['roles'][] = 'admin'; // they've logged in, so see if they are a domain admin, as well. $result = db_query ("SELECT * FROM $table_domain_admins WHERE username='$fUsername' AND domain='ALL' AND active='1'"); if ($result['rows'] == 1) { $_SESSION['sessid']['roles'][] = 'global-admin'; # header("Location: admin/list-admin.php"); # exit(0); } header("Location: main.php"); exit(0); } include ("./templates/header.php"); include ("./templates/login.php"); include ("./templates/footer.php"); } /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ ?> postfixadmin-2.3.7/tests/0000775000175000017620000000000012301477471015427 5ustar davidpalepurplepostfixadmin-2.3.7/tests/RemoteTest.php0000664000175000017620000000573711171453612020242 0ustar davidpalepurpleusername); $password = escape_string(pacrypt($this->password)); db_query("DELETE FROM $table_vacation WHERE email = '$username'"); db_query("DELETE FROM $table_alias WHERE domain = 'example.com'"); db_query("DELETE FROM $table_mailbox WHERE domain = 'example.com'"); db_query("DELETE FROM $table_domain WHERE domain = 'example.com'"); // create new db records.. $result = db_query("INSERT INTO $table_domain (domain, aliases, mailboxes) VALUES ('example.com', 100, 100)"); if($result['rows'] != 1) { die("Failed to add domain to db...."); } $result = db_query("INSERT INTO $table_mailbox (username, password, name, local_part, domain) VALUES ('$username', '$password', 'test user', 'roger', 'example.com')"); if($result['rows'] != 1) { die("Failed to add user to db...."); } $result = db_query("INSERT INTO $table_alias (address, goto, domain) VALUES ('$username', '$username', 'example.com')"); if($result['rows'] != 1) { die("Failed to add alias to db...."); } try { $this->xmlrpc_client = new Zend_XmlRpc_Client($this->server_url); $http_client = $this->xmlrpc_client->getHttpClient(); $http_client->setCookieJar(); $login_object = $this->xmlrpc_client->getProxy('login'); $success = $login_object->login($this->username, $this->password); if(!$success) { var_dump($success); die("Failed to login to xmlrpc interface"); } $this->user = $this->xmlrpc_client->getProxy('user'); $this->alias = $this->xmlrpc_client->getProxy('alias'); $this->vacation = $this->xmlrpc_client->getProxy('vacation'); } catch(Exception $e) { var_dump($e); var_dump($this->xmlrpc_client->getHttpClient()->getLastResponse()->getBody()); die("Error setting up.."); } } } /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ postfixadmin-2.3.7/tests/common.php0000664000175000017620000000032011171453612017416 0ustar davidpalepurpleaddTestFile('./RemoteVacationTest.php'); $test->addTestFile('./RemoteUserTest.php'); $test->addTestFile('./RemoteAliasTest.php'); exit($test->run(new TextReporter()) ? 0 : 1); /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ postfixadmin-2.3.7/tests/simpletest/0000775000175000017620000000000012301477471017620 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/test/0000775000175000017620000000000012301477471020577 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/test/shell_test.php0000664000175000017620000000240511157271050023450 0ustar davidpalepurpleassertIdentical($shell->execute('echo Hello'), 0); $this->assertPattern('/Hello/', $shell->getOutput()); } function testBadCommand() { $shell = &new SimpleShell(); $this->assertNotEqual($ret = $shell->execute('blurgh! 2>&1'), 0); } } class TestOfShellTesterAndShell extends ShellTestCase { function testEcho() { $this->assertTrue($this->execute('echo Hello')); $this->assertExitCode(0); $this->assertoutput('Hello'); } function testFileExistence() { $this->assertFileExists(dirname(__FILE__) . '/all_tests.php'); $this->assertFileNotExists('wibble'); } function testFilePatterns() { $this->assertFilePattern('/all_tests/i', dirname(__FILE__) . '/all_tests.php'); $this->assertNoFilePattern('/sputnik/i', dirname(__FILE__) . '/all_tests.php'); } } ?>postfixadmin-2.3.7/tests/simpletest/test/exceptions_test.php0000664000175000017620000001022511157271050024521 0ustar davidpalepurpleassertTrue($expectation->test(new MyTestException())); $this->assertTrue($expectation->test(new HigherTestException())); $this->assertFalse($expectation->test(new OtherTestException())); } function testMatchesClassAndMessageWhenExceptionExpected() { $expectation = new ExceptionExpectation(new MyTestException('Hello')); $this->assertTrue($expectation->test(new MyTestException('Hello'))); $this->assertFalse($expectation->test(new HigherTestException('Hello'))); $this->assertFalse($expectation->test(new OtherTestException('Hello'))); $this->assertFalse($expectation->test(new MyTestException('Goodbye'))); $this->assertFalse($expectation->test(new MyTestException())); } function testMessagelessExceptionMatchesOnlyOnClass() { $expectation = new ExceptionExpectation(new MyTestException()); $this->assertTrue($expectation->test(new MyTestException())); $this->assertFalse($expectation->test(new HigherTestException())); } } class TestOfExceptionTrap extends UnitTestCase { function testNoExceptionsInQueueMeansNoTestMessages() { $test = new MockSimpleTestCase(); $test->expectNever('assert'); $queue = new SimpleExceptionTrap(); $this->assertFalse($queue->isExpected($test, new Exception())); } function testMatchingExceptionGivesTrue() { $expectation = new MockSimpleExpectation(); $expectation->setReturnValue('test', true); $test = new MockSimpleTestCase(); $test->setReturnValue('assert', true); $queue = new SimpleExceptionTrap(); $queue->expectException($expectation, 'message'); $this->assertTrue($queue->isExpected($test, new Exception())); } function testMatchingExceptionTriggersAssertion() { $test = new MockSimpleTestCase(); $test->expectOnce('assert', array( '*', new ExceptionExpectation(new Exception()), 'message')); $queue = new SimpleExceptionTrap(); $queue->expectException(new ExceptionExpectation(new Exception()), 'message'); $queue->isExpected($test, new Exception()); } } class TestOfCatchingExceptions extends UnitTestCase { function testCanCatchAnyExpectedException() { $this->expectException(); throw new Exception(); } function testCanMatchExceptionByClass() { $this->expectException('MyTestException'); throw new HigherTestException(); } function testCanMatchExceptionExactly() { $this->expectException(new Exception('Ouch')); throw new Exception('Ouch'); } function testLastListedExceptionIsTheOneThatCounts() { $this->expectException('OtherTestException'); $this->expectException('MyTestException'); throw new HigherTestException(); } } class Test1Exception extends Exception {} class Test2Exception extends Exception {} class TestOfCallingTearDownWithExceptions extends UnitTestCase { public function setUp() { $GLOBALS['setUp'] = true; } public function tearDown() { $GLOBALS['tearDown'] = true; } public function test1() { $this->assertTrue($GLOBALS['setUp']); $this->assertNull($GLOBALS['tearDown']); $this->expectException('Test1Exception'); throw new Test1Exception(__FUNCTION__); } public function test2() { $this->assertTrue($GLOBALS['setUp']); $this->assertTrue($GLOBALS['tearDown']); $this->expectException('Test2Exception'); throw new Test2Exception(__FUNCTION__); } } ?>postfixadmin-2.3.7/tests/simpletest/test/parse_error_test.php0000664000175000017620000000045711157271050024671 0ustar davidpalepurpleaddTestFile('test_with_parse_error.php'); $test->run(new HtmlReporter()); ?>postfixadmin-2.3.7/tests/simpletest/test/errors_test.php0000664000175000017620000001775211157271050023670 0ustar davidpalepurpleget('SimpleErrorQueue'); $queue->clear(); } function tearDown() { $context = &SimpleTest::getContext(); $queue = &$context->get('SimpleErrorQueue'); $queue->clear(); } function testOrder() { $context = &SimpleTest::getContext(); $queue = &$context->get('SimpleErrorQueue'); $queue->add(1024, 'Ouch', 'here.php', 100); $queue->add(512, 'Yuk', 'there.php', 101); $this->assertEqual( $queue->extract(), array(1024, 'Ouch', 'here.php', 100)); $this->assertEqual( $queue->extract(), array(512, 'Yuk', 'there.php', 101)); $this->assertFalse($queue->extract()); } function testAssertNoErrorsGivesTrueWhenNoErrors() { $test = &new MockSimpleTestCase(); $test->expectOnce('assert', array(new TrueExpectation(), true, 'Should be no errors')); $test->setReturnValue('assert', true); $queue = &new SimpleErrorQueue(); $queue->setTestCase($test); $this->assertTrue($queue->assertNoErrors('%s')); } function testAssertNoErrorsIssuesFailWhenErrors() { $test = &new MockSimpleTestCase(); $test->expectOnce('assert', array(new TrueExpectation(), false, 'Should be no errors')); $test->setReturnValue('assert', false); $queue = &new SimpleErrorQueue(); $queue->setTestCase($test); $queue->add(1024, 'Ouch', 'here.php', 100); $this->assertFalse($queue->assertNoErrors('%s')); } function testAssertErrorFailsWhenNoError() { $test = &new MockSimpleTestCase(); $test->expectOnce('fail', array('Expected error not found')); $test->setReturnValue('assert', false); $queue = &new SimpleErrorQueue(); $queue->setTestCase($test); $this->assertFalse($queue->assertError(false, '%s')); } function testAssertErrorFailsWhenErrorDoesntMatch() { $test = &new MockSimpleTestCase(); $test->expectOnce('assert', array( new MockSimpleExpectation(), 'B', 'Expected PHP error [B] severity [E_USER_NOTICE] in [b.php] line [100]')); $test->setReturnValue('assert', false); $queue = &new SimpleErrorQueue(); $queue->setTestCase($test); $queue->add(1024, 'B', 'b.php', 100); $this->assertFalse($queue->assertError(new MockSimpleExpectation(), '%s')); } function testExpectationMatchCancelsIncomingError() { $test = &new MockSimpleTestCase(); $test->expectOnce('assert', array(new MockSimpleExpectation(), 'B', 'a message')); $test->setReturnValue('assert', true); $test->expectNever('error'); $queue = &new SimpleErrorQueue(); $queue->setTestCase($test); $queue->expectError(new MockSimpleExpectation(), 'a message'); $queue->add(1024, 'B', 'b.php', 100); } function testExpectationMissTriggersError() { $test = &new MockSimpleTestCase(); $test->expectOnce('assert', array(new MockSimpleExpectation(), 'B', 'a message')); $test->setReturnValue('assert', false); $test->expectOnce('error'); $queue = &new SimpleErrorQueue(); $queue->setTestCase($test); $queue->expectError(new MockSimpleExpectation(), 'a message'); $queue->add(1024, 'B', 'b.php', 100); } } class TestOfErrorTrap extends UnitTestCase { var $_old; function setUp() { $this->_old = error_reporting(E_ALL); set_error_handler('SimpleTestErrorHandler'); } function tearDown() { restore_error_handler(); error_reporting($this->_old); } function testQueueStartsEmpty() { $context = &SimpleTest::getContext(); $queue = &$context->get('SimpleErrorQueue'); $this->assertFalse($queue->extract()); } function testTrappedErrorPlacedInQueue() { trigger_error('Ouch!'); $context = &SimpleTest::getContext(); $queue = &$context->get('SimpleErrorQueue'); list($severity, $message, $file, $line) = $queue->extract(); $this->assertEqual($message, 'Ouch!'); $this->assertEqual($file, __FILE__); $this->assertFalse($queue->extract()); } function testErrorsAreSwallowedByMatchingExpectation() { $this->expectError('Ouch!'); trigger_error('Ouch!'); } function testErrorsAreSwallowedInOrder() { $this->expectError('a'); $this->expectError('b'); trigger_error('a'); trigger_error('b'); } function testAnyErrorCanBeSwallowed() { $this->expectError(); trigger_error('Ouch!'); } function testErrorCanBeSwallowedByPatternMatching() { $this->expectError(new PatternExpectation('/ouch/i')); trigger_error('Ouch!'); } function testErrorWithPercentsPassesWithNoSprintfError() { $this->expectError("%"); trigger_error('%'); } } class TestOfErrors extends UnitTestCase { var $_old; function setUp() { $this->_old = error_reporting(E_ALL); } function tearDown() { error_reporting($this->_old); } function testDefaultWhenAllReported() { error_reporting(E_ALL); trigger_error('Ouch!'); $this->assertError('Ouch!'); } function testNoticeWhenReported() { error_reporting(E_ALL); trigger_error('Ouch!', E_USER_NOTICE); $this->assertError('Ouch!'); } function testWarningWhenReported() { error_reporting(E_ALL); trigger_error('Ouch!', E_USER_WARNING); $this->assertError('Ouch!'); } function testErrorWhenReported() { error_reporting(E_ALL); trigger_error('Ouch!', E_USER_ERROR); $this->assertError('Ouch!'); } function testNoNoticeWhenNotReported() { error_reporting(0); trigger_error('Ouch!', E_USER_NOTICE); } function testNoWarningWhenNotReported() { error_reporting(0); trigger_error('Ouch!', E_USER_WARNING); } function testNoticeSuppressedWhenReported() { error_reporting(E_ALL); @trigger_error('Ouch!', E_USER_NOTICE); } function testWarningSuppressedWhenReported() { error_reporting(E_ALL); @trigger_error('Ouch!', E_USER_WARNING); } function testErrorWithPercentsReportedWithNoSprintfError() { trigger_error('%'); $this->assertError('%'); } } class TestOfErrorsExcludingPHP52AndAbove extends UnitTestCase { function skip() { $this->skipIf(version_compare(phpversion(), '5.2', '>='), 'E_USER_ERROR not tested for PHP 5.2 and above'); } function testNoErrorWhenNotReported() { error_reporting(0); trigger_error('Ouch!', E_USER_ERROR); } function testErrorSuppressedWhenReported() { error_reporting(E_ALL); @trigger_error('Ouch!', E_USER_ERROR); } } // TODO: Add stacked error handler test ?>postfixadmin-2.3.7/tests/simpletest/test/socket_test.php0000664000175000017620000000147311157271050023635 0ustar davidpalepurpleassertFalse($error->isError()); $error->_setError('Ouch'); $this->assertTrue($error->isError()); $this->assertEqual($error->getError(), 'Ouch'); } function testClearingError() { $error = new SimpleStickyError(); $error->_setError('Ouch'); $this->assertTrue($error->isError()); $error->_clearError(); $this->assertFalse($error->isError()); } } ?>postfixadmin-2.3.7/tests/simpletest/test/interfaces_test.php0000664000175000017620000000721011157271050024463 0ustar davidpalepurpleassertIsA($mock, 'SimpleMock'); $this->assertIsA($mock, 'MockDummyInterface'); $this->assertTrue(method_exists($mock, 'aMethod')); $this->assertTrue(method_exists($mock, 'anotherMethod')); $this->assertNull($mock->aMethod()); } function testMockedInterfaceExpectsParameters() { $mock = new MockDummyInterface(); $mock->anotherMethod(); $this->assertError(); } function testCannotPartiallyMockAnInterface() { $this->assertFalse(class_exists('PartialDummyInterface')); } } class TestOfSpl extends UnitTestCase { function testCanMockAllSplClasses() { if (! function_exists('spl_classes')) { return; } foreach(spl_classes() as $class) { $mock_class = "Mock$class"; Mock::generate($class); $this->assertIsA(new $mock_class(), $mock_class); } } function testExtensionOfCommonSplClasses() { if (! function_exists('spl_classes')) { return; } Mock::generate('IteratorImplementation'); $this->assertIsA( new IteratorImplementation(), 'IteratorImplementation'); Mock::generate('IteratorAggregateImplementation'); $this->assertIsA( new IteratorAggregateImplementation(), 'IteratorAggregateImplementation'); } } class WithHint { function hinted(DummyInterface $object) { } } class ImplementsDummy implements DummyInterface { function aMethod() { } function anotherMethod($a) { } function &referenceMethod(&$a) { } function extraMethod($a = false) { } } Mock::generate('ImplementsDummy'); class TestOfImplementations extends UnitTestCase { function testMockedInterfaceCanPassThroughTypeHint() { $mock = new MockDummyInterface(); $hinter = new WithHint(); $hinter->hinted($mock); } function testImplementedInterfacesAreCarried() { $mock = new MockImplementsDummy(); $hinter = new WithHint(); $hinter->hinted($mock); } function testNoSpuriousWarningsWhenSkippingDefaultedParameter() { $mock = new MockImplementsDummy(); $mock->extraMethod(); } } interface SampleClassWithConstruct { function __construct($something); } class TestOfInterfaceMocksWithConstruct extends UnitTestCase { function testBasicConstructOfAnInterface() { Mock::generate('SampleClassWithConstruct'); $this->assertNoErrors(); } } interface SampleInterfaceWithClone { function __clone(); } class TestOfSampleInterfaceWithClone extends UnitTestCase { function testCanMockWithoutErrors() { Mock::generate('SampleInterfaceWithClone'); $this->assertNoErrors(); } } ?> postfixadmin-2.3.7/tests/simpletest/test/cookies_test.php0000664000175000017620000002417611157271050024006 0ustar davidpalepurpleassertFalse($cookie->getValue()); $this->assertEqual($cookie->getPath(), "/"); $this->assertIdentical($cookie->getHost(), false); $this->assertFalse($cookie->getExpiry()); $this->assertFalse($cookie->isSecure()); } function testCookieAccessors() { $cookie = new SimpleCookie( "name", "value", "/path", "Mon, 18 Nov 2002 15:50:29 GMT", true); $this->assertEqual($cookie->getName(), "name"); $this->assertEqual($cookie->getValue(), "value"); $this->assertEqual($cookie->getPath(), "/path/"); $this->assertEqual($cookie->getExpiry(), "Mon, 18 Nov 2002 15:50:29 GMT"); $this->assertTrue($cookie->isSecure()); } function testFullHostname() { $cookie = new SimpleCookie("name"); $this->assertTrue($cookie->setHost("host.name.here")); $this->assertEqual($cookie->getHost(), "host.name.here"); $this->assertTrue($cookie->setHost("host.com")); $this->assertEqual($cookie->getHost(), "host.com"); } function testHostTruncation() { $cookie = new SimpleCookie("name"); $cookie->setHost("this.host.name.here"); $this->assertEqual($cookie->getHost(), "host.name.here"); $cookie->setHost("this.host.com"); $this->assertEqual($cookie->getHost(), "host.com"); $this->assertTrue($cookie->setHost("dashes.in-host.com")); $this->assertEqual($cookie->getHost(), "in-host.com"); } function testBadHosts() { $cookie = new SimpleCookie("name"); $this->assertFalse($cookie->setHost("gibberish")); $this->assertFalse($cookie->setHost("host.here")); $this->assertFalse($cookie->setHost("host..com")); $this->assertFalse($cookie->setHost("...")); $this->assertFalse($cookie->setHost("host.com.")); } function testHostValidity() { $cookie = new SimpleCookie("name"); $cookie->setHost("this.host.name.here"); $this->assertTrue($cookie->isValidHost("host.name.here")); $this->assertTrue($cookie->isValidHost("that.host.name.here")); $this->assertFalse($cookie->isValidHost("bad.host")); $this->assertFalse($cookie->isValidHost("nearly.name.here")); } function testPathValidity() { $cookie = new SimpleCookie("name", "value", "/path"); $this->assertFalse($cookie->isValidPath("/")); $this->assertTrue($cookie->isValidPath("/path/")); $this->assertTrue($cookie->isValidPath("/path/more")); } function testSessionExpiring() { $cookie = new SimpleCookie("name", "value", "/path"); $this->assertTrue($cookie->isExpired(0)); } function testTimestampExpiry() { $cookie = new SimpleCookie("name", "value", "/path", 456); $this->assertFalse($cookie->isExpired(0)); $this->assertTrue($cookie->isExpired(457)); $this->assertFalse($cookie->isExpired(455)); } function testDateExpiry() { $cookie = new SimpleCookie( "name", "value", "/path", "Mon, 18 Nov 2002 15:50:29 GMT"); $this->assertTrue($cookie->isExpired("Mon, 18 Nov 2002 15:50:30 GMT")); $this->assertFalse($cookie->isExpired("Mon, 18 Nov 2002 15:50:28 GMT")); } function testAging() { $cookie = new SimpleCookie("name", "value", "/path", 200); $cookie->agePrematurely(199); $this->assertFalse($cookie->isExpired(0)); $cookie->agePrematurely(2); $this->assertTrue($cookie->isExpired(0)); } } class TestOfCookieJar extends UnitTestCase { function testAddCookie() { $jar = new SimpleCookieJar(); $jar->setCookie("a", "A"); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=A')); } function testHostFilter() { $jar = new SimpleCookieJar(); $jar->setCookie('a', 'A', 'my-host.com'); $jar->setCookie('b', 'B', 'another-host.com'); $jar->setCookie('c', 'C'); $this->assertEqual( $jar->selectAsPairs(new SimpleUrl('my-host.com')), array('a=A', 'c=C')); $this->assertEqual( $jar->selectAsPairs(new SimpleUrl('another-host.com')), array('b=B', 'c=C')); $this->assertEqual( $jar->selectAsPairs(new SimpleUrl('www.another-host.com')), array('b=B', 'c=C')); $this->assertEqual( $jar->selectAsPairs(new SimpleUrl('new-host.org')), array('c=C')); $this->assertEqual( $jar->selectAsPairs(new SimpleUrl('/')), array('a=A', 'b=B', 'c=C')); } function testPathFilter() { $jar = new SimpleCookieJar(); $jar->setCookie('a', 'A', false, '/path/'); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array()); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/elsewhere')), array()); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/')), array('a=A')); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path')), array('a=A')); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/pa')), array()); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/here')), array('a=A')); } function testPathFilterDeeply() { $jar = new SimpleCookieJar(); $jar->setCookie('a', 'A', false, '/path/more_path/'); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/')), array()); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path')), array()); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/pa')), array()); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/more_path/')), array('a=A')); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/more_path/and_more')), array('a=A')); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/not_here/')), array()); } function testMultipleCookieWithDifferentPathsButSameName() { $jar = new SimpleCookieJar(); $jar->setCookie('a', 'abc', false, '/'); $jar->setCookie('a', '123', false, '/path/here/'); $this->assertEqual( $jar->selectAsPairs(new SimpleUrl('/')), array('a=abc')); $this->assertEqual( $jar->selectAsPairs(new SimpleUrl('my-host.com/')), array('a=abc')); $this->assertEqual( $jar->selectAsPairs(new SimpleUrl('my-host.com/path/')), array('a=abc')); $this->assertEqual( $jar->selectAsPairs(new SimpleUrl('my-host.com/path/here')), array('a=abc', 'a=123')); $this->assertEqual( $jar->selectAsPairs(new SimpleUrl('my-host.com/path/here/there')), array('a=abc', 'a=123')); } function testOverwrite() { $jar = new SimpleCookieJar(); $jar->setCookie('a', 'abc', false, '/'); $jar->setCookie('a', 'cde', false, '/'); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=cde')); } function testClearSessionCookies() { $jar = new SimpleCookieJar(); $jar->setCookie('a', 'A', false, '/'); $jar->restartSession(); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array()); } function testExpiryFilterByDate() { $jar = new SimpleCookieJar(); $jar->setCookie('a', 'A', false, '/', 'Wed, 25-Dec-02 04:24:20 GMT'); $jar->restartSession("Wed, 25-Dec-02 04:24:19 GMT"); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=A')); $jar->restartSession("Wed, 25-Dec-02 04:24:21 GMT"); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array()); } function testExpiryFilterByAgeing() { $jar = new SimpleCookieJar(); $jar->setCookie('a', 'A', false, '/', 'Wed, 25-Dec-02 04:24:20 GMT'); $jar->restartSession("Wed, 25-Dec-02 04:24:19 GMT"); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=A')); $jar->agePrematurely(2); $jar->restartSession("Wed, 25-Dec-02 04:24:19 GMT"); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array()); } function testCookieClearing() { $jar = new SimpleCookieJar(); $jar->setCookie('a', 'abc', false, '/'); $jar->setCookie('a', '', false, '/'); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=')); } function testCookieClearByLoweringDate() { $jar = new SimpleCookieJar(); $jar->setCookie('a', 'abc', false, '/', 'Wed, 25-Dec-02 04:24:21 GMT'); $jar->setCookie('a', 'def', false, '/', 'Wed, 25-Dec-02 04:24:19 GMT'); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=def')); $jar->restartSession('Wed, 25-Dec-02 04:24:20 GMT'); $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array()); } } ?>postfixadmin-2.3.7/tests/simpletest/test/web_tester_test.php0000664000175000017620000001621511157271050024510 0ustar davidpalepurpleassertTrue($expectation->test('a')); $this->assertTrue($expectation->test(array('a'))); $this->assertFalse($expectation->test('A')); } function testMatchesInteger() { $expectation = new FieldExpectation('1'); $this->assertTrue($expectation->test('1')); $this->assertTrue($expectation->test(1)); $this->assertTrue($expectation->test(array('1'))); $this->assertTrue($expectation->test(array(1))); } function testNonStringFailsExpectation() { $expectation = new FieldExpectation('a'); $this->assertFalse($expectation->test(null)); } function testUnsetFieldCanBeTestedFor() { $expectation = new FieldExpectation(false); $this->assertTrue($expectation->test(false)); } function testMultipleValuesCanBeInAnyOrder() { $expectation = new FieldExpectation(array('a', 'b')); $this->assertTrue($expectation->test(array('a', 'b'))); $this->assertTrue($expectation->test(array('b', 'a'))); $this->assertFalse($expectation->test(array('a', 'a'))); $this->assertFalse($expectation->test('a')); } function testSingleItemCanBeArrayOrString() { $expectation = new FieldExpectation(array('a')); $this->assertTrue($expectation->test(array('a'))); $this->assertTrue($expectation->test('a')); } } class TestOfHeaderExpectations extends UnitTestCase { function testExpectingOnlyTheHeaderName() { $expectation = new HttpHeaderExpectation('a'); $this->assertIdentical($expectation->test(false), false); $this->assertIdentical($expectation->test('a: A'), true); $this->assertIdentical($expectation->test('A: A'), true); $this->assertIdentical($expectation->test('a: B'), true); $this->assertIdentical($expectation->test(' a : A '), true); } function testHeaderValueAsWell() { $expectation = new HttpHeaderExpectation('a', 'A'); $this->assertIdentical($expectation->test(false), false); $this->assertIdentical($expectation->test('a: A'), true); $this->assertIdentical($expectation->test('A: A'), true); $this->assertIdentical($expectation->test('A: a'), false); $this->assertIdentical($expectation->test('a: B'), false); $this->assertIdentical($expectation->test(' a : A '), true); $this->assertIdentical($expectation->test(' a : AB '), false); } function testHeaderValueWithColons() { $expectation = new HttpHeaderExpectation('a', 'A:B:C'); $this->assertIdentical($expectation->test('a: A'), false); $this->assertIdentical($expectation->test('a: A:B'), false); $this->assertIdentical($expectation->test('a: A:B:C'), true); $this->assertIdentical($expectation->test('a: A:B:C:D'), false); } function testMultilineSearch() { $expectation = new HttpHeaderExpectation('a', 'A'); $this->assertIdentical($expectation->test("aa: A\r\nb: B\r\nc: C"), false); $this->assertIdentical($expectation->test("aa: A\r\na: A\r\nb: B"), true); } function testMultilineSearchWithPadding() { $expectation = new HttpHeaderExpectation('a', ' A '); $this->assertIdentical($expectation->test("aa:A\r\nb:B\r\nc:C"), false); $this->assertIdentical($expectation->test("aa:A\r\na:A\r\nb:B"), true); } function testPatternMatching() { $expectation = new HttpHeaderExpectation('a', new PatternExpectation('/A/')); $this->assertIdentical($expectation->test('a: A'), true); $this->assertIdentical($expectation->test('A: A'), true); $this->assertIdentical($expectation->test('A: a'), false); $this->assertIdentical($expectation->test('a: B'), false); $this->assertIdentical($expectation->test(' a : A '), true); $this->assertIdentical($expectation->test(' a : AB '), true); } function testCaseInsensitivePatternMatching() { $expectation = new HttpHeaderExpectation('a', new PatternExpectation('/A/i')); $this->assertIdentical($expectation->test('a: a'), true); $this->assertIdentical($expectation->test('a: B'), false); $this->assertIdentical($expectation->test(' a : A '), true); $this->assertIdentical($expectation->test(' a : BAB '), true); $this->assertIdentical($expectation->test(' a : bab '), true); } function testUnwantedHeader() { $expectation = new NoHttpHeaderExpectation('a'); $this->assertIdentical($expectation->test(''), true); $this->assertIdentical($expectation->test('stuff'), true); $this->assertIdentical($expectation->test('b: B'), true); $this->assertIdentical($expectation->test('a: A'), false); $this->assertIdentical($expectation->test('A: A'), false); } function testMultilineUnwantedSearch() { $expectation = new NoHttpHeaderExpectation('a'); $this->assertIdentical($expectation->test("aa:A\r\nb:B\r\nc:C"), true); $this->assertIdentical($expectation->test("aa:A\r\na:A\r\nb:B"), false); } function testLocationHeaderSplitsCorrectly() { $expectation = new HttpHeaderExpectation('Location', 'http://here/'); $this->assertIdentical($expectation->test('Location: http://here/'), true); } } class TestOfTextExpectations extends UnitTestCase { function testMatchingSubString() { $expectation = new TextExpectation('wanted'); $this->assertIdentical($expectation->test(''), false); $this->assertIdentical($expectation->test('Wanted'), false); $this->assertIdentical($expectation->test('wanted'), true); $this->assertIdentical($expectation->test('the wanted text is here'), true); } function testNotMatchingSubString() { $expectation = new NoTextExpectation('wanted'); $this->assertIdentical($expectation->test(''), true); $this->assertIdentical($expectation->test('Wanted'), true); $this->assertIdentical($expectation->test('wanted'), false); $this->assertIdentical($expectation->test('the wanted text is here'), false); } } class TestOfGenericAssertionsInWebTester extends WebTestCase { function testEquality() { $this->assertEqual('a', 'a'); $this->assertNotEqual('a', 'A'); } } ?>postfixadmin-2.3.7/tests/simpletest/test/browser_test.php0000664000175000017620000011075611157271050024035 0ustar davidpalepurpleassertIdentical($history->getUrl(), false); $this->assertIdentical($history->getParameters(), false); } function testCannotMoveInEmptyHistory() { $history = &new SimpleBrowserHistory(); $this->assertFalse($history->back()); $this->assertFalse($history->forward()); } function testCurrentTargetAccessors() { $history = &new SimpleBrowserHistory(); $history->recordEntry( new SimpleUrl('http://www.here.com/'), new SimpleGetEncoding()); $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.here.com/')); $this->assertIdentical($history->getParameters(), new SimpleGetEncoding()); } function testSecondEntryAccessors() { $history = &new SimpleBrowserHistory(); $history->recordEntry( new SimpleUrl('http://www.first.com/'), new SimpleGetEncoding()); $history->recordEntry( new SimpleUrl('http://www.second.com/'), new SimplePostEncoding(array('a' => 1))); $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.second.com/')); $this->assertIdentical( $history->getParameters(), new SimplePostEncoding(array('a' => 1))); } function testGoingBackwards() { $history = &new SimpleBrowserHistory(); $history->recordEntry( new SimpleUrl('http://www.first.com/'), new SimpleGetEncoding()); $history->recordEntry( new SimpleUrl('http://www.second.com/'), new SimplePostEncoding(array('a' => 1))); $this->assertTrue($history->back()); $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.first.com/')); $this->assertIdentical($history->getParameters(), new SimpleGetEncoding()); } function testGoingBackwardsOffBeginning() { $history = &new SimpleBrowserHistory(); $history->recordEntry( new SimpleUrl('http://www.first.com/'), new SimpleGetEncoding()); $this->assertFalse($history->back()); $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.first.com/')); $this->assertIdentical($history->getParameters(), new SimpleGetEncoding()); } function testGoingForwardsOffEnd() { $history = &new SimpleBrowserHistory(); $history->recordEntry( new SimpleUrl('http://www.first.com/'), new SimpleGetEncoding()); $this->assertFalse($history->forward()); $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.first.com/')); $this->assertIdentical($history->getParameters(), new SimpleGetEncoding()); } function testGoingBackwardsAndForwards() { $history = &new SimpleBrowserHistory(); $history->recordEntry( new SimpleUrl('http://www.first.com/'), new SimpleGetEncoding()); $history->recordEntry( new SimpleUrl('http://www.second.com/'), new SimplePostEncoding(array('a' => 1))); $this->assertTrue($history->back()); $this->assertTrue($history->forward()); $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.second.com/')); $this->assertIdentical( $history->getParameters(), new SimplePostEncoding(array('a' => 1))); } function testNewEntryReplacesNextOne() { $history = &new SimpleBrowserHistory(); $history->recordEntry( new SimpleUrl('http://www.first.com/'), new SimpleGetEncoding()); $history->recordEntry( new SimpleUrl('http://www.second.com/'), new SimplePostEncoding(array('a' => 1))); $history->back(); $history->recordEntry( new SimpleUrl('http://www.third.com/'), new SimpleGetEncoding()); $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.third.com/')); $this->assertIdentical($history->getParameters(), new SimpleGetEncoding()); } function testNewEntryDropsFutureEntries() { $history = &new SimpleBrowserHistory(); $history->recordEntry( new SimpleUrl('http://www.first.com/'), new SimpleGetEncoding()); $history->recordEntry( new SimpleUrl('http://www.second.com/'), new SimpleGetEncoding()); $history->recordEntry( new SimpleUrl('http://www.third.com/'), new SimpleGetEncoding()); $history->back(); $history->back(); $history->recordEntry( new SimpleUrl('http://www.fourth.com/'), new SimpleGetEncoding()); $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.fourth.com/')); $this->assertFalse($history->forward()); $history->back(); $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.first.com/')); $this->assertFalse($history->back()); } } class TestOfParsedPageAccess extends UnitTestCase { function &loadPage(&$page) { $response = &new MockSimpleHttpResponse($this); $agent = &new MockSimpleUserAgent($this); $agent->setReturnReference('fetchResponse', $response); $browser = &new MockParseSimpleBrowser($this); $browser->setReturnReference('_createUserAgent', $agent); $browser->setReturnReference('_parse', $page); $browser->SimpleBrowser(); $browser->get('http://this.com/page.html'); return $browser; } function testAccessorsWhenNoPage() { $agent = &new MockSimpleUserAgent($this); $browser = &new MockParseSimpleBrowser($this); $browser->setReturnReference('_createUserAgent', $agent); $browser->SimpleBrowser(); $this->assertEqual($browser->getContent(), ''); } function testParse() { $page = &new MockSimplePage(); $page->setReturnValue('getRequest', "GET here.html\r\n\r\n"); $page->setReturnValue('getRaw', 'Raw HTML'); $page->setReturnValue('getTitle', 'Here'); $page->setReturnValue('getFrameFocus', 'Frame'); $page->setReturnValue('getMimeType', 'text/html'); $page->setReturnValue('getResponseCode', 200); $page->setReturnValue('getAuthentication', 'Basic'); $page->setReturnValue('getRealm', 'Somewhere'); $page->setReturnValue('getTransportError', 'Ouch!'); $browser = &$this->loadPage($page); $this->assertEqual($browser->getRequest(), "GET here.html\r\n\r\n"); $this->assertEqual($browser->getContent(), 'Raw HTML'); $this->assertEqual($browser->getTitle(), 'Here'); $this->assertEqual($browser->getFrameFocus(), 'Frame'); $this->assertIdentical($browser->getResponseCode(), 200); $this->assertEqual($browser->getMimeType(), 'text/html'); $this->assertEqual($browser->getAuthentication(), 'Basic'); $this->assertEqual($browser->getRealm(), 'Somewhere'); $this->assertEqual($browser->getTransportError(), 'Ouch!'); } function testLinkAffirmationWhenPresent() { $page = &new MockSimplePage(); $page->setReturnValue('getUrlsByLabel', array('http://www.nowhere.com')); $page->expectOnce('getUrlsByLabel', array('a link label')); $browser = &$this->loadPage($page); $this->assertIdentical($browser->getLink('a link label'), 'http://www.nowhere.com'); } function testLinkAffirmationByIdWhenPresent() { $page = &new MockSimplePage(); $page->setReturnValue('getUrlById', 'a_page.com', array(99)); $page->setReturnValue('getUrlById', false, array('*')); $browser = &$this->loadPage($page); $this->assertIdentical($browser->getLinkById(99), 'a_page.com'); $this->assertFalse($browser->getLinkById(98)); } function testSettingFieldIsPassedToPage() { $page = &new MockSimplePage(); $page->expectOnce('setField', array(new SimpleByLabelOrName('key'), 'Value')); $page->setReturnValue('getField', 'Value'); $browser = &$this->loadPage($page); $this->assertEqual($browser->getField('key'), 'Value'); $browser->setField('key', 'Value'); } } class TestOfBrowserNavigation extends UnitTestCase { function &createBrowser(&$agent, &$page) { $browser = &new MockParseSimpleBrowser(); $browser->setReturnReference('_createUserAgent', $agent); $browser->setReturnReference('_parse', $page); $browser->SimpleBrowser(); return $browser; } function testClickLinkRequestsPage() { $agent = &new MockSimpleUserAgent(); $agent->setReturnReference('fetchResponse', new MockSimpleHttpResponse()); $agent->expectArgumentsAt( 0, 'fetchResponse', array(new SimpleUrl('http://this.com/page.html'), new SimpleGetEncoding())); $agent->expectArgumentsAt( 1, 'fetchResponse', array(new SimpleUrl('http://this.com/new.html'), new SimpleGetEncoding())); $agent->expectCallCount('fetchResponse', 2); $page = &new MockSimplePage(); $page->setReturnValue('getUrlsByLabel', array(new SimpleUrl('http://this.com/new.html'))); $page->expectOnce('getUrlsByLabel', array('New')); $page->setReturnValue('getRaw', 'A page'); $browser = &$this->createBrowser($agent, $page); $browser->get('http://this.com/page.html'); $this->assertTrue($browser->clickLink('New')); } function testClickLinkWithUnknownFrameStillRequestsWholePage() { $agent = &new MockSimpleUserAgent(); $agent->setReturnReference('fetchResponse', new MockSimpleHttpResponse()); $agent->expectArgumentsAt( 0, 'fetchResponse', array(new SimpleUrl('http://this.com/page.html'), new SimpleGetEncoding())); $target = new SimpleUrl('http://this.com/new.html'); $target->setTarget('missing'); $agent->expectArgumentsAt( 1, 'fetchResponse', array($target, new SimpleGetEncoding())); $agent->expectCallCount('fetchResponse', 2); $parsed_url = new SimpleUrl('http://this.com/new.html'); $parsed_url->setTarget('missing'); $page = &new MockSimplePage(); $page->setReturnValue('getUrlsByLabel', array($parsed_url)); $page->setReturnValue('hasFrames', false); $page->expectOnce('getUrlsByLabel', array('New')); $page->setReturnValue('getRaw', 'A page'); $browser = &$this->createBrowser($agent, $page); $browser->get('http://this.com/page.html'); $this->assertTrue($browser->clickLink('New')); } function testClickingMissingLinkFails() { $agent = &new MockSimpleUserAgent($this); $agent->setReturnReference('fetchResponse', new MockSimpleHttpResponse()); $page = &new MockSimplePage(); $page->setReturnValue('getUrlsByLabel', array()); $page->setReturnValue('getRaw', 'stuff'); $browser = &$this->createBrowser($agent, $page); $this->assertTrue($browser->get('http://this.com/page.html')); $this->assertFalse($browser->clickLink('New')); } function testClickIndexedLink() { $agent = &new MockSimpleUserAgent(); $agent->setReturnReference('fetchResponse', new MockSimpleHttpResponse()); $agent->expectArgumentsAt( 1, 'fetchResponse', array(new SimpleUrl('1.html'), new SimpleGetEncoding())); $agent->expectCallCount('fetchResponse', 2); $page = &new MockSimplePage(); $page->setReturnValue( 'getUrlsByLabel', array(new SimpleUrl('0.html'), new SimpleUrl('1.html'))); $page->setReturnValue('getRaw', 'A page'); $browser = &$this->createBrowser($agent, $page); $browser->get('http://this.com/page.html'); $this->assertTrue($browser->clickLink('New', 1)); } function testClinkLinkById() { $agent = &new MockSimpleUserAgent(); $agent->setReturnReference('fetchResponse', new MockSimpleHttpResponse()); $agent->expectArgumentsAt(1, 'fetchResponse', array( new SimpleUrl('http://this.com/link.html'), new SimpleGetEncoding())); $agent->expectCallCount('fetchResponse', 2); $page = &new MockSimplePage(); $page->setReturnValue('getUrlById', new SimpleUrl('http://this.com/link.html')); $page->expectOnce('getUrlById', array(2)); $page->setReturnValue('getRaw', 'A page'); $browser = &$this->createBrowser($agent, $page); $browser->get('http://this.com/page.html'); $this->assertTrue($browser->clickLinkById(2)); } function testClickingMissingLinkIdFails() { $agent = &new MockSimpleUserAgent(); $agent->setReturnReference('fetchResponse', new MockSimpleHttpResponse()); $page = &new MockSimplePage(); $page->setReturnValue('getUrlById', false); $browser = &$this->createBrowser($agent, $page); $browser->get('http://this.com/page.html'); $this->assertFalse($browser->clickLink(0)); } function testSubmitFormByLabel() { $agent = &new MockSimpleUserAgent(); $agent->setReturnReference('fetchResponse', new MockSimpleHttpResponse()); $agent->expectArgumentsAt(1, 'fetchResponse', array( new SimpleUrl('http://this.com/handler.html'), new SimplePostEncoding(array('a' => 'A')))); $agent->expectCallCount('fetchResponse', 2); $form = &new MockSimpleForm(); $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html')); $form->setReturnValue('getMethod', 'post'); $form->setReturnValue('submitButton', new SimplePostEncoding(array('a' => 'A'))); $form->expectOnce('submitButton', array(new SimpleByLabel('Go'), false)); $page = &new MockSimplePage(); $page->setReturnReference('getFormBySubmit', $form); $page->expectOnce('getFormBySubmit', array(new SimpleByLabel('Go'))); $page->setReturnValue('getRaw', 'stuff'); $browser = &$this->createBrowser($agent, $page); $browser->get('http://this.com/page.html'); $this->assertTrue($browser->clickSubmit('Go')); } function testDefaultSubmitFormByLabel() { $agent = &new MockSimpleUserAgent(); $agent->setReturnReference('fetchResponse', new MockSimpleHttpResponse()); $agent->expectArgumentsAt(1, 'fetchResponse', array( new SimpleUrl('http://this.com/page.html'), new SimpleGetEncoding(array('a' => 'A')))); $agent->expectCallCount('fetchResponse', 2); $form = &new MockSimpleForm(); $form->setReturnValue('getAction', new SimpleUrl('http://this.com/page.html')); $form->setReturnValue('getMethod', 'get'); $form->setReturnValue('submitButton', new SimpleGetEncoding(array('a' => 'A'))); $page = &new MockSimplePage(); $page->setReturnReference('getFormBySubmit', $form); $page->expectOnce('getFormBySubmit', array(new SimpleByLabel('Submit'))); $page->setReturnValue('getRaw', 'stuff'); $page->setReturnValue('getUrl', new SimpleUrl('http://this.com/page.html')); $browser = &$this->createBrowser($agent, $page); $browser->get('http://this.com/page.html'); $this->assertTrue($browser->clickSubmit()); } function testSubmitFormByName() { $agent = &new MockSimpleUserAgent(); $agent->setReturnReference('fetchResponse', new MockSimpleHttpResponse()); $form = &new MockSimpleForm(); $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html')); $form->setReturnValue('getMethod', 'post'); $form->setReturnValue('submitButton', new SimplePostEncoding(array('a' => 'A'))); $page = &new MockSimplePage(); $page->setReturnReference('getFormBySubmit', $form); $page->expectOnce('getFormBySubmit', array(new SimpleByName('me'))); $page->setReturnValue('getRaw', 'stuff'); $browser = &$this->createBrowser($agent, $page); $browser->get('http://this.com/page.html'); $this->assertTrue($browser->clickSubmitByName('me')); } function testSubmitFormById() { $agent = &new MockSimpleUserAgent(); $agent->setReturnReference('fetchResponse', new MockSimpleHttpResponse()); $form = &new MockSimpleForm(); $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html')); $form->setReturnValue('getMethod', 'post'); $form->setReturnValue('submitButton', new SimplePostEncoding(array('a' => 'A'))); $form->expectOnce('submitButton', array(new SimpleById(99), false)); $page = &new MockSimplePage(); $page->setReturnReference('getFormBySubmit', $form); $page->expectOnce('getFormBySubmit', array(new SimpleById(99))); $page->setReturnValue('getRaw', 'stuff'); $browser = &$this->createBrowser($agent, $page); $browser->get('http://this.com/page.html'); $this->assertTrue($browser->clickSubmitById(99)); } function testSubmitFormByImageLabel() { $agent = &new MockSimpleUserAgent(); $agent->setReturnReference('fetchResponse', new MockSimpleHttpResponse()); $form = &new MockSimpleForm(); $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html')); $form->setReturnValue('getMethod', 'post'); $form->setReturnValue('submitImage', new SimplePostEncoding(array('a' => 'A'))); $form->expectOnce('submitImage', array(new SimpleByLabel('Go!'), 10, 11, false)); $page = &new MockSimplePage(); $page->setReturnReference('getFormByImage', $form); $page->expectOnce('getFormByImage', array(new SimpleByLabel('Go!'))); $page->setReturnValue('getRaw', 'stuff'); $browser = &$this->createBrowser($agent, $page); $browser->get('http://this.com/page.html'); $this->assertTrue($browser->clickImage('Go!', 10, 11)); } function testSubmitFormByImageName() { $agent = &new MockSimpleUserAgent(); $agent->setReturnReference('fetchResponse', new MockSimpleHttpResponse()); $form = &new MockSimpleForm(); $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html')); $form->setReturnValue('getMethod', 'post'); $form->setReturnValue('submitImage', new SimplePostEncoding(array('a' => 'A'))); $form->expectOnce('submitImage', array(new SimpleByName('a'), 10, 11, false)); $page = &new MockSimplePage(); $page->setReturnReference('getFormByImage', $form); $page->expectOnce('getFormByImage', array(new SimpleByName('a'))); $page->setReturnValue('getRaw', 'stuff'); $browser = &$this->createBrowser($agent, $page); $browser->get('http://this.com/page.html'); $this->assertTrue($browser->clickImageByName('a', 10, 11)); } function testSubmitFormByImageId() { $agent = &new MockSimpleUserAgent(); $agent->setReturnReference('fetchResponse', new MockSimpleHttpResponse()); $form = &new MockSimpleForm(); $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html')); $form->setReturnValue('getMethod', 'post'); $form->setReturnValue('submitImage', new SimplePostEncoding(array('a' => 'A'))); $form->expectOnce('submitImage', array(new SimpleById(99), 10, 11, false)); $page = &new MockSimplePage(); $page->setReturnReference('getFormByImage', $form); $page->expectOnce('getFormByImage', array(new SimpleById(99))); $page->setReturnValue('getRaw', 'stuff'); $browser = &$this->createBrowser($agent, $page); $browser->get('http://this.com/page.html'); $this->assertTrue($browser->clickImageById(99, 10, 11)); } function testSubmitFormByFormId() { $agent = &new MockSimpleUserAgent(); $agent->setReturnReference('fetchResponse', new MockSimpleHttpResponse()); $agent->expectArgumentsAt(1, 'fetchResponse', array( new SimpleUrl('http://this.com/handler.html'), new SimplePostEncoding(array('a' => 'A')))); $agent->expectCallCount('fetchResponse', 2); $form = &new MockSimpleForm(); $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html')); $form->setReturnValue('getMethod', 'post'); $form->setReturnValue('submit', new SimplePostEncoding(array('a' => 'A'))); $page = &new MockSimplePage(); $page->setReturnReference('getFormById', $form); $page->expectOnce('getFormById', array(33)); $page->setReturnValue('getRaw', 'stuff'); $browser = &$this->createBrowser($agent, $page); $browser->get('http://this.com/page.html'); $this->assertTrue($browser->submitFormById(33)); } } class TestOfBrowserFrames extends UnitTestCase { function &createBrowser(&$agent) { $browser = &new MockUserAgentSimpleBrowser(); $browser->setReturnReference('_createUserAgent', $agent); $browser->SimpleBrowser(); return $browser; } function &createUserAgent($pages) { $agent = &new MockSimpleUserAgent(); foreach ($pages as $url => $raw) { $url = new SimpleUrl($url); $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getUrl', $url); $response->setReturnValue('getContent', $raw); $agent->setReturnReference('fetchResponse', $response, array($url, '*')); } return $agent; } function testSimplePageHasNoFrames() { $browser = &$this->createBrowser($this->createUserAgent( array('http://site.with.no.frames/' => 'A non-framed page'))); $this->assertEqual( $browser->get('http://site.with.no.frames/'), 'A non-framed page'); $this->assertIdentical($browser->getFrames(), 'http://site.with.no.frames/'); } function testFramesetWithNoFrames() { $browser = &$this->createBrowser($this->createUserAgent( array('http://site.with.no.frames/' => ''))); $this->assertEqual( $browser->get('http://site.with.no.frames/'), ''); $this->assertIdentical($browser->getFrames(), array()); } function testFramesetWithSingleFrame() { $frameset = ''; $browser = &$this->createBrowser($this->createUserAgent(array( 'http://site.with.one.frame/' => $frameset, 'http://site.with.one.frame/frame.html' => 'A frame'))); $this->assertEqual( $browser->get('http://site.with.one.frame/'), 'A frame'); $this->assertIdentical( $browser->getFrames(), array('a' => 'http://site.with.one.frame/frame.html')); } function testTitleTakenFromFramesetPage() { $frameset = 'Frameset title' . ''; $browser = &$this->createBrowser($this->createUserAgent(array( 'http://site.with.one.frame/' => $frameset, 'http://site.with.one.frame/frame.html' => 'Page title'))); $browser->get('http://site.with.one.frame/'); $this->assertEqual($browser->getTitle(), 'Frameset title'); } function testFramesetWithSingleUnnamedFrame() { $frameset = ''; $browser = &$this->createBrowser($this->createUserAgent(array( 'http://site.with.one.frame/' => $frameset, 'http://site.with.one.frame/frame.html' => 'One frame'))); $this->assertEqual( $browser->get('http://site.with.one.frame/'), 'One frame'); $this->assertIdentical( $browser->getFrames(), array(1 => 'http://site.with.one.frame/frame.html')); } function testFramesetWithMultipleFrames() { $frameset = '' . '' . '' . '' . ''; $browser = &$this->createBrowser($this->createUserAgent(array( 'http://site.with.frames/' => $frameset, 'http://site.with.frames/frame_a.html' => 'A frame', 'http://site.with.frames/frame_b.html' => 'B frame', 'http://site.with.frames/frame_c.html' => 'C frame'))); $this->assertEqual( $browser->get('http://site.with.frames/'), 'A frameB frameC frame'); $this->assertIdentical($browser->getFrames(), array( 'a' => 'http://site.with.frames/frame_a.html', 'b' => 'http://site.with.frames/frame_b.html', 'c' => 'http://site.with.frames/frame_c.html')); } function testFrameFocusByName() { $frameset = '' . '' . '' . '' . ''; $browser = &$this->createBrowser($this->createUserAgent(array( 'http://site.with.frames/' => $frameset, 'http://site.with.frames/frame_a.html' => 'A frame', 'http://site.with.frames/frame_b.html' => 'B frame', 'http://site.with.frames/frame_c.html' => 'C frame'))); $browser->get('http://site.with.frames/'); $browser->setFrameFocus('a'); $this->assertEqual($browser->getContent(), 'A frame'); $browser->setFrameFocus('b'); $this->assertEqual($browser->getContent(), 'B frame'); $browser->setFrameFocus('c'); $this->assertEqual($browser->getContent(), 'C frame'); } function testFramesetWithSomeNamedFrames() { $frameset = '' . '' . '' . '' . '' . ''; $browser = &$this->createBrowser($this->createUserAgent(array( 'http://site.with.frames/' => $frameset, 'http://site.with.frames/frame_a.html' => 'A frame', 'http://site.with.frames/frame_b.html' => 'B frame', 'http://site.with.frames/frame_c.html' => 'C frame', 'http://site.with.frames/frame_d.html' => 'D frame'))); $this->assertEqual( $browser->get('http://site.with.frames/'), 'A frameB frameC frameD frame'); $this->assertIdentical($browser->getFrames(), array( 'a' => 'http://site.with.frames/frame_a.html', 2 => 'http://site.with.frames/frame_b.html', 'c' => 'http://site.with.frames/frame_c.html', 4 => 'http://site.with.frames/frame_d.html')); } function testFrameFocusWithMixedNamesAndIndexes() { $frameset = '' . '' . '' . '' . '' . ''; $browser = &$this->createBrowser($this->createUserAgent(array( 'http://site.with.frames/' => $frameset, 'http://site.with.frames/frame_a.html' => 'A frame', 'http://site.with.frames/frame_b.html' => 'B frame', 'http://site.with.frames/frame_c.html' => 'C frame', 'http://site.with.frames/frame_d.html' => 'D frame'))); $browser->get('http://site.with.frames/'); $browser->setFrameFocus('a'); $this->assertEqual($browser->getContent(), 'A frame'); $browser->setFrameFocus(2); $this->assertEqual($browser->getContent(), 'B frame'); $browser->setFrameFocus('c'); $this->assertEqual($browser->getContent(), 'C frame'); $browser->setFrameFocus(4); $this->assertEqual($browser->getContent(), 'D frame'); $browser->clearFrameFocus(); $this->assertEqual($browser->getContent(), 'A frameB frameC frameD frame'); } function testNestedFrameset() { $inner = '' . '' . ''; $outer = '' . '' . ''; $browser = &$this->createBrowser($this->createUserAgent(array( 'http://site.with.nested.frame/' => $outer, 'http://site.with.nested.frame/inner.html' => $inner, 'http://site.with.nested.frame/page.html' => 'The page'))); $this->assertEqual( $browser->get('http://site.with.nested.frame/'), 'The page'); $this->assertIdentical($browser->getFrames(), array( 'inner' => array( 'page' => 'http://site.with.nested.frame/page.html'))); } function testCanNavigateToNestedFrame() { $inner = '' . '' . '' . ''; $outer = '' . '' . '' . ''; $browser = &$this->createBrowser($this->createUserAgent(array( 'http://site.with.nested.frames/' => $outer, 'http://site.with.nested.frames/inner.html' => $inner, 'http://site.with.nested.frames/one.html' => 'Page one', 'http://site.with.nested.frames/two.html' => 'Page two', 'http://site.with.nested.frames/three.html' => 'Page three'))); $browser->get('http://site.with.nested.frames/'); $this->assertEqual($browser->getContent(), 'Page onePage twoPage three'); $this->assertTrue($browser->setFrameFocus('inner')); $this->assertEqual($browser->getFrameFocus(), array('inner')); $this->assertTrue($browser->setFrameFocus('one')); $this->assertEqual($browser->getFrameFocus(), array('inner', 'one')); $this->assertEqual($browser->getContent(), 'Page one'); $this->assertTrue($browser->setFrameFocus('two')); $this->assertEqual($browser->getFrameFocus(), array('inner', 'two')); $this->assertEqual($browser->getContent(), 'Page two'); $browser->clearFrameFocus(); $this->assertTrue($browser->setFrameFocus('three')); $this->assertEqual($browser->getFrameFocus(), array('three')); $this->assertEqual($browser->getContent(), 'Page three'); $this->assertTrue($browser->setFrameFocus('inner')); $this->assertEqual($browser->getContent(), 'Page onePage two'); } function testCanNavigateToNestedFrameByIndex() { $inner = '' . '' . '' . ''; $outer = '' . '' . '' . ''; $browser = &$this->createBrowser($this->createUserAgent(array( 'http://site.with.nested.frames/' => $outer, 'http://site.with.nested.frames/inner.html' => $inner, 'http://site.with.nested.frames/one.html' => 'Page one', 'http://site.with.nested.frames/two.html' => 'Page two', 'http://site.with.nested.frames/three.html' => 'Page three'))); $browser->get('http://site.with.nested.frames/'); $this->assertEqual($browser->getContent(), 'Page onePage twoPage three'); $this->assertTrue($browser->setFrameFocusByIndex(1)); $this->assertEqual($browser->getFrameFocus(), array(1)); $this->assertTrue($browser->setFrameFocusByIndex(1)); $this->assertEqual($browser->getFrameFocus(), array(1, 1)); $this->assertEqual($browser->getContent(), 'Page one'); $this->assertTrue($browser->setFrameFocusByIndex(2)); $this->assertEqual($browser->getFrameFocus(), array(1, 2)); $this->assertEqual($browser->getContent(), 'Page two'); $browser->clearFrameFocus(); $this->assertTrue($browser->setFrameFocusByIndex(2)); $this->assertEqual($browser->getFrameFocus(), array(2)); $this->assertEqual($browser->getContent(), 'Page three'); $this->assertTrue($browser->setFrameFocusByIndex(1)); $this->assertEqual($browser->getContent(), 'Page onePage two'); } } ?>postfixadmin-2.3.7/tests/simpletest/test/http_test.php0000664000175000017620000005044511157271050023327 0ustar davidpalepurpleexpectArgumentsAt(0, 'write', array("GET /here.html HTTP/1.0\r\n")); $socket->expectArgumentsAt(1, 'write', array("Host: a.valid.host\r\n")); $socket->expectArgumentsAt(2, 'write', array("Connection: close\r\n")); $socket->expectCallCount('write', 3); $route = &new PartialSimpleRoute(); $route->setReturnReference('_createSocket', $socket); $route->SimpleRoute(new SimpleUrl('http://a.valid.host/here.html')); $this->assertReference($route->createConnection('GET', 15), $socket); } function testDefaultPostRequest() { $socket = &new MockSimpleSocket(); $socket->expectArgumentsAt(0, 'write', array("POST /here.html HTTP/1.0\r\n")); $socket->expectArgumentsAt(1, 'write', array("Host: a.valid.host\r\n")); $socket->expectArgumentsAt(2, 'write', array("Connection: close\r\n")); $socket->expectCallCount('write', 3); $route = &new PartialSimpleRoute(); $route->setReturnReference('_createSocket', $socket); $route->SimpleRoute(new SimpleUrl('http://a.valid.host/here.html')); $route->createConnection('POST', 15); } function testGetWithPort() { $socket = &new MockSimpleSocket(); $socket->expectArgumentsAt(0, 'write', array("GET /here.html HTTP/1.0\r\n")); $socket->expectArgumentsAt(1, 'write', array("Host: a.valid.host:81\r\n")); $socket->expectArgumentsAt(2, 'write', array("Connection: close\r\n")); $socket->expectCallCount('write', 3); $route = &new PartialSimpleRoute(); $route->setReturnReference('_createSocket', $socket); $route->SimpleRoute(new SimpleUrl('http://a.valid.host:81/here.html')); $route->createConnection('GET', 15); } function testGetWithParameters() { $socket = &new MockSimpleSocket(); $socket->expectArgumentsAt(0, 'write', array("GET /here.html?a=1&b=2 HTTP/1.0\r\n")); $socket->expectArgumentsAt(1, 'write', array("Host: a.valid.host\r\n")); $socket->expectArgumentsAt(2, 'write', array("Connection: close\r\n")); $socket->expectCallCount('write', 3); $route = &new PartialSimpleRoute(); $route->setReturnReference('_createSocket', $socket); $route->SimpleRoute(new SimpleUrl('http://a.valid.host/here.html?a=1&b=2')); $route->createConnection('GET', 15); } } class TestOfProxyRoute extends UnitTestCase { function testDefaultGet() { $socket = &new MockSimpleSocket(); $socket->expectArgumentsAt(0, 'write', array("GET http://a.valid.host/here.html HTTP/1.0\r\n")); $socket->expectArgumentsAt(1, 'write', array("Host: my-proxy:8080\r\n")); $socket->expectArgumentsAt(2, 'write', array("Connection: close\r\n")); $socket->expectCallCount('write', 3); $route = &new PartialSimpleProxyRoute(); $route->setReturnReference('_createSocket', $socket); $route->SimpleProxyRoute( new SimpleUrl('http://a.valid.host/here.html'), new SimpleUrl('http://my-proxy')); $route->createConnection('GET', 15); } function testDefaultPost() { $socket = &new MockSimpleSocket(); $socket->expectArgumentsAt(0, 'write', array("POST http://a.valid.host/here.html HTTP/1.0\r\n")); $socket->expectArgumentsAt(1, 'write', array("Host: my-proxy:8080\r\n")); $socket->expectArgumentsAt(2, 'write', array("Connection: close\r\n")); $socket->expectCallCount('write', 3); $route = &new PartialSimpleProxyRoute(); $route->setReturnReference('_createSocket', $socket); $route->SimpleProxyRoute( new SimpleUrl('http://a.valid.host/here.html'), new SimpleUrl('http://my-proxy')); $route->createConnection('POST', 15); } function testGetWithPort() { $socket = &new MockSimpleSocket(); $socket->expectArgumentsAt(0, 'write', array("GET http://a.valid.host:81/here.html HTTP/1.0\r\n")); $socket->expectArgumentsAt(1, 'write', array("Host: my-proxy:8081\r\n")); $socket->expectArgumentsAt(2, 'write', array("Connection: close\r\n")); $socket->expectCallCount('write', 3); $route = &new PartialSimpleProxyRoute(); $route->setReturnReference('_createSocket', $socket); $route->SimpleProxyRoute( new SimpleUrl('http://a.valid.host:81/here.html'), new SimpleUrl('http://my-proxy:8081')); $route->createConnection('GET', 15); } function testGetWithParameters() { $socket = &new MockSimpleSocket(); $socket->expectArgumentsAt(0, 'write', array("GET http://a.valid.host/here.html?a=1&b=2 HTTP/1.0\r\n")); $socket->expectArgumentsAt(1, 'write', array("Host: my-proxy:8080\r\n")); $socket->expectArgumentsAt(2, 'write', array("Connection: close\r\n")); $socket->expectCallCount('write', 3); $route = &new PartialSimpleProxyRoute(); $route->setReturnReference('_createSocket', $socket); $route->SimpleProxyRoute( new SimpleUrl('http://a.valid.host/here.html?a=1&b=2'), new SimpleUrl('http://my-proxy')); $route->createConnection('GET', 15); } function testGetWithAuthentication() { $encoded = base64_encode('Me:Secret'); $socket = &new MockSimpleSocket(); $socket->expectArgumentsAt(0, 'write', array("GET http://a.valid.host/here.html HTTP/1.0\r\n")); $socket->expectArgumentsAt(1, 'write', array("Host: my-proxy:8080\r\n")); $socket->expectArgumentsAt(2, 'write', array("Proxy-Authorization: Basic $encoded\r\n")); $socket->expectArgumentsAt(3, 'write', array("Connection: close\r\n")); $socket->expectCallCount('write', 4); $route = &new PartialSimpleProxyRoute(); $route->setReturnReference('_createSocket', $socket); $route->SimpleProxyRoute( new SimpleUrl('http://a.valid.host/here.html'), new SimpleUrl('http://my-proxy'), 'Me', 'Secret'); $route->createConnection('GET', 15); } } class TestOfHttpRequest extends UnitTestCase { function testReadingBadConnection() { $socket = &new MockSimpleSocket(); $route = &new MockSimpleRoute(); $route->setReturnReference('createConnection', $socket); $request = &new SimpleHttpRequest($route, new SimpleGetEncoding()); $reponse = &$request->fetch(15); $this->assertTrue($reponse->isError()); } function testReadingGoodConnection() { $socket = &new MockSimpleSocket(); $socket->expectOnce('write', array("\r\n")); $route = &new MockSimpleRoute(); $route->setReturnReference('createConnection', $socket); $route->expectArguments('createConnection', array('GET', 15)); $request = &new SimpleHttpRequest($route, new SimpleGetEncoding()); $this->assertIsA($request->fetch(15), 'SimpleHttpResponse'); } function testWritingAdditionalHeaders() { $socket = &new MockSimpleSocket(); $socket->expectArgumentsAt(0, 'write', array("My: stuff\r\n")); $socket->expectArgumentsAt(1, 'write', array("\r\n")); $socket->expectCallCount('write', 2); $route = &new MockSimpleRoute(); $route->setReturnReference('createConnection', $socket); $request = &new SimpleHttpRequest($route, new SimpleGetEncoding()); $request->addHeaderLine('My: stuff'); $request->fetch(15); } function testCookieWriting() { $socket = &new MockSimpleSocket(); $socket->expectArgumentsAt(0, 'write', array("Cookie: a=A\r\n")); $socket->expectArgumentsAt(1, 'write', array("\r\n")); $socket->expectCallCount('write', 2); $route = &new MockSimpleRoute(); $route->setReturnReference('createConnection', $socket); $jar = new SimpleCookieJar(); $jar->setCookie('a', 'A'); $request = &new SimpleHttpRequest($route, new SimpleGetEncoding()); $request->readCookiesFromJar($jar, new SimpleUrl('/')); $this->assertIsA($request->fetch(15), 'SimpleHttpResponse'); } function testMultipleCookieWriting() { $socket = &new MockSimpleSocket(); $socket->expectArgumentsAt(0, 'write', array("Cookie: a=A;b=B\r\n")); $route = &new MockSimpleRoute(); $route->setReturnReference('createConnection', $socket); $jar = new SimpleCookieJar(); $jar->setCookie('a', 'A'); $jar->setCookie('b', 'B'); $request = &new SimpleHttpRequest($route, new SimpleGetEncoding()); $request->readCookiesFromJar($jar, new SimpleUrl('/')); $request->fetch(15); } } class TestOfHttpPostRequest extends UnitTestCase { function testReadingBadConnectionCausesErrorBecauseOfDeadSocket() { $socket = &new MockSimpleSocket(); $route = &new MockSimpleRoute(); $route->setReturnReference('createConnection', $socket); $request = &new SimpleHttpRequest($route, new SimplePostEncoding()); $reponse = &$request->fetch(15); $this->assertTrue($reponse->isError()); } function testReadingGoodConnection() { $socket = &new MockSimpleSocket(); $socket->expectArgumentsAt(0, 'write', array("Content-Length: 0\r\n")); $socket->expectArgumentsAt(1, 'write', array("Content-Type: application/x-www-form-urlencoded\r\n")); $socket->expectArgumentsAt(2, 'write', array("\r\n")); $socket->expectArgumentsAt(3, 'write', array("")); $route = &new MockSimpleRoute(); $route->setReturnReference('createConnection', $socket); $route->expectArguments('createConnection', array('POST', 15)); $request = &new SimpleHttpRequest($route, new SimplePostEncoding()); $this->assertIsA($request->fetch(15), 'SimpleHttpResponse'); } function testContentHeadersCalculated() { $socket = &new MockSimpleSocket(); $socket->expectArgumentsAt(0, 'write', array("Content-Length: 3\r\n")); $socket->expectArgumentsAt(1, 'write', array("Content-Type: application/x-www-form-urlencoded\r\n")); $socket->expectArgumentsAt(2, 'write', array("\r\n")); $socket->expectArgumentsAt(3, 'write', array("a=A")); $route = &new MockSimpleRoute(); $route->setReturnReference('createConnection', $socket); $route->expectArguments('createConnection', array('POST', 15)); $request = &new SimpleHttpRequest( $route, new SimplePostEncoding(array('a' => 'A'))); $this->assertIsA($request->fetch(15), 'SimpleHttpResponse'); } } class TestOfHttpHeaders extends UnitTestCase { function testParseBasicHeaders() { $headers = new SimpleHttpHeaders( "HTTP/1.1 200 OK\r\n" . "Date: Mon, 18 Nov 2002 15:50:29 GMT\r\n" . "Content-Type: text/plain\r\n" . "Server: Apache/1.3.24 (Win32) PHP/4.2.3\r\n" . "Connection: close"); $this->assertIdentical($headers->getHttpVersion(), "1.1"); $this->assertIdentical($headers->getResponseCode(), 200); $this->assertEqual($headers->getMimeType(), "text/plain"); } function testNonStandardResponseHeader() { $headers = new SimpleHttpHeaders( "HTTP/1.1 302 (HTTP-Version SP Status-Code CRLF)\r\n" . "Connection: close"); $this->assertIdentical($headers->getResponseCode(), 302); } function testCanParseMultipleCookies() { $jar = &new MockSimpleCookieJar(); $jar->expectAt(0, 'setCookie', array('a', 'aaa', 'host', '/here/', 'Wed, 25 Dec 2002 04:24:20 GMT')); $jar->expectAt(1, 'setCookie', array('b', 'bbb', 'host', '/', false)); $headers = new SimpleHttpHeaders( "HTTP/1.1 200 OK\r\n" . "Date: Mon, 18 Nov 2002 15:50:29 GMT\r\n" . "Content-Type: text/plain\r\n" . "Server: Apache/1.3.24 (Win32) PHP/4.2.3\r\n" . "Set-Cookie: a=aaa; expires=Wed, 25-Dec-02 04:24:20 GMT; path=/here/\r\n" . "Set-Cookie: b=bbb\r\n" . "Connection: close"); $headers->writeCookiesToJar($jar, new SimpleUrl('http://host')); } function testCanRecogniseRedirect() { $headers = new SimpleHttpHeaders("HTTP/1.1 301 OK\r\n" . "Content-Type: text/plain\r\n" . "Content-Length: 0\r\n" . "Location: http://www.somewhere-else.com/\r\n" . "Connection: close"); $this->assertIdentical($headers->getResponseCode(), 301); $this->assertEqual($headers->getLocation(), "http://www.somewhere-else.com/"); $this->assertTrue($headers->isRedirect()); } function testCanParseChallenge() { $headers = new SimpleHttpHeaders("HTTP/1.1 401 Authorization required\r\n" . "Content-Type: text/plain\r\n" . "Connection: close\r\n" . "WWW-Authenticate: Basic realm=\"Somewhere\""); $this->assertEqual($headers->getAuthentication(), 'Basic'); $this->assertEqual($headers->getRealm(), 'Somewhere'); $this->assertTrue($headers->isChallenge()); } } class TestOfHttpResponse extends UnitTestCase { function testBadRequest() { $socket = &new MockSimpleSocket(); $socket->setReturnValue('getSent', ''); $response = &new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding()); $this->assertTrue($response->isError()); $this->assertPattern('/Nothing fetched/', $response->getError()); $this->assertIdentical($response->getContent(), false); $this->assertIdentical($response->getSent(), ''); } function testBadSocketDuringResponse() { $socket = &new MockSimpleSocket(); $socket->setReturnValueAt(0, "read", "HTTP/1.1 200 OK\r\n"); $socket->setReturnValueAt(1, "read", "Date: Mon, 18 Nov 2002 15:50:29 GMT\r\n"); $socket->setReturnValue("read", ""); $socket->setReturnValue('getSent', 'HTTP/1.1 ...'); $response = &new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding()); $this->assertTrue($response->isError()); $this->assertEqual($response->getContent(), ''); $this->assertEqual($response->getSent(), 'HTTP/1.1 ...'); } function testIncompleteHeader() { $socket = &new MockSimpleSocket(); $socket->setReturnValueAt(0, "read", "HTTP/1.1 200 OK\r\n"); $socket->setReturnValueAt(1, "read", "Date: Mon, 18 Nov 2002 15:50:29 GMT\r\n"); $socket->setReturnValueAt(2, "read", "Content-Type: text/plain\r\n"); $socket->setReturnValue("read", ""); $response = &new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding()); $this->assertTrue($response->isError()); $this->assertEqual($response->getContent(), ""); } function testParseOfResponseHeadersWhenChunked() { $socket = &new MockSimpleSocket(); $socket->setReturnValueAt(0, "read", "HTTP/1.1 200 OK\r\nDate: Mon, 18 Nov 2002 15:50:29 GMT\r\n"); $socket->setReturnValueAt(1, "read", "Content-Type: text/plain\r\n"); $socket->setReturnValueAt(2, "read", "Server: Apache/1.3.24 (Win32) PHP/4.2.3\r\nConne"); $socket->setReturnValueAt(3, "read", "ction: close\r\n\r\nthis is a test file\n"); $socket->setReturnValueAt(4, "read", "with two lines in it\n"); $socket->setReturnValue("read", ""); $response = &new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding()); $this->assertFalse($response->isError()); $this->assertEqual( $response->getContent(), "this is a test file\nwith two lines in it\n"); $headers = $response->getHeaders(); $this->assertIdentical($headers->getHttpVersion(), "1.1"); $this->assertIdentical($headers->getResponseCode(), 200); $this->assertEqual($headers->getMimeType(), "text/plain"); $this->assertFalse($headers->isRedirect()); $this->assertFalse($headers->getLocation()); } function testRedirect() { $socket = &new MockSimpleSocket(); $socket->setReturnValueAt(0, "read", "HTTP/1.1 301 OK\r\n"); $socket->setReturnValueAt(1, "read", "Content-Type: text/plain\r\n"); $socket->setReturnValueAt(2, "read", "Location: http://www.somewhere-else.com/\r\n"); $socket->setReturnValueAt(3, "read", "Connection: close\r\n"); $socket->setReturnValueAt(4, "read", "\r\n"); $socket->setReturnValue("read", ""); $response = &new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding()); $headers = $response->getHeaders(); $this->assertTrue($headers->isRedirect()); $this->assertEqual($headers->getLocation(), "http://www.somewhere-else.com/"); } function testRedirectWithPort() { $socket = &new MockSimpleSocket(); $socket->setReturnValueAt(0, "read", "HTTP/1.1 301 OK\r\n"); $socket->setReturnValueAt(1, "read", "Content-Type: text/plain\r\n"); $socket->setReturnValueAt(2, "read", "Location: http://www.somewhere-else.com:80/\r\n"); $socket->setReturnValueAt(3, "read", "Connection: close\r\n"); $socket->setReturnValueAt(4, "read", "\r\n"); $socket->setReturnValue("read", ""); $response = &new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding()); $headers = $response->getHeaders(); $this->assertTrue($headers->isRedirect()); $this->assertEqual($headers->getLocation(), "http://www.somewhere-else.com:80/"); } } ?>postfixadmin-2.3.7/tests/simpletest/test/live_test.php0000664000175000017620000000373711157271050023311 0ustar davidpalepurpleassertTrue($socket->isError()); $this->assertPattern( '/Cannot open \\[bad_url:111\\] with \\[/', $socket->getError()); $this->assertFalse($socket->isOpen()); $this->assertFalse($socket->write('A message')); } function testSocketClosure() { $socket = &new SimpleSocket('www.lastcraft.com', 80, 15, 8); $this->assertTrue($socket->isOpen()); $this->assertTrue($socket->write("GET /test/network_confirm.php HTTP/1.0\r\n")); $socket->write("Host: www.lastcraft.com\r\n"); $socket->write("Connection: close\r\n\r\n"); $this->assertEqual($socket->read(), "HTTP/1.1"); $socket->close(); $this->assertIdentical($socket->read(), false); } function testRecordOfSentCharacters() { $socket = &new SimpleSocket('www.lastcraft.com', 80, 15); $this->assertTrue($socket->write("GET /test/network_confirm.php HTTP/1.0\r\n")); $socket->write("Host: www.lastcraft.com\r\n"); $socket->write("Connection: close\r\n\r\n"); $socket->close(); $this->assertEqual($socket->getSent(), "GET /test/network_confirm.php HTTP/1.0\r\n" . "Host: www.lastcraft.com\r\n" . "Connection: close\r\n\r\n"); } } ?>postfixadmin-2.3.7/tests/simpletest/test/detached_test.php0000664000175000017620000000100711157271050024077 0ustar davidpalepurpleaddTestCase(new DetachedTestCase($command)); if (SimpleReporter::inCli()) { exit ($test->run(new TextReporter()) ? 0 : 1); } $test->run(new HtmlReporter()); ?>postfixadmin-2.3.7/tests/simpletest/test/unit_tests.php0000664000175000017620000000104711157271050023504 0ustar davidpalepurplerun(new SelectiveReporter(new TextReporter(), @$argv[1], @$argv[2])); return ($result ? 0 : 1); } $test->run(new SelectiveReporter(new HtmlReporter(), @$_GET['c'], @$_GET['t'])); } ?>postfixadmin-2.3.7/tests/simpletest/test/collector_test.php0000664000175000017620000000335411157271050024333 0ustar davidpalepurpleEqualExpectation($v = str_replace("\\", '/', $value), $message); } function test($compare) { return parent::test(str_replace("\\", '/', $compare)); } } class TestOfCollector extends UnitTestCase { function testCollectionIsAddedToGroup() { $suite = &new MockTestSuite(); $suite->expectMinimumCallCount('addTestFile', 2); $suite->expectArguments( 'addTestFile', array(new PatternExpectation('/collectable\\.(1|2)$/'))); $collector = &new SimpleCollector(); $collector->collect($suite, dirname(__FILE__) . '/support/collector/'); } } class TestOfPatternCollector extends UnitTestCase { function testAddingEverythingToGroup() { $suite = &new MockTestSuite(); $suite->expectCallCount('addTestFile', 2); $suite->expectArguments( 'addTestFile', array(new PatternExpectation('/collectable\\.(1|2)$/'))); $collector = &new SimplePatternCollector('/.*/'); $collector->collect($suite, dirname(__FILE__) . '/support/collector/'); } function testOnlyMatchedFilesAreAddedToGroup() { $suite = &new MockTestSuite(); $suite->expectOnce('addTestFile', array(new PathEqualExpectation( dirname(__FILE__) . '/support/collector/collectable.1'))); $collector = &new SimplePatternCollector('/1$/'); $collector->collect($suite, dirname(__FILE__) . '/support/collector/'); } } ?>postfixadmin-2.3.7/tests/simpletest/test/reflection_php5_test.php0000664000175000017620000001617711157271050025442 0ustar davidpalepurpleassertTrue($reflection->classOrInterfaceExists()); $this->assertTrue($reflection->classOrInterfaceExistsSansAutoload()); $this->assertFalse($reflection->isAbstract()); $this->assertFalse($reflection->isInterface()); } function testClassNonExistence() { $reflection = new SimpleReflection('UnknownThing'); $this->assertFalse($reflection->classOrInterfaceExists()); $this->assertFalse($reflection->classOrInterfaceExistsSansAutoload()); } function testDetectionOfAbstractClass() { $reflection = new SimpleReflection('AnyOldClass'); $this->assertTrue($reflection->isAbstract()); } function testFindingParentClass() { $reflection = new SimpleReflection('AnyOldSubclass'); $this->assertEqual($reflection->getParent(), 'AnyOldImplementation'); } function testInterfaceExistence() { $reflection = new SimpleReflection('AnyOldInterface'); $this->assertTrue( $reflection->classOrInterfaceExists()); $this->assertTrue( $reflection->classOrInterfaceExistsSansAutoload()); $this->assertTrue($reflection->isInterface()); } function testMethodsListFromClass() { $reflection = new SimpleReflection('AnyOldClass'); $this->assertIdentical($reflection->getMethods(), array('aMethod')); } function testMethodsListFromInterface() { $reflection = new SimpleReflection('AnyOldInterface'); $this->assertIdentical($reflection->getMethods(), array('aMethod')); $this->assertIdentical($reflection->getInterfaceMethods(), array('aMethod')); } function testMethodsComeFromDescendentInterfacesASWell() { $reflection = new SimpleReflection('AnyDescendentInterface'); $this->assertIdentical($reflection->getMethods(), array('aMethod')); } function testCanSeparateInterfaceMethodsFromOthers() { $reflection = new SimpleReflection('AnyOldImplementation'); $this->assertIdentical($reflection->getMethods(), array('aMethod', 'extraMethod')); $this->assertIdentical($reflection->getInterfaceMethods(), array('aMethod')); } function testMethodsComeFromDescendentInterfacesInAbstractClass() { $reflection = new SimpleReflection('AnyAbstractImplementation'); $this->assertIdentical($reflection->getMethods(), array('aMethod')); } function testInterfaceHasOnlyItselfToImplement() { $reflection = new SimpleReflection('AnyOldInterface'); $this->assertEqual( $reflection->getInterfaces(), array('AnyOldInterface')); } function testInterfacesListedForClass() { $reflection = new SimpleReflection('AnyOldImplementation'); $this->assertEqual( $reflection->getInterfaces(), array('AnyOldInterface')); } function testInterfacesListedForSubclass() { $reflection = new SimpleReflection('AnyOldSubclass'); $this->assertEqual( $reflection->getInterfaces(), array('AnyOldInterface')); } function testNoParameterCreationWhenNoInterface() { $reflection = new SimpleReflection('AnyOldArgumentClass'); $function = $reflection->getSignature('aMethod'); if (version_compare(phpversion(), '5.0.2', '<=')) { $this->assertEqual('function amethod()', strtolower($function)); } else { $this->assertEqual('function aMethod()', $function); } } function testParameterCreationWithoutTypeHinting() { $reflection = new SimpleReflection('AnyOldArgumentImplementation'); $function = $reflection->getSignature('aMethod'); if (version_compare(phpversion(), '5.0.2', '<=')) { $this->assertEqual('function amethod(AnyOldInterface $argument)', $function); } else { $this->assertEqual('function aMethod(AnyOldInterface $argument)', $function); } } function testParameterCreationForTypeHinting() { $reflection = new SimpleReflection('AnyOldTypeHintedClass'); $function = $reflection->getSignature('aMethod'); if (version_compare(phpversion(), '5.0.2', '<=')) { $this->assertEqual('function amethod(AnyOldInterface $argument)', $function); } else { $this->assertEqual('function aMethod(AnyOldInterface $argument)', $function); } } function testIssetFunctionSignature() { $reflection = new SimpleReflection('AnyOldOverloadedClass'); $function = $reflection->getSignature('__isset'); if (version_compare(phpversion(), '5.1.0', '>=')) { $this->assertEqual('function __isset($key)', $function); } else { $this->assertEqual('function __isset()', $function); } } function testUnsetFunctionSignature() { $reflection = new SimpleReflection('AnyOldOverloadedClass'); $function = $reflection->getSignature('__unset'); if (version_compare(phpversion(), '5.1.0', '>=')) { $this->assertEqual('function __unset($key)', $function); } else { $this->assertEqual('function __unset()', $function); } } function testProperlyReflectsTheFinalInterfaceWhenObjectImplementsAnExtendedInterface() { $reflection = new SimpleReflection('AnyDescendentImplementation'); $interfaces = $reflection->getInterfaces(); $this->assertEqual(1, count($interfaces)); $this->assertEqual('AnyDescendentInterface', array_shift($interfaces)); } } ?> postfixadmin-2.3.7/tests/simpletest/test/remote_test.php0000664000175000017620000000145711157271050023642 0ustar davidpalepurpleaddTestCase(new RemoteTestCase($test_url . '?xml=yes', $test_url . '?xml=yes&dry=yes')); if (SimpleReporter::inCli()) { exit ($test->run(new TextReporter()) ? 0 : 1); } $test->run(new HtmlReporter()); ?>postfixadmin-2.3.7/tests/simpletest/test/all_tests.php0000664000175000017620000000105011157271050023267 0ustar davidpalepurplerun(new SelectiveReporter(new TextReporter(), @$argv[1], @$argv[2])); return ($result ? 0 : 1); } $test->run(new SelectiveReporter(new HtmlReporter(), @$_GET['c'], @$_GET['t'])); ?> postfixadmin-2.3.7/tests/simpletest/test/support/0000775000175000017620000000000012301477471022313 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/test/support/latin1_sample0000664000175000017620000000002211157271050024752 0ustar davidpalepurple@櫻postfixadmin-2.3.7/tests/simpletest/test/support/spl_examples.php0000664000175000017620000000062111157271050025510 0ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/test/support/supplementary_upload_sample.txt0000664000175000017620000000002611157271050030660 0ustar davidpalepurpleSome more text contentpostfixadmin-2.3.7/tests/simpletest/test/support/upload_sample.txt0000664000175000017620000000003611157271050025671 0ustar davidpalepurpleSample for testing file uploadpostfixadmin-2.3.7/tests/simpletest/test/support/test1.php0000664000175000017620000000015611157271050024057 0ustar davidpalepurpleassertEqual(3,1+2, "pass1"); } } ?> postfixadmin-2.3.7/tests/simpletest/test/support/collector/0000775000175000017620000000000012301477471024301 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/test/support/collector/collectable.10000664000175000017620000000000011157271050026613 0ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/test/support/collector/collectable.20000664000175000017620000000000011157271050026614 0ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/test/authentication_test.php0000664000175000017620000001406011157271050025360 0ustar davidpalepurpleassertTrue($realm->isWithin( new SimpleUrl('http://www.here.com/path/hello.html'))); } function testInsideWithLongerUrl() { $realm = &new SimpleRealm( 'Basic', new SimpleUrl('http://www.here.com/path/')); $this->assertTrue($realm->isWithin( new SimpleUrl('http://www.here.com/path/hello.html'))); } function testBelowRootIsOutside() { $realm = &new SimpleRealm( 'Basic', new SimpleUrl('http://www.here.com/path/')); $this->assertTrue($realm->isWithin( new SimpleUrl('http://www.here.com/path/more/hello.html'))); } function testOldNetscapeDefinitionIsOutside() { $realm = &new SimpleRealm( 'Basic', new SimpleUrl('http://www.here.com/path/')); $this->assertFalse($realm->isWithin( new SimpleUrl('http://www.here.com/pathmore/hello.html'))); } function testInsideWithMissingTrailingSlash() { $realm = &new SimpleRealm( 'Basic', new SimpleUrl('http://www.here.com/path/')); $this->assertTrue($realm->isWithin( new SimpleUrl('http://www.here.com/path'))); } function testDifferentPageNameStillInside() { $realm = &new SimpleRealm( 'Basic', new SimpleUrl('http://www.here.com/path/hello.html')); $this->assertTrue($realm->isWithin( new SimpleUrl('http://www.here.com/path/goodbye.html'))); } function testNewUrlInSameDirectoryDoesNotChangeRealm() { $realm = &new SimpleRealm( 'Basic', new SimpleUrl('http://www.here.com/path/hello.html')); $realm->stretch(new SimpleUrl('http://www.here.com/path/goodbye.html')); $this->assertTrue($realm->isWithin( new SimpleUrl('http://www.here.com/path/index.html'))); $this->assertFalse($realm->isWithin( new SimpleUrl('http://www.here.com/index.html'))); } function testNewUrlMakesRealmTheCommonPath() { $realm = &new SimpleRealm( 'Basic', new SimpleUrl('http://www.here.com/path/here/hello.html')); $realm->stretch(new SimpleUrl('http://www.here.com/path/there/goodbye.html')); $this->assertTrue($realm->isWithin( new SimpleUrl('http://www.here.com/path/here/index.html'))); $this->assertTrue($realm->isWithin( new SimpleUrl('http://www.here.com/path/there/index.html'))); $this->assertTrue($realm->isWithin( new SimpleUrl('http://www.here.com/path/index.html'))); $this->assertFalse($realm->isWithin( new SimpleUrl('http://www.here.com/index.html'))); $this->assertFalse($realm->isWithin( new SimpleUrl('http://www.here.com/paths/index.html'))); $this->assertFalse($realm->isWithin( new SimpleUrl('http://www.here.com/pathindex.html'))); } } class TestOfAuthenticator extends UnitTestCase { function testNoRealms() { $request = &new MockSimpleHttpRequest(); $request->expectNever('addHeaderLine'); $authenticator = &new SimpleAuthenticator(); $authenticator->addHeaders($request, new SimpleUrl('http://here.com/')); } function &createSingleRealm() { $authenticator = &new SimpleAuthenticator(); $authenticator->addRealm( new SimpleUrl('http://www.here.com/path/hello.html'), 'Basic', 'Sanctuary'); $authenticator->setIdentityForRealm('www.here.com', 'Sanctuary', 'test', 'secret'); return $authenticator; } function testOutsideRealm() { $request = &new MockSimpleHttpRequest(); $request->expectNever('addHeaderLine'); $authenticator = &$this->createSingleRealm(); $authenticator->addHeaders( $request, new SimpleUrl('http://www.here.com/hello.html')); } function testWithinRealm() { $request = &new MockSimpleHttpRequest(); $request->expectOnce('addHeaderLine'); $authenticator = &$this->createSingleRealm(); $authenticator->addHeaders( $request, new SimpleUrl('http://www.here.com/path/more/hello.html')); } function testRestartingClearsRealm() { $request = &new MockSimpleHttpRequest(); $request->expectNever('addHeaderLine'); $authenticator = &$this->createSingleRealm(); $authenticator->restartSession(); $authenticator->addHeaders( $request, new SimpleUrl('http://www.here.com/hello.html')); } function testDifferentHostIsOutsideRealm() { $request = &new MockSimpleHttpRequest(); $request->expectNever('addHeaderLine'); $authenticator = &$this->createSingleRealm(); $authenticator->addHeaders( $request, new SimpleUrl('http://here.com/path/hello.html')); } } ?>postfixadmin-2.3.7/tests/simpletest/test/user_agent_test.php0000664000175000017620000003711211157271050024500 0ustar davidpalepurple_headers = &new MockSimpleHttpHeaders(); $this->_response = &new MockSimpleHttpResponse(); $this->_response->setReturnValue('isError', false); $this->_response->setReturnReference('getHeaders', new MockSimpleHttpHeaders()); $this->_request = &new MockSimpleHttpRequest(); $this->_request->setReturnReference('fetch', $this->_response); } function testGetRequestWithoutIncidentGivesNoErrors() { $url = new SimpleUrl('http://test:secret@this.com/page.html'); $url->addRequestParameters(array('a' => 'A', 'b' => 'B')); $agent = &new MockRequestUserAgent(); $agent->setReturnReference('_createHttpRequest', $this->_request); $agent->SimpleUserAgent(); $response = &$agent->fetchResponse( new SimpleUrl('http://test:secret@this.com/page.html'), new SimpleGetEncoding(array('a' => 'A', 'b' => 'B'))); $this->assertFalse($response->isError()); } } class TestOfAdditionalHeaders extends UnitTestCase { function testAdditionalHeaderAddedToRequest() { $response = &new MockSimpleHttpResponse(); $response->setReturnReference('getHeaders', new MockSimpleHttpHeaders()); $request = &new MockSimpleHttpRequest(); $request->setReturnReference('fetch', $response); $request->expectOnce( 'addHeaderLine', array('User-Agent: SimpleTest')); $agent = &new MockRequestUserAgent(); $agent->setReturnReference('_createHttpRequest', $request); $agent->SimpleUserAgent(); $agent->addHeader('User-Agent: SimpleTest'); $response = &$agent->fetchResponse(new SimpleUrl('http://this.host/'), new SimpleGetEncoding()); } } class TestOfBrowserCookies extends UnitTestCase { function &_createStandardResponse() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue("isError", false); $response->setReturnValue("getContent", "stuff"); $response->setReturnReference("getHeaders", new MockSimpleHttpHeaders()); return $response; } function &_createCookieSite($header_lines) { $headers = &new SimpleHttpHeaders($header_lines); $response = &new MockSimpleHttpResponse(); $response->setReturnValue("isError", false); $response->setReturnReference("getHeaders", $headers); $response->setReturnValue("getContent", "stuff"); $request = &new MockSimpleHttpRequest(); $request->setReturnReference("fetch", $response); return $request; } function &_createMockedRequestUserAgent(&$request) { $agent = &new MockRequestUserAgent(); $agent->setReturnReference('_createHttpRequest', $request); $agent->SimpleUserAgent(); return $agent; } function testCookieJarIsSentToRequest() { $jar = new SimpleCookieJar(); $jar->setCookie('a', 'A'); $request = &new MockSimpleHttpRequest(); $request->setReturnReference('fetch', $this->_createStandardResponse()); $request->expectOnce('readCookiesFromJar', array($jar, '*')); $agent = &$this->_createMockedRequestUserAgent($request); $agent->setCookie('a', 'A'); $agent->fetchResponse( new SimpleUrl('http://this.com/this/path/page.html'), new SimpleGetEncoding()); } function testNoCookieJarIsSentToRequestWhenCookiesAreDisabled() { $request = &new MockSimpleHttpRequest(); $request->setReturnReference('fetch', $this->_createStandardResponse()); $request->expectNever('readCookiesFromJar'); $agent = &$this->_createMockedRequestUserAgent($request); $agent->setCookie('a', 'A'); $agent->ignoreCookies(); $agent->fetchResponse( new SimpleUrl('http://this.com/this/path/page.html'), new SimpleGetEncoding()); } function testReadingNewCookie() { $request = &$this->_createCookieSite('Set-cookie: a=AAAA'); $agent = &$this->_createMockedRequestUserAgent($request); $agent->fetchResponse( new SimpleUrl('http://this.com/this/path/page.html'), new SimpleGetEncoding()); $this->assertEqual($agent->getCookieValue("this.com", "this/path/", "a"), "AAAA"); } function testIgnoringNewCookieWhenCookiesDisabled() { $request = &$this->_createCookieSite('Set-cookie: a=AAAA'); $agent = &$this->_createMockedRequestUserAgent($request); $agent->ignoreCookies(); $agent->fetchResponse( new SimpleUrl('http://this.com/this/path/page.html'), new SimpleGetEncoding()); $this->assertIdentical($agent->getCookieValue("this.com", "this/path/", "a"), false); } function testOverwriteCookieThatAlreadyExists() { $request = &$this->_createCookieSite('Set-cookie: a=AAAA'); $agent = &$this->_createMockedRequestUserAgent($request); $agent->setCookie('a', 'A'); $agent->fetchResponse( new SimpleUrl('http://this.com/this/path/page.html'), new SimpleGetEncoding()); $this->assertEqual($agent->getCookieValue("this.com", "this/path/", "a"), "AAAA"); } function testClearCookieBySettingExpiry() { $request = &$this->_createCookieSite('Set-cookie: a=b'); $agent = &$this->_createMockedRequestUserAgent($request); $agent->setCookie("a", "A", "this/path/", "Wed, 25-Dec-02 04:24:21 GMT"); $agent->fetchResponse( new SimpleUrl('http://this.com/this/path/page.html'), new SimpleGetEncoding()); $this->assertIdentical( $agent->getCookieValue("this.com", "this/path/", "a"), "b"); $agent->restart("Wed, 25-Dec-02 04:24:20 GMT"); $this->assertIdentical( $agent->getCookieValue("this.com", "this/path/", "a"), false); } function testAgeingAndClearing() { $request = &$this->_createCookieSite('Set-cookie: a=A; expires=Wed, 25-Dec-02 04:24:21 GMT; path=/this/path'); $agent = &$this->_createMockedRequestUserAgent($request); $agent->fetchResponse( new SimpleUrl('http://this.com/this/path/page.html'), new SimpleGetEncoding()); $agent->restart("Wed, 25-Dec-02 04:24:20 GMT"); $this->assertIdentical( $agent->getCookieValue("this.com", "this/path/", "a"), "A"); $agent->ageCookies(2); $agent->restart("Wed, 25-Dec-02 04:24:20 GMT"); $this->assertIdentical( $agent->getCookieValue("this.com", "this/path/", "a"), false); } function testReadingIncomingAndSettingNewCookies() { $request = &$this->_createCookieSite('Set-cookie: a=AAA'); $agent = &$this->_createMockedRequestUserAgent($request); $this->assertNull($agent->getBaseCookieValue("a", false)); $agent->fetchResponse( new SimpleUrl('http://this.com/this/path/page.html'), new SimpleGetEncoding()); $agent->setCookie("b", "BBB", "this.com", "this/path/"); $this->assertEqual( $agent->getBaseCookieValue("a", new SimpleUrl('http://this.com/this/path/page.html')), "AAA"); $this->assertEqual( $agent->getBaseCookieValue("b", new SimpleUrl('http://this.com/this/path/page.html')), "BBB"); } } class TestOfHttpRedirects extends UnitTestCase { function &createRedirect($content, $redirect) { $headers = &new MockSimpleHttpHeaders(); $headers->setReturnValue('isRedirect', (boolean)$redirect); $headers->setReturnValue('getLocation', $redirect); $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', $content); $response->setReturnReference('getHeaders', $headers); $request = &new MockSimpleHttpRequest(); $request->setReturnReference('fetch', $response); return $request; } function testDisabledRedirects() { $agent = &new MockRequestUserAgent(); $agent->setReturnReference( '_createHttpRequest', $this->createRedirect('stuff', 'there.html')); $agent->expectOnce('_createHttpRequest'); $agent->SimpleUserAgent(); $agent->setMaximumRedirects(0); $response = &$agent->fetchResponse(new SimpleUrl('here.html'), new SimpleGetEncoding()); $this->assertEqual($response->getContent(), 'stuff'); } function testSingleRedirect() { $agent = &new MockRequestUserAgent(); $agent->setReturnReferenceAt( 0, '_createHttpRequest', $this->createRedirect('first', 'two.html')); $agent->setReturnReferenceAt( 1, '_createHttpRequest', $this->createRedirect('second', 'three.html')); $agent->expectCallCount('_createHttpRequest', 2); $agent->SimpleUserAgent(); $agent->setMaximumRedirects(1); $response = &$agent->fetchResponse(new SimpleUrl('one.html'), new SimpleGetEncoding()); $this->assertEqual($response->getContent(), 'second'); } function testDoubleRedirect() { $agent = &new MockRequestUserAgent(); $agent->setReturnReferenceAt( 0, '_createHttpRequest', $this->createRedirect('first', 'two.html')); $agent->setReturnReferenceAt( 1, '_createHttpRequest', $this->createRedirect('second', 'three.html')); $agent->setReturnReferenceAt( 2, '_createHttpRequest', $this->createRedirect('third', 'four.html')); $agent->expectCallCount('_createHttpRequest', 3); $agent->SimpleUserAgent(); $agent->setMaximumRedirects(2); $response = &$agent->fetchResponse(new SimpleUrl('one.html'), new SimpleGetEncoding()); $this->assertEqual($response->getContent(), 'third'); } function testSuccessAfterRedirect() { $agent = &new MockRequestUserAgent(); $agent->setReturnReferenceAt( 0, '_createHttpRequest', $this->createRedirect('first', 'two.html')); $agent->setReturnReferenceAt( 1, '_createHttpRequest', $this->createRedirect('second', false)); $agent->setReturnReferenceAt( 2, '_createHttpRequest', $this->createRedirect('third', 'four.html')); $agent->expectCallCount('_createHttpRequest', 2); $agent->SimpleUserAgent(); $agent->setMaximumRedirects(2); $response = &$agent->fetchResponse(new SimpleUrl('one.html'), new SimpleGetEncoding()); $this->assertEqual($response->getContent(), 'second'); } function testRedirectChangesPostToGet() { $agent = &new MockRequestUserAgent(); $agent->setReturnReferenceAt( 0, '_createHttpRequest', $this->createRedirect('first', 'two.html')); $agent->expectArgumentsAt(0, '_createHttpRequest', array('*', new IsAExpectation('SimplePostEncoding'))); $agent->setReturnReferenceAt( 1, '_createHttpRequest', $this->createRedirect('second', 'three.html')); $agent->expectArgumentsAt(1, '_createHttpRequest', array('*', new IsAExpectation('SimpleGetEncoding'))); $agent->expectCallCount('_createHttpRequest', 2); $agent->SimpleUserAgent(); $agent->setMaximumRedirects(1); $response = &$agent->fetchResponse(new SimpleUrl('one.html'), new SimplePostEncoding()); } } class TestOfBadHosts extends UnitTestCase { function &_createSimulatedBadHost() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('isError', true); $response->setReturnValue('getError', 'Bad socket'); $response->setReturnValue('getContent', false); $request = &new MockSimpleHttpRequest(); $request->setReturnReference('fetch', $response); return $request; } function testUntestedHost() { $request = &$this->_createSimulatedBadHost(); $agent = &new MockRequestUserAgent(); $agent->setReturnReference('_createHttpRequest', $request); $agent->SimpleUserAgent(); $response = &$agent->fetchResponse( new SimpleUrl('http://this.host/this/path/page.html'), new SimpleGetEncoding()); $this->assertTrue($response->isError()); } } class TestOfAuthorisation extends UnitTestCase { function testAuthenticateHeaderAdded() { $response = &new MockSimpleHttpResponse(); $response->setReturnReference('getHeaders', new MockSimpleHttpHeaders()); $request = &new MockSimpleHttpRequest(); $request->setReturnReference('fetch', $response); $request->expectOnce( 'addHeaderLine', array('Authorization: Basic ' . base64_encode('test:secret'))); $agent = &new MockRequestUserAgent(); $agent->setReturnReference('_createHttpRequest', $request); $agent->SimpleUserAgent(); $response = &$agent->fetchResponse( new SimpleUrl('http://test:secret@this.host'), new SimpleGetEncoding()); } } ?>postfixadmin-2.3.7/tests/simpletest/test/reflection_php4_test.php0000664000175000017620000000406111157271050025426 0ustar davidpalepurpleassertTrue($reflection->classOrInterfaceExists()); $this->assertTrue($reflection->classOrInterfaceExistsSansAutoload()); } function testClassNonExistence() { $reflection = new SimpleReflection('UnknownThing'); $this->assertFalse($reflection->classOrInterfaceExists()); $this->assertFalse($reflection->classOrInterfaceExistsSansAutoload()); } function testDetectionOfInterfacesAlwaysFalse() { $reflection = new SimpleReflection('AnyOldThing'); $this->assertFalse($reflection->isAbstract()); $this->assertFalse($reflection->isInterface()); } function testFindingParentClass() { $reflection = new SimpleReflection('AnyOldChildThing'); $this->assertEqual(strtolower($reflection->getParent()), 'anyoldthing'); } function testMethodsListFromClass() { $reflection = new SimpleReflection('AnyOldThing'); $methods = $reflection->getMethods(); $this->assertEqualIgnoringCase($methods[0], 'aMethod'); } function testNoInterfacesForPHP4() { $reflection = new SimpleReflection('AnyOldThing'); $this->assertEqual( $reflection->getInterfaces(), array()); } function testMostGeneralPossibleSignature() { $reflection = new SimpleReflection('AnyOldThing'); $this->assertEqualIgnoringCase( $reflection->getSignature('aMethod'), 'function &aMethod()'); } function assertEqualIgnoringCase($a, $b) { return $this->assertEqual(strtolower($a), strtolower($b)); } } ?>postfixadmin-2.3.7/tests/simpletest/test/xml_test.php0000664000175000017620000001756511157271050023156 0ustar davidpalepurple 2)); $this->assertEqual($nesting->getSize(), 2); } } class TestOfXmlStructureParsing extends UnitTestCase { function testValidXml() { $listener = &new MockSimpleScorer(); $listener->expectNever('paintGroupStart'); $listener->expectNever('paintGroupEnd'); $listener->expectNever('paintCaseStart'); $listener->expectNever('paintCaseEnd'); $parser = &new SimpleTestXmlParser($listener); $this->assertTrue($parser->parse("\n")); $this->assertTrue($parser->parse("\n")); $this->assertTrue($parser->parse("\n")); } function testEmptyGroup() { $listener = &new MockSimpleScorer(); $listener->expectOnce('paintGroupStart', array('a_group', 7)); $listener->expectOnce('paintGroupEnd', array('a_group')); $parser = &new SimpleTestXmlParser($listener); $parser->parse("\n"); $parser->parse("\n"); $this->assertTrue($parser->parse("\n")); $this->assertTrue($parser->parse("a_group\n")); $this->assertTrue($parser->parse("\n")); $parser->parse("\n"); } function testEmptyCase() { $listener = &new MockSimpleScorer(); $listener->expectOnce('paintCaseStart', array('a_case')); $listener->expectOnce('paintCaseEnd', array('a_case')); $parser = &new SimpleTestXmlParser($listener); $parser->parse("\n"); $parser->parse("\n"); $this->assertTrue($parser->parse("\n")); $this->assertTrue($parser->parse("a_case\n")); $this->assertTrue($parser->parse("\n")); $parser->parse("\n"); } function testEmptyMethod() { $listener = &new MockSimpleScorer(); $listener->expectOnce('paintCaseStart', array('a_case')); $listener->expectOnce('paintCaseEnd', array('a_case')); $listener->expectOnce('paintMethodStart', array('a_method')); $listener->expectOnce('paintMethodEnd', array('a_method')); $parser = &new SimpleTestXmlParser($listener); $parser->parse("\n"); $parser->parse("\n"); $parser->parse("\n"); $parser->parse("a_case\n"); $this->assertTrue($parser->parse("\n")); $this->assertTrue($parser->parse("a_method\n")); $this->assertTrue($parser->parse("\n")); $parser->parse("\n"); $parser->parse("\n"); } function testNestedGroup() { $listener = &new MockSimpleScorer(); $listener->expectArgumentsAt(0, 'paintGroupStart', array('a_group', 7)); $listener->expectArgumentsAt(1, 'paintGroupStart', array('b_group', 3)); $listener->expectCallCount('paintGroupStart', 2); $listener->expectArgumentsAt(0, 'paintGroupEnd', array('b_group')); $listener->expectArgumentsAt(1, 'paintGroupEnd', array('a_group')); $listener->expectCallCount('paintGroupEnd', 2); $parser = &new SimpleTestXmlParser($listener); $parser->parse("\n"); $parser->parse("\n"); $this->assertTrue($parser->parse("\n")); $this->assertTrue($parser->parse("a_group\n")); $this->assertTrue($parser->parse("\n")); $this->assertTrue($parser->parse("b_group\n")); $this->assertTrue($parser->parse("\n")); $this->assertTrue($parser->parse("\n")); $parser->parse("\n"); } } class AnyOldSignal { var $stuff = true; } class TestOfXmlResultsParsing extends UnitTestCase { function sendValidStart(&$parser) { $parser->parse("\n"); $parser->parse("\n"); $parser->parse("\n"); $parser->parse("a_case\n"); $parser->parse("\n"); $parser->parse("a_method\n"); } function sendValidEnd(&$parser) { $parser->parse("\n"); $parser->parse("\n"); $parser->parse("\n"); } function testPass() { $listener = &new MockSimpleScorer(); $listener->expectOnce('paintPass', array('a_message')); $parser = &new SimpleTestXmlParser($listener); $this->sendValidStart($parser); $this->assertTrue($parser->parse("a_message\n")); $this->sendValidEnd($parser); } function testFail() { $listener = &new MockSimpleScorer(); $listener->expectOnce('paintFail', array('a_message')); $parser = &new SimpleTestXmlParser($listener); $this->sendValidStart($parser); $this->assertTrue($parser->parse("a_message\n")); $this->sendValidEnd($parser); } function testException() { $listener = &new MockSimpleScorer(); $listener->expectOnce('paintError', array('a_message')); $parser = &new SimpleTestXmlParser($listener); $this->sendValidStart($parser); $this->assertTrue($parser->parse("a_message\n")); $this->sendValidEnd($parser); } function testSkip() { $listener = &new MockSimpleScorer(); $listener->expectOnce('paintSkip', array('a_message')); $parser = &new SimpleTestXmlParser($listener); $this->sendValidStart($parser); $this->assertTrue($parser->parse("a_message\n")); $this->sendValidEnd($parser); } function testSignal() { $signal = new AnyOldSignal(); $signal->stuff = "Hello"; $listener = &new MockSimpleScorer(); $listener->expectOnce('paintSignal', array('a_signal', $signal)); $parser = &new SimpleTestXmlParser($listener); $this->sendValidStart($parser); $this->assertTrue($parser->parse( "\n")); $this->sendValidEnd($parser); } function testMessage() { $listener = &new MockSimpleScorer(); $listener->expectOnce('paintMessage', array('a_message')); $parser = &new SimpleTestXmlParser($listener); $this->sendValidStart($parser); $this->assertTrue($parser->parse("a_message\n")); $this->sendValidEnd($parser); } function testFormattedMessage() { $listener = &new MockSimpleScorer(); $listener->expectOnce('paintFormattedMessage', array("\na\tmessage\n")); $parser = &new SimpleTestXmlParser($listener); $this->sendValidStart($parser); $this->assertTrue($parser->parse("\n")); $this->sendValidEnd($parser); } } ?>postfixadmin-2.3.7/tests/simpletest/test/encoding_test.php0000664000175000017620000001716111157271050024134 0ustar davidpalepurpleassertEqual($pair->asRequest(), 'a=A'); } function testMimeEncodedAsHeadersAndContent() { $pair = new SimpleEncodedPair('a', 'A'); $this->assertEqual( $pair->asMime(), "Content-Disposition: form-data; name=\"a\"\r\n\r\nA"); } function testAttachmentEncodedAsHeadersWithDispositionAndContent() { $part = new SimpleAttachment('a', 'A', 'aaa.txt'); $this->assertEqual( $part->asMime(), "Content-Disposition: form-data; name=\"a\"; filename=\"aaa.txt\"\r\n" . "Content-Type: text/plain\r\n\r\nA"); } } class TestOfEncoding extends UnitTestCase { var $_content_so_far; function write($content) { $this->_content_so_far .= $content; } function clear() { $this->_content_so_far = ''; } function assertWritten($encoding, $content, $message = '%s') { $this->clear(); $encoding->writeTo($this); $this->assertIdentical($this->_content_so_far, $content, $message); } function testGetEmpty() { $encoding = &new SimpleGetEncoding(); $this->assertIdentical($encoding->getValue('a'), false); $this->assertIdentical($encoding->asUrlRequest(), ''); } function testPostEmpty() { $encoding = &new SimplePostEncoding(); $this->assertIdentical($encoding->getValue('a'), false); $this->assertWritten($encoding, ''); } function testPrefilled() { $encoding = &new SimplePostEncoding(array('a' => 'aaa')); $this->assertIdentical($encoding->getValue('a'), 'aaa'); $this->assertWritten($encoding, 'a=aaa'); } function testPrefilledWithObject() { $encoding = &new SimplePostEncoding(new SimpleEncoding(array('a' => 'aaa'))); $this->assertIdentical($encoding->getValue('a'), 'aaa'); $this->assertWritten($encoding, 'a=aaa'); } function testMultiplePrefilled() { $encoding = &new SimplePostEncoding(array('a' => array('a1', 'a2'))); $this->assertIdentical($encoding->getValue('a'), array('a1', 'a2')); $this->assertWritten($encoding, 'a=a1&a=a2'); } function testSingleParameter() { $encoding = &new SimplePostEncoding(); $encoding->add('a', 'Hello'); $this->assertEqual($encoding->getValue('a'), 'Hello'); $this->assertWritten($encoding, 'a=Hello'); } function testFalseParameter() { $encoding = &new SimplePostEncoding(); $encoding->add('a', false); $this->assertEqual($encoding->getValue('a'), false); $this->assertWritten($encoding, ''); } function testUrlEncoding() { $encoding = &new SimplePostEncoding(); $encoding->add('a', 'Hello there!'); $this->assertWritten($encoding, 'a=Hello+there%21'); } function testUrlEncodingOfKey() { $encoding = &new SimplePostEncoding(); $encoding->add('a!', 'Hello'); $this->assertWritten($encoding, 'a%21=Hello'); } function testMultipleParameter() { $encoding = &new SimplePostEncoding(); $encoding->add('a', 'Hello'); $encoding->add('b', 'Goodbye'); $this->assertWritten($encoding, 'a=Hello&b=Goodbye'); } function testEmptyParameters() { $encoding = &new SimplePostEncoding(); $encoding->add('a', ''); $encoding->add('b', ''); $this->assertWritten($encoding, 'a=&b='); } function testRepeatedParameter() { $encoding = &new SimplePostEncoding(); $encoding->add('a', 'Hello'); $encoding->add('a', 'Goodbye'); $this->assertIdentical($encoding->getValue('a'), array('Hello', 'Goodbye')); $this->assertWritten($encoding, 'a=Hello&a=Goodbye'); } function testAddingLists() { $encoding = &new SimplePostEncoding(); $encoding->add('a', array('Hello', 'Goodbye')); $this->assertIdentical($encoding->getValue('a'), array('Hello', 'Goodbye')); $this->assertWritten($encoding, 'a=Hello&a=Goodbye'); } function testMergeInHash() { $encoding = &new SimpleGetEncoding(array('a' => 'A1', 'b' => 'B')); $encoding->merge(array('a' => 'A2')); $this->assertIdentical($encoding->getValue('a'), array('A1', 'A2')); $this->assertIdentical($encoding->getValue('b'), 'B'); } function testMergeInObject() { $encoding = &new SimpleGetEncoding(array('a' => 'A1', 'b' => 'B')); $encoding->merge(new SimpleEncoding(array('a' => 'A2'))); $this->assertIdentical($encoding->getValue('a'), array('A1', 'A2')); $this->assertIdentical($encoding->getValue('b'), 'B'); } function testPrefilledMultipart() { $encoding = &new SimpleMultipartEncoding(array('a' => 'aaa'), 'boundary'); $this->assertIdentical($encoding->getValue('a'), 'aaa'); $this->assertwritten($encoding, "--boundary\r\n" . "Content-Disposition: form-data; name=\"a\"\r\n" . "\r\n" . "aaa\r\n" . "--boundary--\r\n"); } function testAttachment() { $encoding = &new SimpleMultipartEncoding(array(), 'boundary'); $encoding->attach('a', 'aaa', 'aaa.txt'); $this->assertIdentical($encoding->getValue('a'), 'aaa.txt'); $this->assertwritten($encoding, "--boundary\r\n" . "Content-Disposition: form-data; name=\"a\"; filename=\"aaa.txt\"\r\n" . "Content-Type: text/plain\r\n" . "\r\n" . "aaa\r\n" . "--boundary--\r\n"); } } class TestOfFormHeaders extends UnitTestCase { function testEmptyEncodingWritesZeroContentLength() { $socket = &new MockSimpleSocket(); $socket->expectArgumentsAt(0, 'write', array("Content-Length: 0\r\n")); $socket->expectArgumentsAt(1, 'write', array("Content-Type: application/x-www-form-urlencoded\r\n")); $encoding = &new SimplePostEncoding(); $encoding->writeHeadersTo($socket); } function testEmptyMultipartEncodingWritesEndBoundaryContentLength() { $socket = &new MockSimpleSocket(); $socket->expectArgumentsAt(0, 'write', array("Content-Length: 14\r\n")); $socket->expectArgumentsAt(1, 'write', array("Content-Type: multipart/form-data, boundary=boundary\r\n")); $encoding = &new SimpleMultipartEncoding(array(), 'boundary'); $encoding->writeHeadersTo($socket); } } ?>postfixadmin-2.3.7/tests/simpletest/test/tag_test.php0000664000175000017620000005601611157271050023123 0ustar davidpalepurple '1', 'b' => '')); $this->assertEqual($tag->getTagName(), 'title'); $this->assertIdentical($tag->getAttribute('a'), '1'); $this->assertIdentical($tag->getAttribute('b'), ''); $this->assertIdentical($tag->getAttribute('c'), false); $this->assertIdentical($tag->getContent(), ''); } function testTitleContent() { $tag = &new SimpleTitleTag(array()); $this->assertTrue($tag->expectEndTag()); $tag->addContent('Hello'); $tag->addContent('World'); $this->assertEqual($tag->getText(), 'HelloWorld'); } function testMessyTitleContent() { $tag = &new SimpleTitleTag(array()); $this->assertTrue($tag->expectEndTag()); $tag->addContent('Hello'); $tag->addContent('World'); $this->assertEqual($tag->getText(), 'HelloWorld'); } function testTagWithNoEnd() { $tag = &new SimpleTextTag(array()); $this->assertFalse($tag->expectEndTag()); } function testAnchorHref() { $tag = &new SimpleAnchorTag(array('href' => 'http://here/')); $this->assertEqual($tag->getHref(), 'http://here/'); $tag = &new SimpleAnchorTag(array('href' => '')); $this->assertIdentical($tag->getAttribute('href'), ''); $this->assertIdentical($tag->getHref(), ''); $tag = &new SimpleAnchorTag(array()); $this->assertIdentical($tag->getAttribute('href'), false); $this->assertIdentical($tag->getHref(), ''); } function testIsIdMatchesIdAttribute() { $tag = &new SimpleAnchorTag(array('href' => 'http://here/', 'id' => 7)); $this->assertIdentical($tag->getAttribute('id'), '7'); $this->assertTrue($tag->isId(7)); } } class TestOfWidget extends UnitTestCase { function testTextEmptyDefault() { $tag = &new SimpleTextTag(array('type' => 'text')); $this->assertIdentical($tag->getDefault(), ''); $this->assertIdentical($tag->getValue(), ''); } function testSettingOfExternalLabel() { $tag = &new SimpleTextTag(array('type' => 'text')); $tag->setLabel('it'); $this->assertTrue($tag->isLabel('it')); } function testTextDefault() { $tag = &new SimpleTextTag(array('value' => 'aaa')); $this->assertEqual($tag->getDefault(), 'aaa'); $this->assertEqual($tag->getValue(), 'aaa'); } function testSettingTextValue() { $tag = &new SimpleTextTag(array('value' => 'aaa')); $tag->setValue('bbb'); $this->assertEqual($tag->getValue(), 'bbb'); $tag->resetValue(); $this->assertEqual($tag->getValue(), 'aaa'); } function testFailToSetHiddenValue() { $tag = &new SimpleTextTag(array('value' => 'aaa', 'type' => 'hidden')); $this->assertFalse($tag->setValue('bbb')); $this->assertEqual($tag->getValue(), 'aaa'); } function testSubmitDefaults() { $tag = &new SimpleSubmitTag(array('type' => 'submit')); $this->assertIdentical($tag->getName(), false); $this->assertEqual($tag->getValue(), 'Submit'); $this->assertFalse($tag->setValue('Cannot set this')); $this->assertEqual($tag->getValue(), 'Submit'); $this->assertEqual($tag->getLabel(), 'Submit'); $encoding = &new MockSimpleMultipartEncoding(); $encoding->expectNever('add'); $tag->write($encoding); } function testPopulatedSubmit() { $tag = &new SimpleSubmitTag( array('type' => 'submit', 'name' => 's', 'value' => 'Ok!')); $this->assertEqual($tag->getName(), 's'); $this->assertEqual($tag->getValue(), 'Ok!'); $this->assertEqual($tag->getLabel(), 'Ok!'); $encoding = &new MockSimpleMultipartEncoding(); $encoding->expectOnce('add', array('s', 'Ok!')); $tag->write($encoding); } function testImageSubmit() { $tag = &new SimpleImageSubmitTag( array('type' => 'image', 'name' => 's', 'alt' => 'Label')); $this->assertEqual($tag->getName(), 's'); $this->assertEqual($tag->getLabel(), 'Label'); $encoding = &new MockSimpleMultipartEncoding(); $encoding->expectAt(0, 'add', array('s.x', 20)); $encoding->expectAt(1, 'add', array('s.y', 30)); $tag->write($encoding, 20, 30); } function testImageSubmitTitlePreferredOverAltForLabel() { $tag = &new SimpleImageSubmitTag( array('type' => 'image', 'name' => 's', 'alt' => 'Label', 'title' => 'Title')); $this->assertEqual($tag->getLabel(), 'Title'); } function testButton() { $tag = &new SimpleButtonTag( array('type' => 'submit', 'name' => 's', 'value' => 'do')); $tag->addContent('I am a button'); $this->assertEqual($tag->getName(), 's'); $this->assertEqual($tag->getValue(), 'do'); $this->assertEqual($tag->getLabel(), 'I am a button'); $encoding = &new MockSimpleMultipartEncoding(); $encoding->expectOnce('add', array('s', 'do')); $tag->write($encoding); } } class TestOfTextArea extends UnitTestCase { function testDefault() { $tag = &new SimpleTextAreaTag(array('name' => 'a')); $tag->addContent('Some text'); $this->assertEqual($tag->getName(), 'a'); $this->assertEqual($tag->getDefault(), 'Some text'); } function testWrapping() { $tag = &new SimpleTextAreaTag(array('cols' => '10', 'wrap' => 'physical')); $tag->addContent("Lot's of text that should be wrapped"); $this->assertEqual( $tag->getDefault(), "Lot's of\r\ntext that\r\nshould be\r\nwrapped"); $tag->setValue("New long text\r\nwith two lines"); $this->assertEqual( $tag->getValue(), "New long\r\ntext\r\nwith two\r\nlines"); } function testWrappingRemovesLeadingcariageReturn() { $tag = &new SimpleTextAreaTag(array('cols' => '20', 'wrap' => 'physical')); $tag->addContent("\rStuff"); $this->assertEqual($tag->getDefault(), 'Stuff'); $tag->setValue("\nNew stuff\n"); $this->assertEqual($tag->getValue(), "New stuff\r\n"); } function testBreaksAreNewlineAndCarriageReturn() { $tag = &new SimpleTextAreaTag(array('cols' => '10')); $tag->addContent("Some\nText\rwith\r\nbreaks"); $this->assertEqual($tag->getValue(), "Some\r\nText\r\nwith\r\nbreaks"); } } class TestOfCheckbox extends UnitTestCase { function testCanSetCheckboxToNamedValueWithBooleanTrue() { $tag = &new SimpleCheckboxTag(array('name' => 'a', 'value' => 'A')); $this->assertEqual($tag->getValue(), false); $tag->setValue(true); $this->assertIdentical($tag->getValue(), 'A'); } } class TestOfSelection extends UnitTestCase { function testEmpty() { $tag = &new SimpleSelectionTag(array('name' => 'a')); $this->assertIdentical($tag->getValue(), ''); } function testSingle() { $tag = &new SimpleSelectionTag(array('name' => 'a')); $option = &new SimpleOptionTag(array()); $option->addContent('AAA'); $tag->addTag($option); $this->assertEqual($tag->getValue(), 'AAA'); } function testSingleDefault() { $tag = &new SimpleSelectionTag(array('name' => 'a')); $option = &new SimpleOptionTag(array('selected' => '')); $option->addContent('AAA'); $tag->addTag($option); $this->assertEqual($tag->getValue(), 'AAA'); } function testSingleMappedDefault() { $tag = &new SimpleSelectionTag(array('name' => 'a')); $option = &new SimpleOptionTag(array('selected' => '', 'value' => 'aaa')); $option->addContent('AAA'); $tag->addTag($option); $this->assertEqual($tag->getValue(), 'aaa'); } function testStartsWithDefault() { $tag = &new SimpleSelectionTag(array('name' => 'a')); $a = &new SimpleOptionTag(array()); $a->addContent('AAA'); $tag->addTag($a); $b = &new SimpleOptionTag(array('selected' => '')); $b->addContent('BBB'); $tag->addTag($b); $c = &new SimpleOptionTag(array()); $c->addContent('CCC'); $tag->addTag($c); $this->assertEqual($tag->getValue(), 'BBB'); } function testSettingOption() { $tag = &new SimpleSelectionTag(array('name' => 'a')); $a = &new SimpleOptionTag(array()); $a->addContent('AAA'); $tag->addTag($a); $b = &new SimpleOptionTag(array('selected' => '')); $b->addContent('BBB'); $tag->addTag($b); $c = &new SimpleOptionTag(array()); $c->addContent('CCC'); $tag->setValue('AAA'); $this->assertEqual($tag->getValue(), 'AAA'); } function testSettingMappedOption() { $tag = &new SimpleSelectionTag(array('name' => 'a')); $a = &new SimpleOptionTag(array('value' => 'aaa')); $a->addContent('AAA'); $tag->addTag($a); $b = &new SimpleOptionTag(array('value' => 'bbb', 'selected' => '')); $b->addContent('BBB'); $tag->addTag($b); $c = &new SimpleOptionTag(array('value' => 'ccc')); $c->addContent('CCC'); $tag->addTag($c); $tag->setValue('AAA'); $this->assertEqual($tag->getValue(), 'aaa'); $tag->setValue('ccc'); $this->assertEqual($tag->getValue(), 'ccc'); } function testSelectionDespiteSpuriousWhitespace() { $tag = &new SimpleSelectionTag(array('name' => 'a')); $a = &new SimpleOptionTag(array()); $a->addContent(' AAA '); $tag->addTag($a); $b = &new SimpleOptionTag(array('selected' => '')); $b->addContent(' BBB '); $tag->addTag($b); $c = &new SimpleOptionTag(array()); $c->addContent(' CCC '); $tag->addTag($c); $this->assertEqual($tag->getValue(), ' BBB '); $tag->setValue('AAA'); $this->assertEqual($tag->getValue(), ' AAA '); } function testFailToSetIllegalOption() { $tag = &new SimpleSelectionTag(array('name' => 'a')); $a = &new SimpleOptionTag(array()); $a->addContent('AAA'); $tag->addTag($a); $b = &new SimpleOptionTag(array('selected' => '')); $b->addContent('BBB'); $tag->addTag($b); $c = &new SimpleOptionTag(array()); $c->addContent('CCC'); $tag->addTag($c); $this->assertFalse($tag->setValue('Not present')); $this->assertEqual($tag->getValue(), 'BBB'); } function testNastyOptionValuesThatLookLikeFalse() { $tag = &new SimpleSelectionTag(array('name' => 'a')); $a = &new SimpleOptionTag(array('value' => '1')); $a->addContent('One'); $tag->addTag($a); $b = &new SimpleOptionTag(array('value' => '0')); $b->addContent('Zero'); $tag->addTag($b); $this->assertIdentical($tag->getValue(), '1'); $tag->setValue('Zero'); $this->assertIdentical($tag->getValue(), '0'); } function testBlankOption() { $tag = &new SimpleSelectionTag(array('name' => 'A')); $a = &new SimpleOptionTag(array()); $tag->addTag($a); $b = &new SimpleOptionTag(array()); $b->addContent('b'); $tag->addTag($b); $this->assertIdentical($tag->getValue(), ''); $tag->setValue('b'); $this->assertIdentical($tag->getValue(), 'b'); $tag->setValue(''); $this->assertIdentical($tag->getValue(), ''); } function testMultipleDefaultWithNoSelections() { $tag = &new MultipleSelectionTag(array('name' => 'a', 'multiple' => '')); $a = &new SimpleOptionTag(array()); $a->addContent('AAA'); $tag->addTag($a); $b = &new SimpleOptionTag(array()); $b->addContent('BBB'); $tag->addTag($b); $this->assertIdentical($tag->getDefault(), array()); $this->assertIdentical($tag->getValue(), array()); } function testMultipleDefaultWithSelections() { $tag = &new MultipleSelectionTag(array('name' => 'a', 'multiple' => '')); $a = &new SimpleOptionTag(array('selected' => '')); $a->addContent('AAA'); $tag->addTag($a); $b = &new SimpleOptionTag(array('selected' => '')); $b->addContent('BBB'); $tag->addTag($b); $this->assertIdentical($tag->getDefault(), array('AAA', 'BBB')); $this->assertIdentical($tag->getValue(), array('AAA', 'BBB')); } function testSettingMultiple() { $tag = &new MultipleSelectionTag(array('name' => 'a', 'multiple' => '')); $a = &new SimpleOptionTag(array('selected' => '')); $a->addContent('AAA'); $tag->addTag($a); $b = &new SimpleOptionTag(array()); $b->addContent('BBB'); $tag->addTag($b); $c = &new SimpleOptionTag(array('selected' => '', 'value' => 'ccc')); $c->addContent('CCC'); $tag->addTag($c); $this->assertIdentical($tag->getDefault(), array('AAA', 'ccc')); $this->assertTrue($tag->setValue(array('BBB', 'ccc'))); $this->assertIdentical($tag->getValue(), array('BBB', 'ccc')); $this->assertTrue($tag->setValue(array())); $this->assertIdentical($tag->getValue(), array()); } function testFailToSetIllegalOptionsInMultiple() { $tag = &new MultipleSelectionTag(array('name' => 'a', 'multiple' => '')); $a = &new SimpleOptionTag(array('selected' => '')); $a->addContent('AAA'); $tag->addTag($a); $b = &new SimpleOptionTag(array()); $b->addContent('BBB'); $tag->addTag($b); $this->assertFalse($tag->setValue(array('CCC'))); $this->assertTrue($tag->setValue(array('AAA', 'BBB'))); $this->assertFalse($tag->setValue(array('AAA', 'CCC'))); } } class TestOfRadioGroup extends UnitTestCase { function testEmptyGroup() { $group = &new SimpleRadioGroup(); $this->assertIdentical($group->getDefault(), false); $this->assertIdentical($group->getValue(), false); $this->assertFalse($group->setValue('a')); } function testReadingSingleButtonGroup() { $group = &new SimpleRadioGroup(); $group->addWidget(new SimpleRadioButtonTag( array('value' => 'A', 'checked' => ''))); $this->assertIdentical($group->getDefault(), 'A'); $this->assertIdentical($group->getValue(), 'A'); } function testReadingMultipleButtonGroup() { $group = &new SimpleRadioGroup(); $group->addWidget(new SimpleRadioButtonTag( array('value' => 'A'))); $group->addWidget(new SimpleRadioButtonTag( array('value' => 'B', 'checked' => ''))); $this->assertIdentical($group->getDefault(), 'B'); $this->assertIdentical($group->getValue(), 'B'); } function testFailToSetUnlistedValue() { $group = &new SimpleRadioGroup(); $group->addWidget(new SimpleRadioButtonTag(array('value' => 'z'))); $this->assertFalse($group->setValue('a')); $this->assertIdentical($group->getValue(), false); } function testSettingNewValueClearsTheOldOne() { $group = &new SimpleRadioGroup(); $group->addWidget(new SimpleRadioButtonTag( array('value' => 'A'))); $group->addWidget(new SimpleRadioButtonTag( array('value' => 'B', 'checked' => ''))); $this->assertTrue($group->setValue('A')); $this->assertIdentical($group->getValue(), 'A'); } function testIsIdMatchesAnyWidgetInSet() { $group = &new SimpleRadioGroup(); $group->addWidget(new SimpleRadioButtonTag( array('value' => 'A', 'id' => 'i1'))); $group->addWidget(new SimpleRadioButtonTag( array('value' => 'B', 'id' => 'i2'))); $this->assertFalse($group->isId('i0')); $this->assertTrue($group->isId('i1')); $this->assertTrue($group->isId('i2')); } function testIsLabelMatchesAnyWidgetInSet() { $group = &new SimpleRadioGroup(); $button1 = &new SimpleRadioButtonTag(array('value' => 'A')); $button1->setLabel('one'); $group->addWidget($button1); $button2 = &new SimpleRadioButtonTag(array('value' => 'B')); $button2->setLabel('two'); $group->addWidget($button2); $this->assertFalse($group->isLabel('three')); $this->assertTrue($group->isLabel('one')); $this->assertTrue($group->isLabel('two')); } } class TestOfTagGroup extends UnitTestCase { function testReadingMultipleCheckboxGroup() { $group = &new SimpleCheckboxGroup(); $group->addWidget(new SimpleCheckboxTag(array('value' => 'A'))); $group->addWidget(new SimpleCheckboxTag( array('value' => 'B', 'checked' => ''))); $this->assertIdentical($group->getDefault(), 'B'); $this->assertIdentical($group->getValue(), 'B'); } function testReadingMultipleUncheckedItems() { $group = &new SimpleCheckboxGroup(); $group->addWidget(new SimpleCheckboxTag(array('value' => 'A'))); $group->addWidget(new SimpleCheckboxTag(array('value' => 'B'))); $this->assertIdentical($group->getDefault(), false); $this->assertIdentical($group->getValue(), false); } function testReadingMultipleCheckedItems() { $group = &new SimpleCheckboxGroup(); $group->addWidget(new SimpleCheckboxTag( array('value' => 'A', 'checked' => ''))); $group->addWidget(new SimpleCheckboxTag( array('value' => 'B', 'checked' => ''))); $this->assertIdentical($group->getDefault(), array('A', 'B')); $this->assertIdentical($group->getValue(), array('A', 'B')); } function testSettingSingleValue() { $group = &new SimpleCheckboxGroup(); $group->addWidget(new SimpleCheckboxTag(array('value' => 'A'))); $group->addWidget(new SimpleCheckboxTag(array('value' => 'B'))); $this->assertTrue($group->setValue('A')); $this->assertIdentical($group->getValue(), 'A'); $this->assertTrue($group->setValue('B')); $this->assertIdentical($group->getValue(), 'B'); } function testSettingMultipleValues() { $group = &new SimpleCheckboxGroup(); $group->addWidget(new SimpleCheckboxTag(array('value' => 'A'))); $group->addWidget(new SimpleCheckboxTag(array('value' => 'B'))); $this->assertTrue($group->setValue(array('A', 'B'))); $this->assertIdentical($group->getValue(), array('A', 'B')); } function testSettingNoValue() { $group = &new SimpleCheckboxGroup(); $group->addWidget(new SimpleCheckboxTag(array('value' => 'A'))); $group->addWidget(new SimpleCheckboxTag(array('value' => 'B'))); $this->assertTrue($group->setValue(false)); $this->assertIdentical($group->getValue(), false); } function testIsIdMatchesAnyIdInSet() { $group = &new SimpleCheckboxGroup(); $group->addWidget(new SimpleCheckboxTag(array('id' => 1, 'value' => 'A'))); $group->addWidget(new SimpleCheckboxTag(array('id' => 2, 'value' => 'B'))); $this->assertFalse($group->isId(0)); $this->assertTrue($group->isId(1)); $this->assertTrue($group->isId(2)); } } class TestOfUploadWidget extends UnitTestCase { function testValueIsFilePath() { $upload = &new SimpleUploadTag(array('name' => 'a')); $upload->setValue(dirname(__FILE__) . '/support/upload_sample.txt'); $this->assertEqual($upload->getValue(), dirname(__FILE__) . '/support/upload_sample.txt'); } function testSubmitsFileContents() { $encoding = &new MockSimpleMultipartEncoding(); $encoding->expectOnce('attach', array( 'a', 'Sample for testing file upload', 'upload_sample.txt')); $upload = &new SimpleUploadTag(array('name' => 'a')); $upload->setValue(dirname(__FILE__) . '/support/upload_sample.txt'); $upload->write($encoding); } } class TestOfLabelTag extends UnitTestCase { function testLabelShouldHaveAnEndTag() { $label = &new SimpleLabelTag(array()); $this->assertTrue($label->expectEndTag()); } function testContentIsTextOnly() { $label = &new SimpleLabelTag(array()); $label->addContent('Here are words'); $this->assertEqual($label->getText(), 'Here are words'); } } ?>postfixadmin-2.3.7/tests/simpletest/test/mock_objects_test.php0000664000175000017620000006307011157271050025010 0ustar davidpalepurpleassertTrue($expectation->test(33)); $this->assertTrue($expectation->test(false)); $this->assertTrue($expectation->test(null)); } } class TestOfParametersExpectation extends UnitTestCase { function testEmptyMatch() { $expectation = new ParametersExpectation(array()); $this->assertTrue($expectation->test(array())); $this->assertFalse($expectation->test(array(33))); } function testSingleMatch() { $expectation = new ParametersExpectation(array(0)); $this->assertFalse($expectation->test(array(1))); $this->assertTrue($expectation->test(array(0))); } function testAnyMatch() { $expectation = new ParametersExpectation(false); $this->assertTrue($expectation->test(array())); $this->assertTrue($expectation->test(array(1, 2))); } function testMissingParameter() { $expectation = new ParametersExpectation(array(0)); $this->assertFalse($expectation->test(array())); } function testNullParameter() { $expectation = new ParametersExpectation(array(null)); $this->assertTrue($expectation->test(array(null))); $this->assertFalse($expectation->test(array())); } function testAnythingExpectations() { $expectation = new ParametersExpectation(array(new AnythingExpectation())); $this->assertFalse($expectation->test(array())); $this->assertIdentical($expectation->test(array(null)), true); $this->assertIdentical($expectation->test(array(13)), true); } function testOtherExpectations() { $expectation = new ParametersExpectation( array(new PatternExpectation('/hello/i'))); $this->assertFalse($expectation->test(array('Goodbye'))); $this->assertTrue($expectation->test(array('hello'))); $this->assertTrue($expectation->test(array('Hello'))); } function testIdentityOnly() { $expectation = new ParametersExpectation(array("0")); $this->assertFalse($expectation->test(array(0))); $this->assertTrue($expectation->test(array("0"))); } function testLongList() { $expectation = new ParametersExpectation( array("0", 0, new AnythingExpectation(), false)); $this->assertTrue($expectation->test(array("0", 0, 37, false))); $this->assertFalse($expectation->test(array("0", 0, 37, true))); $this->assertFalse($expectation->test(array("0", 0, 37))); } } class TestOfCallMap extends UnitTestCase { function testEmpty() { $map = new CallMap(); $this->assertFalse($map->isMatch("any", array())); $this->assertNull($map->findFirstMatch("any", array())); } function testExactValue() { $map = new CallMap(); $map->addValue(array(0), "Fred"); $map->addValue(array(1), "Jim"); $map->addValue(array("1"), "Tom"); $this->assertTrue($map->isMatch(array(0))); $this->assertEqual($map->findFirstMatch(array(0)), "Fred"); $this->assertTrue($map->isMatch(array(1))); $this->assertEqual($map->findFirstMatch(array(1)), "Jim"); $this->assertEqual($map->findFirstMatch(array("1")), "Tom"); } function testExactReference() { $map = new CallMap(); $ref = "Fred"; $map->addReference(array(0), $ref); $this->assertEqual($map->findFirstMatch(array(0)), "Fred"); $ref2 = &$map->findFirstMatch(array(0)); $this->assertReference($ref2, $ref); } function testWildcard() { $map = new CallMap(); $map->addValue(array(new AnythingExpectation(), 1, 3), "Fred"); $this->assertTrue($map->isMatch(array(2, 1, 3))); $this->assertEqual($map->findFirstMatch(array(2, 1, 3)), "Fred"); } function testAllWildcard() { $map = new CallMap(); $this->assertFalse($map->isMatch(array(2, 1, 3))); $map->addValue("", "Fred"); $this->assertTrue($map->isMatch(array(2, 1, 3))); $this->assertEqual($map->findFirstMatch(array(2, 1, 3)), "Fred"); } function testOrdering() { $map = new CallMap(); $map->addValue(array(1, 2), "1, 2"); $map->addValue(array(1, 3), "1, 3"); $map->addValue(array(1), "1"); $map->addValue(array(1, 4), "1, 4"); $map->addValue(array(new AnythingExpectation()), "Any"); $map->addValue(array(2), "2"); $map->addValue("", "Default"); $map->addValue(array(), "None"); $this->assertEqual($map->findFirstMatch(array(1, 2)), "1, 2"); $this->assertEqual($map->findFirstMatch(array(1, 3)), "1, 3"); $this->assertEqual($map->findFirstMatch(array(1, 4)), "1, 4"); $this->assertEqual($map->findFirstMatch(array(1)), "1"); $this->assertEqual($map->findFirstMatch(array(2)), "Any"); $this->assertEqual($map->findFirstMatch(array(3)), "Any"); $this->assertEqual($map->findFirstMatch(array()), "Default"); } } class Dummy { function Dummy() { } function aMethod() { return true; } function anotherMethod() { return true; } } Stub::generateSubclass('Dummy', 'StubDummy'); Stub::generateSubclass('Dummy', 'AnotherStubDummy'); Stub::generateSubclass('Dummy', 'StubDummyWithExtraMethods', array('extraMethod')); class SpecialSimpleStub extends SimpleMock { function SpecialSimpleStub() { $this->SimpleMock(); } } SimpleTest::setMockBaseClass('SpecialSimpleStub'); Stub::generateSubclass('Dummy', 'SpecialStubDummy'); SimpleTest::setMockBaseClass('SimpleMock'); class TestOfStubGeneration extends UnitTestCase { function testCloning() { $stub = &new StubDummy(); $this->assertTrue(method_exists($stub, "aMethod")); $this->assertNull($stub->aMethod(null)); } function testCloningWithExtraMethod() { $stub = &new StubDummyWithExtraMethods(); $this->assertTrue(method_exists($stub, "extraMethod")); } function testCloningWithChosenClassName() { $stub = &new AnotherStubDummy(); $this->assertTrue(method_exists($stub, "aMethod")); } function testCloningWithDifferentBaseClass() { $stub = &new SpecialStubDummy(); $this->assertTrue(method_exists($stub, "aMethod")); } } class TestOfServerStubReturns extends UnitTestCase { function testDefaultReturn() { $stub = &new StubDummy(); $stub->setReturnValue("aMethod", "aaa"); $this->assertIdentical($stub->aMethod(), "aaa"); $this->assertIdentical($stub->aMethod(), "aaa"); } function testParameteredReturn() { $stub = &new StubDummy(); $stub->setReturnValue("aMethod", "aaa", array(1, 2, 3)); $this->assertNull($stub->aMethod()); $this->assertIdentical($stub->aMethod(1, 2, 3), "aaa"); } function testReferenceReturned() { $stub = &new StubDummy(); $object = new Dummy(); $stub->setReturnReference("aMethod", $object, array(1, 2, 3)); $this->assertReference($zref =& $stub->aMethod(1, 2, 3), $object); } function testMultipleMethods() { $stub = &new StubDummy(); $stub->setReturnValue("aMethod", 100, array(1)); $stub->setReturnValue("aMethod", 200, array(2)); $stub->setReturnValue("anotherMethod", 10, array(1)); $stub->setReturnValue("anotherMethod", 20, array(2)); $this->assertIdentical($stub->aMethod(1), 100); $this->assertIdentical($stub->anotherMethod(1), 10); $this->assertIdentical($stub->aMethod(2), 200); $this->assertIdentical($stub->anotherMethod(2), 20); } function testReturnSequence() { $stub = &new StubDummy(); $stub->setReturnValueAt(0, "aMethod", "aaa"); $stub->setReturnValueAt(1, "aMethod", "bbb"); $stub->setReturnValueAt(3, "aMethod", "ddd"); $this->assertIdentical($stub->aMethod(), "aaa"); $this->assertIdentical($stub->aMethod(), "bbb"); $this->assertNull($stub->aMethod()); $this->assertIdentical($stub->aMethod(), "ddd"); } function testReturnReferenceSequence() { $stub = &new StubDummy(); $object = new Dummy(); $stub->setReturnReferenceAt(1, "aMethod", $object); $this->assertNull($stub->aMethod()); $this->assertReference($zref =& $stub->aMethod(), $object); $this->assertNull($stub->aMethod()); } function testComplicatedReturnSequence() { $stub = &new StubDummy(); $object = new Dummy(); $stub->setReturnValueAt(1, "aMethod", "aaa", array("a")); $stub->setReturnValueAt(1, "aMethod", "bbb"); $stub->setReturnReferenceAt(2, "aMethod", $object, array('*', 2)); $stub->setReturnValueAt(2, "aMethod", "value", array('*', 3)); $stub->setReturnValue("aMethod", 3, array(3)); $this->assertNull($stub->aMethod()); $this->assertEqual($stub->aMethod("a"), "aaa"); $this->assertReference($zref =& $stub->aMethod(1, 2), $object); $this->assertEqual($stub->aMethod(3), 3); $this->assertNull($stub->aMethod()); } function testMultipleMethodSequences() { $stub = &new StubDummy(); $stub->setReturnValueAt(0, "aMethod", "aaa"); $stub->setReturnValueAt(1, "aMethod", "bbb"); $stub->setReturnValueAt(0, "anotherMethod", "ccc"); $stub->setReturnValueAt(1, "anotherMethod", "ddd"); $this->assertIdentical($stub->aMethod(), "aaa"); $this->assertIdentical($stub->anotherMethod(), "ccc"); $this->assertIdentical($stub->aMethod(), "bbb"); $this->assertIdentical($stub->anotherMethod(), "ddd"); } function testSequenceFallback() { $stub = &new StubDummy(); $stub->setReturnValueAt(0, "aMethod", "aaa", array('a')); $stub->setReturnValueAt(1, "aMethod", "bbb", array('a')); $stub->setReturnValue("aMethod", "AAA"); $this->assertIdentical($stub->aMethod('a'), "aaa"); $this->assertIdentical($stub->aMethod('b'), "AAA"); } function testMethodInterference() { $stub = &new StubDummy(); $stub->setReturnValueAt(0, "anotherMethod", "aaa"); $stub->setReturnValue("aMethod", "AAA"); $this->assertIdentical($stub->aMethod(), "AAA"); $this->assertIdentical($stub->anotherMethod(), "aaa"); } } Mock::generateSubclass('Dummy'); Mock::generateSubclass('Dummy', 'AnotherMockDummy'); Mock::generateSubclass('Dummy', 'MockDummyWithExtraMethods', array('extraMethod')); class SpecialSimpleMock extends SimpleMock { } SimpleTest::setMockBaseClass("SpecialSimpleMock"); Mock::generateSubclass("Dummy", "SpecialMockDummy"); SimpleTest::setMockBaseClass("SimpleMock"); class TestOfMockGeneration extends UnitTestCase { function testCloning() { $mock = &new MockDummy(); $this->assertTrue(method_exists($mock, "aMethod")); $this->assertNull($mock->aMethod()); } function testCloningWithExtraMethod() { $mock = &new MockDummyWithExtraMethods(); $this->assertTrue(method_exists($mock, "extraMethod")); } function testCloningWithChosenClassName() { $mock = &new AnotherMockDummy(); $this->assertTrue(method_exists($mock, "aMethod")); } function testCloningWithDifferentBaseClass() { $mock = &new SpecialMockDummy(); $this->assertTrue(method_exists($mock, "aMethod")); } } class TestOfMockReturns extends UnitTestCase { function testParameteredReturn() { $mock = &new MockDummy(); $mock->setReturnValue('aMethod', 'aaa', array(1, 2, 3)); $this->assertNull($mock->aMethod()); $this->assertIdentical($mock->aMethod(1, 2, 3), 'aaa'); } function testReferenceReturned() { $mock = &new MockDummy(); $object = new Dummy(); $mock->setReturnReference("aMethod", $object, array(1, 2, 3)); $this->assertReference($zref =& $mock->aMethod(1, 2, 3), $object); } function testPatternMatchReturn() { $mock = &new MockDummy(); $mock->setReturnValue( "aMethod", "aaa", array(new PatternExpectation('/hello/i'))); $this->assertIdentical($mock->aMethod('Hello'), "aaa"); $this->assertNull($mock->aMethod('Goodbye')); } function testReturnReferenceSequence() { $mock = &new MockDummy(); $object = new Dummy(); $mock->setReturnReferenceAt(1, 'aMethod', $object); $this->assertNull($mock->aMethod()); $this->assertReference($zref =& $mock->aMethod(), $object); $this->assertNull($mock->aMethod()); $this->swallowErrors(); } } class ClassWithSpecialMethods { function __get($name) { } function __set($name, $value) { } function __isset($name) { } function __unset($name) { } function __call($method, $arguments) { } function __toString() { } } Mock::generateSubclass('ClassWithSpecialMethods'); class TestOfSpecialMethods extends UnitTestCase { function skip() { $this->skipIf(version_compare(phpversion(), '5', '<='), 'Overloading not tested for PHP 4'); } function testCanMockTheThingAtAll() { $mock = new MockClassWithSpecialMethods(); } function testReturnFromSpecialAccessor() { $mock = &new MockClassWithSpecialMethods(); $mock->setReturnValue('__get', '1st Return', array('first')); $mock->setReturnValue('__get', '2nd Return', array('second')); $this->assertEqual($mock->first, '1st Return'); $this->assertEqual($mock->second, '2nd Return'); } function testcanExpectTheSettingOfValue() { $mock = &new MockClassWithSpecialMethods(); $mock->expectOnce('__set', array('a', 'A')); $mock->a = 'A'; } function testCanSimulateAnOverloadmethod() { $mock = &new MockClassWithSpecialMethods(); $mock->expectOnce('__call', array('amOverloaded', array('A'))); $mock->setReturnValue('__call', 'aaa'); $this->assertIdentical($mock->amOverloaded('A'), 'aaa'); } function testCanEmulateIsset() { $mock = &new MockClassWithSpecialMethods(); $mock->setReturnValue('__isset', true); $this->assertIdentical(isset($mock->a), true); } function testCanExpectUnset() { $mock = &new MockClassWithSpecialMethods(); $mock->expectOnce('__unset', array('a')); unset($mock->a); } function testToStringMagic() { $mock = &new MockClassWithSpecialMethods(); $mock->expectOnce('__toString'); $mock->setReturnValue('__toString', 'AAA'); ob_start(); print $mock; $output = ob_get_contents(); ob_end_clean(); $this->assertEqual($output, 'AAA'); } } class TestOfMockTally extends UnitTestCase { function testZeroCallCount() { $mock = &new MockDummy(); $mock->expectCallCount('aMethod', 0); } function testExpectedCallCount() { $mock = &new MockDummy(); $mock->expectCallCount('aMethod', 2); $mock->aMethod(); $mock->aMethod(); } } class MockWithInjectedTestCase extends SimpleMock { function &_getCurrentTestCase() { $context = &SimpleTest::getContext(); $test = &$context->getTest(); return $test->test; } } SimpleTest::setMockBaseClass('MockWithInjectedTestCase'); Mock::generateSubclass('Dummy', 'MockDummyWithInjectedTestCase'); SimpleTest::setMockBaseClass('SimpleMock'); Mock::generateSubclass('SimpleTestCase'); class TestOfMockExpectations extends UnitTestCase { var $test; function setUp() { $this->test = &new MockSimpleTestCase(); } function testSettingExpectationOnNonMethodThrowsError() { $mock = &new MockDummyWithInjectedTestCase(); $mock->expectMaximumCallCount('aMissingMethod', 2); $this->assertError(); } function testMaxCallsDetectsOverrun() { $this->test->expectOnce('assert', array(new IsAExpectation('MaximumCallCountExpectation'), 3)); $mock = &new MockDummyWithInjectedTestCase(); $mock->expectMaximumCallCount('aMethod', 2); $mock->aMethod(); $mock->aMethod(); $mock->aMethod(); $mock->_mock->atTestEnd('testSomething', $this->test); } function testTallyOnMaxCallsSendsPassOnUnderrun() { $this->test->expectOnce('assert', array(new IsAExpectation('MaximumCallCountExpectation'), 2)); $mock = &new MockDummyWithInjectedTestCase(); $mock->expectMaximumCallCount("aMethod", 2); $mock->aMethod(); $mock->aMethod(); $mock->_mock->atTestEnd('testSomething', $this->test); } function testExpectNeverDetectsOverrun() { $this->test->expectOnce('assert', array(new IsAExpectation('MaximumCallCountExpectation'), 1)); $mock = &new MockDummyWithInjectedTestCase(); $mock->expectNever('aMethod'); $mock->aMethod(); $mock->_mock->atTestEnd('testSomething', $this->test); } function testTallyOnExpectNeverSendsPassOnUnderrun() { $this->test->expectOnce('assert', array(new IsAExpectation('MaximumCallCountExpectation'), 0)); $mock = &new MockDummyWithInjectedTestCase(); $mock->expectNever('aMethod'); $mock->_mock->atTestEnd('testSomething', $this->test); } function testMinCalls() { $this->test->expectOnce('assert', array(new IsAExpectation('MinimumCallCountExpectation'), 2)); $mock = &new MockDummyWithInjectedTestCase(); $mock->expectMinimumCallCount('aMethod', 2); $mock->aMethod(); $mock->aMethod(); $mock->_mock->atTestEnd('testSomething', $this->test); } function testFailedNever() { $this->test->expectOnce('assert', array(new IsAExpectation('MaximumCallCountExpectation'), 1)); $mock = &new MockDummyWithInjectedTestCase(); $mock->expectNever('aMethod'); $mock->aMethod(); $mock->_mock->atTestEnd('testSomething', $this->test); } function testUnderOnce() { $this->test->expectOnce('assert', array(new IsAExpectation('CallCountExpectation'), 0)); $mock = &new MockDummyWithInjectedTestCase(); $mock->expectOnce('aMethod'); $mock->_mock->atTestEnd('testSomething', $this->test); } function testOverOnce() { $this->test->expectOnce('assert', array(new IsAExpectation('CallCountExpectation'), 2)); $mock = &new MockDummyWithInjectedTestCase(); $mock->expectOnce('aMethod'); $mock->aMethod(); $mock->aMethod(); $mock->_mock->atTestEnd('testSomething', $this->test); $this->swallowErrors(); } function testUnderAtLeastOnce() { $this->test->expectOnce('assert', array(new IsAExpectation('MinimumCallCountExpectation'), 0)); $mock = &new MockDummyWithInjectedTestCase(); $mock->expectAtLeastOnce("aMethod"); $mock->_mock->atTestEnd('testSomething', $this->test); } function testZeroArguments() { $mock = &new MockDummyWithInjectedTestCase(); $mock->expectArguments("aMethod", array()); $mock->aMethod(); $mock->_mock->atTestEnd('testSomething', $this->test); } function testExpectedArguments() { $mock = &new MockDummyWithInjectedTestCase(); $mock->expectArguments('aMethod', array(1, 2, 3)); $mock->aMethod(1, 2, 3); $mock->_mock->atTestEnd('testSomething', $this->test); } function testFailedArguments() { $this->test->expectOnce('assert', array(new IsAExpectation('ParametersExpectation'), array('that'), '*')); $mock = &new MockDummyWithInjectedTestCase(); $mock->expectArguments('aMethod', array('this')); $mock->aMethod('that'); $mock->_mock->atTestEnd('testSomething', $this->test); } function testWildcardArguments() { $mock = &new MockDummyWithInjectedTestCase($this, "wild"); $mock->expectArguments("aMethod", array("wild", 123, "wild")); $mock->aMethod(100, 123, 101); $mock->_mock->atTestEnd('testSomething', $this->test); } function testSpecificSequence() { $mock = &new MockDummyWithInjectedTestCase(); $mock->expectArgumentsAt(1, "aMethod", array(1, 2, 3)); $mock->expectArgumentsAt(2, "aMethod", array("Hello")); $mock->aMethod(); $mock->aMethod(1, 2, 3); $mock->aMethod("Hello"); $mock->aMethod(); $mock->_mock->atTestEnd('testSomething', $this->test); } function testBadArgParameter() { $mock = &new MockDummyWithInjectedTestCase(); $mock->expectArguments("aMethod", "foo"); $this->assertErrorPattern('/\$args.*not an array/i'); $mock->aMethod(); $mock->tally(); $mock->_mock->atTestEnd('testSomething', $this->test); } } class TestOfMockComparisons extends UnitTestCase { function testEqualComparisonOfMocksDoesNotCrash() { $expectation = &new EqualExpectation(new MockDummy()); $this->assertTrue($expectation->test(new MockDummy(), true)); } function testIdenticalComparisonOfMocksDoesNotCrash() { $expectation = &new IdenticalExpectation(new MockDummy()); $this->assertTrue($expectation->test(new MockDummy())); } } Mock::generatePartial('Dummy', 'TestDummy', array('anotherMethod')); class TestOfPartialMocks extends UnitTestCase { function testMethodReplacement() { $mock = &new TestDummy(); $this->assertEqual($mock->aMethod(99), 99); $this->assertNull($mock->anotherMethod()); } function testSettingReturns() { $mock = &new TestDummy(); $mock->setReturnValue('anotherMethod', 33, array(3)); $mock->setReturnValue('anotherMethod', 22); $mock->setReturnValueAt(2, 'anotherMethod', 44, array(3)); $this->assertEqual($mock->anotherMethod(), 22); $this->assertEqual($mock->anotherMethod(3), 33); $this->assertEqual($mock->anotherMethod(3), 44); } function testReferences() { $mock = &new TestDummy(); $object = new Dummy(); $mock->setReturnReferenceAt(0, 'anotherMethod', $object, array(3)); $this->assertReference($zref =& $mock->anotherMethod(3), $object); } function testExpectations() { $mock = &new TestDummy(); $mock->expectCallCount('anotherMethod', 2); $mock->expectArguments('anotherMethod', array(77)); $mock->expectArgumentsAt(1, 'anotherMethod', array(66)); $mock->anotherMethod(77); $mock->anotherMethod(66); } function testSettingExpectationOnMissingMethodThrowsError() { $mock = &new TestDummy(); $mock->expectCallCount('aMissingMethod', 2); $this->assertError(); } } class ConstructorSuperClass { function ConstructorSuperClass() { } } class ConstructorSubClass extends ConstructorSuperClass { } class TestOfPHP4StyleSuperClassConstruct extends UnitTestCase { /* * This addresses issue #1231401. Without the fix in place, this will * generate a fatal PHP error. */ function testBasicConstruct() { Mock::generateSubclass('ConstructorSubClass'); $mock = &new MockConstructorSubClass(); $this->assertIsA($mock, 'ConstructorSubClass'); $this->assertTrue(method_exists($mock, 'ConstructorSuperClass')); } } ?>postfixadmin-2.3.7/tests/simpletest/test/unit_tester_test.php0000664000175000017620000000310011157271050024677 0ustar davidpalepurpleassertTrue($this->assertTrue(true)); } function testAssertFalseReturnsAssertionAsBoolean() { $this->assertTrue($this->assertFalse(false)); } function testAssertEqualReturnsAssertionAsBoolean() { $this->assertTrue($this->assertEqual(5, 5)); } function testAssertIdenticalReturnsAssertionAsBoolean() { $this->assertTrue($this->assertIdentical(5, 5)); } function testCoreAssertionsDoNotThrowErrors() { $this->assertIsA($this, 'UnitTestCase'); $this->assertNotA($this, 'WebTestCase'); } function testReferenceAssertionOnObjects() { $a = &new ReferenceForTesting(); $b = &$a; $this->assertReference($a, $b); } function testReferenceAssertionOnScalars() { $a = 25; $b = &$a; $this->assertReference($a, $b); } function testCloneOnObjects() { $a = &new ReferenceForTesting(); $b = &new ReferenceForTesting(); $this->assertClone($a, $b); } function testCloneOnScalars() { $a = 25; $b = 25; $this->assertClone($a, $b); } } ?>postfixadmin-2.3.7/tests/simpletest/test/frames_test.php0000664000175000017620000005466611157271050023636 0ustar davidpalepurplesetReturnValue('getTitle', 'This page'); $frameset = &new SimpleFrameset($page); $this->assertEqual($frameset->getTitle(), 'This page'); } function TestHeadersReadFromFramesetByDefault() { $page = &new MockSimplePage(); $page->setReturnValue('getHeaders', 'Header: content'); $page->setReturnValue('getMimeType', 'text/xml'); $page->setReturnValue('getResponseCode', 401); $page->setReturnValue('getTransportError', 'Could not parse headers'); $page->setReturnValue('getAuthentication', 'Basic'); $page->setReturnValue('getRealm', 'Safe place'); $frameset = &new SimpleFrameset($page); $this->assertIdentical($frameset->getHeaders(), 'Header: content'); $this->assertIdentical($frameset->getMimeType(), 'text/xml'); $this->assertIdentical($frameset->getResponseCode(), 401); $this->assertIdentical($frameset->getTransportError(), 'Could not parse headers'); $this->assertIdentical($frameset->getAuthentication(), 'Basic'); $this->assertIdentical($frameset->getRealm(), 'Safe place'); } function testEmptyFramesetHasNoContent() { $page = &new MockSimplePage(); $page->setReturnValue('getRaw', 'This content'); $frameset = &new SimpleFrameset($page); $this->assertEqual($frameset->getRaw(), ''); } function testRawContentIsFromOnlyFrame() { $page = &new MockSimplePage(); $page->expectNever('getRaw'); $frame = &new MockSimplePage(); $frame->setReturnValue('getRaw', 'Stuff'); $frameset = &new SimpleFrameset($page); $frameset->addFrame($frame); $this->assertEqual($frameset->getRaw(), 'Stuff'); } function testRawContentIsFromAllFrames() { $page = &new MockSimplePage(); $page->expectNever('getRaw'); $frame1 = &new MockSimplePage(); $frame1->setReturnValue('getRaw', 'Stuff1'); $frame2 = &new MockSimplePage(); $frame2->setReturnValue('getRaw', 'Stuff2'); $frameset = &new SimpleFrameset($page); $frameset->addFrame($frame1); $frameset->addFrame($frame2); $this->assertEqual($frameset->getRaw(), 'Stuff1Stuff2'); } function testTextContentIsFromOnlyFrame() { $page = &new MockSimplePage(); $page->expectNever('getText'); $frame = &new MockSimplePage(); $frame->setReturnValue('getText', 'Stuff'); $frameset = &new SimpleFrameset($page); $frameset->addFrame($frame); $this->assertEqual($frameset->getText(), 'Stuff'); } function testTextContentIsFromAllFrames() { $page = &new MockSimplePage(); $page->expectNever('getText'); $frame1 = &new MockSimplePage(); $frame1->setReturnValue('getText', 'Stuff1'); $frame2 = &new MockSimplePage(); $frame2->setReturnValue('getText', 'Stuff2'); $frameset = &new SimpleFrameset($page); $frameset->addFrame($frame1); $frameset->addFrame($frame2); $this->assertEqual($frameset->getText(), 'Stuff1 Stuff2'); } function testFieldFoundIsFirstInFramelist() { $frame1 = &new MockSimplePage(); $frame1->setReturnValue('getField', null); $frame1->expectOnce('getField', array(new SimpleByName('a'))); $frame2 = &new MockSimplePage(); $frame2->setReturnValue('getField', 'A'); $frame2->expectOnce('getField', array(new SimpleByName('a'))); $frame3 = &new MockSimplePage(); $frame3->expectNever('getField'); $page = &new MockSimplePage(); $frameset = &new SimpleFrameset($page); $frameset->addFrame($frame1); $frameset->addFrame($frame2); $frameset->addFrame($frame3); $this->assertIdentical($frameset->getField(new SimpleByName('a')), 'A'); } function testFrameReplacementByIndex() { $page = &new MockSimplePage(); $page->expectNever('getRaw'); $frame1 = &new MockSimplePage(); $frame1->setReturnValue('getRaw', 'Stuff1'); $frame2 = &new MockSimplePage(); $frame2->setReturnValue('getRaw', 'Stuff2'); $frameset = &new SimpleFrameset($page); $frameset->addFrame($frame1); $frameset->setFrame(array(1), $frame2); $this->assertEqual($frameset->getRaw(), 'Stuff2'); } function testFrameReplacementByName() { $page = &new MockSimplePage(); $page->expectNever('getRaw'); $frame1 = &new MockSimplePage(); $frame1->setReturnValue('getRaw', 'Stuff1'); $frame2 = &new MockSimplePage(); $frame2->setReturnValue('getRaw', 'Stuff2'); $frameset = &new SimpleFrameset($page); $frameset->addFrame($frame1, 'a'); $frameset->setFrame(array('a'), $frame2); $this->assertEqual($frameset->getRaw(), 'Stuff2'); } } class TestOfFrameNavigation extends UnitTestCase { function testStartsWithoutFrameFocus() { $page = &new MockSimplePage(); $frameset = &new SimpleFrameset($page); $frameset->addFrame($frame); $this->assertFalse($frameset->getFrameFocus()); } function testCanFocusOnSingleFrame() { $page = &new MockSimplePage(); $page->expectNever('getRaw'); $frame = &new MockSimplePage(); $frame->setReturnValue('getFrameFocus', array()); $frame->setReturnValue('getRaw', 'Stuff'); $frameset = &new SimpleFrameset($page); $frameset->addFrame($frame); $this->assertFalse($frameset->setFrameFocusByIndex(0)); $this->assertTrue($frameset->setFrameFocusByIndex(1)); $this->assertEqual($frameset->getRaw(), 'Stuff'); $this->assertFalse($frameset->setFrameFocusByIndex(2)); $this->assertIdentical($frameset->getFrameFocus(), array(1)); } function testContentComesFromFrameInFocus() { $page = &new MockSimplePage(); $frame1 = &new MockSimplePage(); $frame1->setReturnValue('getRaw', 'Stuff1'); $frame1->setReturnValue('getFrameFocus', array()); $frame2 = &new MockSimplePage(); $frame2->setReturnValue('getRaw', 'Stuff2'); $frame2->setReturnValue('getFrameFocus', array()); $frameset = &new SimpleFrameset($page); $frameset->addFrame($frame1); $frameset->addFrame($frame2); $this->assertTrue($frameset->setFrameFocusByIndex(1)); $this->assertEqual($frameset->getFrameFocus(), array(1)); $this->assertEqual($frameset->getRaw(), 'Stuff1'); $this->assertTrue($frameset->setFrameFocusByIndex(2)); $this->assertEqual($frameset->getFrameFocus(), array(2)); $this->assertEqual($frameset->getRaw(), 'Stuff2'); $this->assertFalse($frameset->setFrameFocusByIndex(3)); $this->assertEqual($frameset->getFrameFocus(), array(2)); $frameset->clearFrameFocus(); $this->assertEqual($frameset->getRaw(), 'Stuff1Stuff2'); } function testCanFocusByName() { $page = &new MockSimplePage(); $frame1 = &new MockSimplePage(); $frame1->setReturnValue('getRaw', 'Stuff1'); $frame1->setReturnValue('getFrameFocus', array()); $frame2 = &new MockSimplePage(); $frame2->setReturnValue('getRaw', 'Stuff2'); $frame2->setReturnValue('getFrameFocus', array()); $frameset = &new SimpleFrameset($page); $frameset->addFrame($frame1, 'A'); $frameset->addFrame($frame2, 'B'); $this->assertTrue($frameset->setFrameFocus('A')); $this->assertEqual($frameset->getFrameFocus(), array('A')); $this->assertEqual($frameset->getRaw(), 'Stuff1'); $this->assertTrue($frameset->setFrameFocusByIndex(2)); $this->assertEqual($frameset->getFrameFocus(), array('B')); $this->assertEqual($frameset->getRaw(), 'Stuff2'); $this->assertFalse($frameset->setFrameFocus('z')); $frameset->clearFrameFocus(); $this->assertEqual($frameset->getRaw(), 'Stuff1Stuff2'); } } class TestOfFramesetPageInterface extends UnitTestCase { var $_page_interface; var $_frameset_interface; function TestOfFramesetPageInterface() { $this->UnitTestCase(); $this->_page_interface = $this->_getPageMethods(); $this->_frameset_interface = $this->_getFramesetMethods(); } function assertListInAnyOrder($list, $expected) { sort($list); sort($expected); $this->assertEqual($list, $expected); } function _getPageMethods() { $methods = array(); foreach (get_class_methods('SimplePage') as $method) { if (strtolower($method) == strtolower('SimplePage')) { continue; } if (strtolower($method) == strtolower('getFrameset')) { continue; } if (strncmp($method, '_', 1) == 0) { continue; } if (strncmp($method, 'accept', 6) == 0) { continue; } $methods[] = $method; } return $methods; } function _getFramesetMethods() { $methods = array(); foreach (get_class_methods('SimpleFrameset') as $method) { if (strtolower($method) == strtolower('SimpleFrameset')) { continue; } if (strncmp($method, '_', 1) == 0) { continue; } if (strncmp($method, 'add', 3) == 0) { continue; } $methods[] = $method; } return $methods; } function testFramsetHasPageInterface() { $difference = array(); foreach ($this->_page_interface as $method) { if (! in_array($method, $this->_frameset_interface)) { $this->fail("No [$method] in Frameset class"); return; } } $this->pass('Frameset covers Page interface'); } function testHeadersReadFromFrameIfInFocus() { $frame = &new MockSimplePage(); $frame->setReturnValue('getUrl', new SimpleUrl('http://localhost/stuff')); $frame->setReturnValue('getRequest', 'POST stuff'); $frame->setReturnValue('getMethod', 'POST'); $frame->setReturnValue('getRequestData', array('a' => 'A')); $frame->setReturnValue('getHeaders', 'Header: content'); $frame->setReturnValue('getMimeType', 'text/xml'); $frame->setReturnValue('getResponseCode', 401); $frame->setReturnValue('getTransportError', 'Could not parse headers'); $frame->setReturnValue('getAuthentication', 'Basic'); $frame->setReturnValue('getRealm', 'Safe place'); $frameset = &new SimpleFrameset(new MockSimplePage()); $frameset->addFrame($frame); $frameset->setFrameFocusByIndex(1); $url = new SimpleUrl('http://localhost/stuff'); $url->setTarget(1); $this->assertIdentical($frameset->getUrl(), $url); $this->assertIdentical($frameset->getRequest(), 'POST stuff'); $this->assertIdentical($frameset->getMethod(), 'POST'); $this->assertIdentical($frameset->getRequestData(), array('a' => 'A')); $this->assertIdentical($frameset->getHeaders(), 'Header: content'); $this->assertIdentical($frameset->getMimeType(), 'text/xml'); $this->assertIdentical($frameset->getResponseCode(), 401); $this->assertIdentical($frameset->getTransportError(), 'Could not parse headers'); $this->assertIdentical($frameset->getAuthentication(), 'Basic'); $this->assertIdentical($frameset->getRealm(), 'Safe place'); } function testAbsoluteUrlsComeFromBothFrames() { $page = &new MockSimplePage(); $page->expectNever('getAbsoluteUrls'); $frame1 = &new MockSimplePage(); $frame1->setReturnValue( 'getAbsoluteUrls', array('http://www.lastcraft.com/', 'http://myserver/')); $frame2 = &new MockSimplePage(); $frame2->setReturnValue( 'getAbsoluteUrls', array('http://www.lastcraft.com/', 'http://test/')); $frameset = &new SimpleFrameset($page); $frameset->addFrame($frame1); $frameset->addFrame($frame2); $this->assertListInAnyOrder( $frameset->getAbsoluteUrls(), array('http://www.lastcraft.com/', 'http://myserver/', 'http://test/')); } function testRelativeUrlsComeFromBothFrames() { $frame1 = &new MockSimplePage(); $frame1->setReturnValue( 'getRelativeUrls', array('/', '.', '/test/', 'goodbye.php')); $frame2 = &new MockSimplePage(); $frame2->setReturnValue( 'getRelativeUrls', array('/', '..', '/test/', 'hello.php')); $page = &new MockSimplePage(); $page->expectNever('getRelativeUrls'); $frameset = &new SimpleFrameset($page); $frameset->addFrame($frame1); $frameset->addFrame($frame2); $this->assertListInAnyOrder( $frameset->getRelativeUrls(), array('/', '.', '/test/', 'goodbye.php', '..', 'hello.php')); } function testLabelledUrlsComeFromBothFrames() { $frame1 = &new MockSimplePage(); $frame1->setReturnValue( 'getUrlsByLabel', array(new SimpleUrl('goodbye.php')), array('a')); $frame2 = &new MockSimplePage(); $frame2->setReturnValue( 'getUrlsByLabel', array(new SimpleUrl('hello.php')), array('a')); $frameset = &new SimpleFrameset(new MockSimplePage()); $frameset->addFrame($frame1); $frameset->addFrame($frame2, 'Two'); $expected1 = new SimpleUrl('goodbye.php'); $expected1->setTarget(1); $expected2 = new SimpleUrl('hello.php'); $expected2->setTarget('Two'); $this->assertEqual( $frameset->getUrlsByLabel('a'), array($expected1, $expected2)); } function testUrlByIdComesFromFirstFrameToRespond() { $frame1 = &new MockSimplePage(); $frame1->setReturnValue('getUrlById', new SimpleUrl('four.php'), array(4)); $frame1->setReturnValue('getUrlById', false, array(5)); $frame2 = &new MockSimplePage(); $frame2->setReturnValue('getUrlById', false, array(4)); $frame2->setReturnValue('getUrlById', new SimpleUrl('five.php'), array(5)); $frameset = &new SimpleFrameset(new MockSimplePage()); $frameset->addFrame($frame1); $frameset->addFrame($frame2); $four = new SimpleUrl('four.php'); $four->setTarget(1); $this->assertEqual($frameset->getUrlById(4), $four); $five = new SimpleUrl('five.php'); $five->setTarget(2); $this->assertEqual($frameset->getUrlById(5), $five); } function testReadUrlsFromFrameInFocus() { $frame1 = &new MockSimplePage(); $frame1->setReturnValue('getAbsoluteUrls', array('a')); $frame1->setReturnValue('getRelativeUrls', array('r')); $frame1->setReturnValue('getUrlsByLabel', array(new SimpleUrl('l'))); $frame1->setReturnValue('getUrlById', new SimpleUrl('i')); $frame2 = &new MockSimplePage(); $frame2->expectNever('getAbsoluteUrls'); $frame2->expectNever('getRelativeUrls'); $frame2->expectNever('getUrlsByLabel'); $frame2->expectNever('getUrlById'); $frameset = &new SimpleFrameset(new MockSimplePage()); $frameset->addFrame($frame1, 'A'); $frameset->addFrame($frame2, 'B'); $frameset->setFrameFocus('A'); $this->assertIdentical($frameset->getAbsoluteUrls(), array('a')); $this->assertIdentical($frameset->getRelativeUrls(), array('r')); $expected = new SimpleUrl('l'); $expected->setTarget('A'); $this->assertIdentical($frameset->getUrlsByLabel('label'), array($expected)); $expected = new SimpleUrl('i'); $expected->setTarget('A'); $this->assertIdentical($frameset->getUrlById(99), $expected); } function testReadFrameTaggedUrlsFromFrameInFocus() { $frame = &new MockSimplePage(); $by_label = new SimpleUrl('l'); $by_label->setTarget('L'); $frame->setReturnValue('getUrlsByLabel', array($by_label)); $by_id = new SimpleUrl('i'); $by_id->setTarget('I'); $frame->setReturnValue('getUrlById', $by_id); $frameset = &new SimpleFrameset(new MockSimplePage()); $frameset->addFrame($frame, 'A'); $frameset->setFrameFocus('A'); $this->assertIdentical($frameset->getUrlsByLabel('label'), array($by_label)); $this->assertIdentical($frameset->getUrlById(99), $by_id); } function testFindingFormsById() { $frame = &new MockSimplePage(); $form = &new MockSimpleForm(); $frame->setReturnReference('getFormById', $form, array('a')); $frameset = &new SimpleFrameset(new MockSimplePage()); $frameset->addFrame(new MockSimplePage(), 'A'); $frameset->addFrame($frame, 'B'); $this->assertReference($frameset->getFormById('a'), $form); $frameset->setFrameFocus('A'); $this->assertNull($frameset->getFormById('a')); $frameset->setFrameFocus('B'); $this->assertReference($frameset->getFormById('a'), $form); } function testFindingFormsBySubmit() { $frame = &new MockSimplePage(); $form = &new MockSimpleForm(); $frame->setReturnReference( 'getFormBySubmit', $form, array(new SimpleByLabel('a'))); $frameset = &new SimpleFrameset(new MockSimplePage()); $frameset->addFrame(new MockSimplePage(), 'A'); $frameset->addFrame($frame, 'B'); $this->assertReference($frameset->getFormBySubmit(new SimpleByLabel('a')), $form); $frameset->setFrameFocus('A'); $this->assertNull($frameset->getFormBySubmit(new SimpleByLabel('a'))); $frameset->setFrameFocus('B'); $this->assertReference($frameset->getFormBySubmit(new SimpleByLabel('a')), $form); } function testFindingFormsByImage() { $frame = &new MockSimplePage(); $form = &new MockSimpleForm(); $frame->setReturnReference( 'getFormByImage', $form, array(new SimpleByLabel('a'))); $frameset = &new SimpleFrameset(new MockSimplePage()); $frameset->addFrame(new MockSimplePage(), 'A'); $frameset->addFrame($frame, 'B'); $this->assertReference($frameset->getFormByImage(new SimpleByLabel('a')), $form); $frameset->setFrameFocus('A'); $this->assertNull($frameset->getFormByImage(new SimpleByLabel('a'))); $frameset->setFrameFocus('B'); $this->assertReference($frameset->getFormByImage(new SimpleByLabel('a')), $form); } function testSettingAllFrameFieldsWhenNoFrameFocus() { $frame1 = &new MockSimplePage(); $frame1->expectOnce('setField', array(new SimpleById(22), 'A')); $frame2 = &new MockSimplePage(); $frame2->expectOnce('setField', array(new SimpleById(22), 'A')); $frameset = &new SimpleFrameset(new MockSimplePage()); $frameset->addFrame($frame1, 'A'); $frameset->addFrame($frame2, 'B'); $frameset->setField(new SimpleById(22), 'A'); } function testOnlySettingFieldFromFocusedFrame() { $frame1 = &new MockSimplePage(); $frame1->expectOnce('setField', array(new SimpleByLabelOrName('a'), 'A')); $frame2 = &new MockSimplePage(); $frame2->expectNever('setField'); $frameset = &new SimpleFrameset(new MockSimplePage()); $frameset->addFrame($frame1, 'A'); $frameset->addFrame($frame2, 'B'); $frameset->setFrameFocus('A'); $frameset->setField(new SimpleByLabelOrName('a'), 'A'); } function testOnlyGettingFieldFromFocusedFrame() { $frame1 = &new MockSimplePage(); $frame1->setReturnValue('getField', 'f', array(new SimpleByName('a'))); $frame2 = &new MockSimplePage(); $frame2->expectNever('getField'); $frameset = &new SimpleFrameset(new MockSimplePage()); $frameset->addFrame($frame1, 'A'); $frameset->addFrame($frame2, 'B'); $frameset->setFrameFocus('A'); $this->assertIdentical($frameset->getField(new SimpleByName('a')), 'f'); } } ?>postfixadmin-2.3.7/tests/simpletest/test/form_test.php0000664000175000017620000004035311157271050023310 0ustar davidpalepurple 'GET', 'action' => 'here.php', 'id' => '33')); $form = &new SimpleForm($tag, new SimpleUrl('http://host/a/index.html')); $this->assertEqual($form->getMethod(), 'get'); $this->assertEqual( $form->getAction(), new SimpleUrl('http://host/a/here.php')); $this->assertIdentical($form->getId(), '33'); $this->assertNull($form->getValue(new SimpleByName('a'))); } function testEmptyAction() { $tag = &new SimpleFormTag(array('method' => 'GET', 'action' => '', 'id' => '33')); $form = &new SimpleForm($tag, new SimpleUrl('http://host/a/index.html')); $this->assertEqual( $form->getAction(), new SimpleUrl('http://host/a/index.html')); } function testMissingAction() { $tag = &new SimpleFormTag(array('method' => 'GET', 'id' => '33')); $form = &new SimpleForm($tag, new SimpleUrl('http://host/a/index.html')); $this->assertEqual( $form->getAction(), new SimpleUrl('http://host/a/index.html')); } function testRootAction() { $tag = &new SimpleFormTag(array('method' => 'GET', 'action' => '/', 'id' => '33')); $form = &new SimpleForm($tag, new SimpleUrl('http://host/a/index.html')); $this->assertEqual( $form->getAction(), new SimpleUrl('http://host/')); } function testDefaultFrameTargetOnForm() { $tag = &new SimpleFormTag(array('method' => 'GET', 'action' => 'here.php', 'id' => '33')); $form = &new SimpleForm($tag, new SimpleUrl('http://host/a/index.html')); $form->setDefaultTarget('frame'); $expected = new SimpleUrl('http://host/a/here.php'); $expected->setTarget('frame'); $this->assertEqual($form->getAction(), $expected); } function testTextWidget() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('htp://host')); $form->addWidget(new SimpleTextTag( array('name' => 'me', 'type' => 'text', 'value' => 'Myself'))); $this->assertIdentical($form->getValue(new SimpleByName('me')), 'Myself'); $this->assertTrue($form->setField(new SimpleByName('me'), 'Not me')); $this->assertFalse($form->setField(new SimpleByName('not_present'), 'Not me')); $this->assertIdentical($form->getValue(new SimpleByName('me')), 'Not me'); $this->assertNull($form->getValue(new SimpleByName('not_present'))); } function testTextWidgetById() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('htp://host')); $form->addWidget(new SimpleTextTag( array('name' => 'me', 'type' => 'text', 'value' => 'Myself', 'id' => 50))); $this->assertIdentical($form->getValue(new SimpleById(50)), 'Myself'); $this->assertTrue($form->setField(new SimpleById(50), 'Not me')); $this->assertIdentical($form->getValue(new SimpleById(50)), 'Not me'); } function testTextWidgetByLabel() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('htp://host')); $widget = &new SimpleTextTag(array('name' => 'me', 'type' => 'text', 'value' => 'a')); $form->addWidget($widget); $widget->setLabel('thing'); $this->assertIdentical($form->getValue(new SimpleByLabel('thing')), 'a'); $this->assertTrue($form->setField(new SimpleByLabel('thing'), 'b')); $this->assertIdentical($form->getValue(new SimpleByLabel('thing')), 'b'); } function testSubmitEmpty() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('htp://host')); $this->assertIdentical($form->submit(), new SimpleGetEncoding()); } function testSubmitButton() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('http://host')); $form->addWidget(new SimpleSubmitTag( array('type' => 'submit', 'name' => 'go', 'value' => 'Go!', 'id' => '9'))); $this->assertTrue($form->hasSubmit(new SimpleByName('go'))); $this->assertEqual($form->getValue(new SimpleByName('go')), 'Go!'); $this->assertEqual($form->getValue(new SimpleById(9)), 'Go!'); $this->assertEqual( $form->submitButton(new SimpleByName('go')), new SimpleGetEncoding(array('go' => 'Go!'))); $this->assertEqual( $form->submitButton(new SimpleByLabel('Go!')), new SimpleGetEncoding(array('go' => 'Go!'))); $this->assertEqual( $form->submitButton(new SimpleById(9)), new SimpleGetEncoding(array('go' => 'Go!'))); } function testSubmitWithAdditionalParameters() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('http://host')); $form->addWidget(new SimpleSubmitTag( array('type' => 'submit', 'name' => 'go', 'value' => 'Go!'))); $this->assertEqual( $form->submitButton(new SimpleByLabel('Go!'), array('a' => 'A')), new SimpleGetEncoding(array('go' => 'Go!', 'a' => 'A'))); } function testSubmitButtonWithLabelOfSubmit() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('http://host')); $form->addWidget(new SimpleSubmitTag( array('type' => 'submit', 'name' => 'test', 'value' => 'Submit'))); $this->assertEqual( $form->submitButton(new SimpleByName('test')), new SimpleGetEncoding(array('test' => 'Submit'))); $this->assertEqual( $form->submitButton(new SimpleByLabel('Submit')), new SimpleGetEncoding(array('test' => 'Submit'))); } function testSubmitButtonWithWhitespacePaddedLabelOfSubmit() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('http://host')); $form->addWidget(new SimpleSubmitTag( array('type' => 'submit', 'name' => 'test', 'value' => ' Submit '))); $this->assertEqual( $form->submitButton(new SimpleByLabel('Submit')), new SimpleGetEncoding(array('test' => ' Submit '))); } function testImageSubmitButton() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('htp://host')); $form->addWidget(new SimpleImageSubmitTag(array( 'type' => 'image', 'src' => 'source.jpg', 'name' => 'go', 'alt' => 'Go!', 'id' => '9'))); $this->assertTrue($form->hasImage(new SimpleByLabel('Go!'))); $this->assertEqual( $form->submitImage(new SimpleByLabel('Go!'), 100, 101), new SimpleGetEncoding(array('go.x' => 100, 'go.y' => 101))); $this->assertTrue($form->hasImage(new SimpleByName('go'))); $this->assertEqual( $form->submitImage(new SimpleByName('go'), 100, 101), new SimpleGetEncoding(array('go.x' => 100, 'go.y' => 101))); $this->assertTrue($form->hasImage(new SimpleById(9))); $this->assertEqual( $form->submitImage(new SimpleById(9), 100, 101), new SimpleGetEncoding(array('go.x' => 100, 'go.y' => 101))); } function testImageSubmitButtonWithAdditionalData() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('htp://host')); $form->addWidget(new SimpleImageSubmitTag(array( 'type' => 'image', 'src' => 'source.jpg', 'name' => 'go', 'alt' => 'Go!'))); $this->assertEqual( $form->submitImage(new SimpleByLabel('Go!'), 100, 101, array('a' => 'A')), new SimpleGetEncoding(array('go.x' => 100, 'go.y' => 101, 'a' => 'A'))); } function testButtonTag() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('http://host')); $widget = &new SimpleButtonTag( array('type' => 'submit', 'name' => 'go', 'value' => 'Go', 'id' => '9')); $widget->addContent('Go!'); $form->addWidget($widget); $this->assertTrue($form->hasSubmit(new SimpleByName('go'))); $this->assertTrue($form->hasSubmit(new SimpleByLabel('Go!'))); $this->assertEqual( $form->submitButton(new SimpleByName('go')), new SimpleGetEncoding(array('go' => 'Go'))); $this->assertEqual( $form->submitButton(new SimpleByLabel('Go!')), new SimpleGetEncoding(array('go' => 'Go'))); $this->assertEqual( $form->submitButton(new SimpleById(9)), new SimpleGetEncoding(array('go' => 'Go'))); } function testSingleSelectFieldSubmitted() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('htp://host')); $select = &new SimpleSelectionTag(array('name' => 'a')); $select->addTag(new SimpleOptionTag( array('value' => 'aaa', 'selected' => ''))); $form->addWidget($select); $this->assertIdentical( $form->submit(), new SimpleGetEncoding(array('a' => 'aaa'))); } function testSingleSelectFieldSubmittedWithPost() { $form = &new SimpleForm( new SimpleFormTag(array('method' => 'post')), new SimpleUrl('htp://host')); $select = &new SimpleSelectionTag(array('name' => 'a')); $select->addTag(new SimpleOptionTag( array('value' => 'aaa', 'selected' => ''))); $form->addWidget($select); $this->assertIdentical( $form->submit(), new SimplePostEncoding(array('a' => 'aaa'))); } function testUnchecked() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('htp://host')); $form->addWidget(new SimpleCheckboxTag( array('name' => 'me', 'type' => 'checkbox'))); $this->assertIdentical($form->getValue(new SimpleByName('me')), false); $this->assertTrue($form->setField(new SimpleByName('me'), 'on')); $this->assertEqual($form->getValue(new SimpleByName('me')), 'on'); $this->assertFalse($form->setField(new SimpleByName('me'), 'other')); $this->assertEqual($form->getValue(new SimpleByName('me')), 'on'); } function testChecked() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('htp://host')); $form->addWidget(new SimpleCheckboxTag( array('name' => 'me', 'value' => 'a', 'type' => 'checkbox', 'checked' => ''))); $this->assertIdentical($form->getValue(new SimpleByName('me')), 'a'); $this->assertTrue($form->setField(new SimpleByName('me'), 'a')); $this->assertEqual($form->getValue(new SimpleByName('me')), 'a'); $this->assertTrue($form->setField(new SimpleByName('me'), false)); $this->assertEqual($form->getValue(new SimpleByName('me')), false); } function testSingleUncheckedRadioButton() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('htp://host')); $form->addWidget(new SimpleRadioButtonTag( array('name' => 'me', 'value' => 'a', 'type' => 'radio'))); $this->assertIdentical($form->getValue(new SimpleByName('me')), false); $this->assertTrue($form->setField(new SimpleByName('me'), 'a')); $this->assertEqual($form->getValue(new SimpleByName('me')), 'a'); } function testSingleCheckedRadioButton() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('htp://host')); $form->addWidget(new SimpleRadioButtonTag( array('name' => 'me', 'value' => 'a', 'type' => 'radio', 'checked' => ''))); $this->assertIdentical($form->getValue(new SimpleByName('me')), 'a'); $this->assertFalse($form->setField(new SimpleByName('me'), 'other')); } function testUncheckedRadioButtons() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('htp://host')); $form->addWidget(new SimpleRadioButtonTag( array('name' => 'me', 'value' => 'a', 'type' => 'radio'))); $form->addWidget(new SimpleRadioButtonTag( array('name' => 'me', 'value' => 'b', 'type' => 'radio'))); $this->assertIdentical($form->getValue(new SimpleByName('me')), false); $this->assertTrue($form->setField(new SimpleByName('me'), 'a')); $this->assertIdentical($form->getValue(new SimpleByName('me')), 'a'); $this->assertTrue($form->setField(new SimpleByName('me'), 'b')); $this->assertIdentical($form->getValue(new SimpleByName('me')), 'b'); $this->assertFalse($form->setField(new SimpleByName('me'), 'c')); $this->assertIdentical($form->getValue(new SimpleByName('me')), 'b'); } function testCheckedRadioButtons() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('htp://host')); $form->addWidget(new SimpleRadioButtonTag( array('name' => 'me', 'value' => 'a', 'type' => 'radio'))); $form->addWidget(new SimpleRadioButtonTag( array('name' => 'me', 'value' => 'b', 'type' => 'radio', 'checked' => ''))); $this->assertIdentical($form->getValue(new SimpleByName('me')), 'b'); $this->assertTrue($form->setField(new SimpleByName('me'), 'a')); $this->assertIdentical($form->getValue(new SimpleByName('me')), 'a'); } function testMultipleFieldsWithSameKey() { $form = &new SimpleForm( new SimpleFormTag(array()), new SimpleUrl('htp://host')); $form->addWidget(new SimpleCheckboxTag( array('name' => 'a', 'type' => 'checkbox', 'value' => 'me'))); $form->addWidget(new SimpleCheckboxTag( array('name' => 'a', 'type' => 'checkbox', 'value' => 'you'))); $this->assertIdentical($form->getValue(new SimpleByName('a')), false); $this->assertTrue($form->setField(new SimpleByName('a'), 'me')); $this->assertIdentical($form->getValue(new SimpleByName('a')), 'me'); } } ?>postfixadmin-2.3.7/tests/simpletest/test/eclipse_test.php0000664000175000017620000000236411157271050023771 0ustar davidpalepurpleexpectOnce('write',array($expected)); $listener->setReturnValue('write',-1); $pathparts = pathinfo($fullpath); $filename = $pathparts['basename']; $test= &new TestSuite($filename); $test->addTestFile($fullpath); $test->run(new EclipseReporter(&$listener)); $this->assertEqual($expected,$listener->output); } } ?>postfixadmin-2.3.7/tests/simpletest/test/adapter_test.php0000664000175000017620000000411511157271050023761 0ustar davidpalepurpleassertTrue(true, "PEAR true"); $this->assertFalse(false, "PEAR false"); } function testName() { $this->assertTrue($this->getName() == get_class($this)); } function testPass() { $this->pass("PEAR pass"); } function testNulls() { $value = null; $this->assertNull($value, "PEAR null"); $value = 0; $this->assertNotNull($value, "PEAR not null"); } function testType() { $this->assertType("Hello", "string", "PEAR type"); } function testEquals() { $this->assertEquals(12, 12, "PEAR identity"); $this->setLooselyTyped(true); $this->assertEquals("12", 12, "PEAR equality"); } function testSame() { $same = &new SameTestClass(); $this->assertSame($same, $same, "PEAR same"); } function testRegExp() { $this->assertRegExp('/hello/', "A big hello from me", "PEAR regex"); } } class TestOfPhpUnitAdapter extends TestCase { function TestOfPhpUnitAdapter() { $this->TestCase('TestOfPhpUnitAdapter'); } function testBoolean() { $this->assert(true, 'PHP Unit true'); } function testName() { $this->assert($this->name() == 'TestOfPhpUnitAdapter'); } function testEquals() { $this->assertEquals(12, 12, 'PHP Unit equality'); } function testMultilineEquals() { $this->assertEquals("a\nb\n", "a\nb\n", 'PHP Unit equality'); } function testRegExp() { $this->assertRegexp('/hello/', 'A big hello from me', 'PHPUnit regex'); } } ?>postfixadmin-2.3.7/tests/simpletest/test/compatibility_test.php0000664000175000017620000000675211157271050025223 0ustar davidpalepurple= 0) { eval('interface ComparisonInterface { }'); eval('class ComparisonClassWithInterface implements ComparisonInterface { }'); } class TestOfCompatibility extends UnitTestCase { function testIsA() { $this->assertTrue(SimpleTestCompatibility::isA( new ComparisonClass(), 'ComparisonClass')); $this->assertFalse(SimpleTestCompatibility::isA( new ComparisonClass(), 'ComparisonSubclass')); $this->assertTrue(SimpleTestCompatibility::isA( new ComparisonSubclass(), 'ComparisonClass')); } function testIdentityOfNumericStrings() { $numericString1 = "123"; $numericString2 = "00123"; $this->assertNotIdentical($numericString1, $numericString2); } function testIdentityOfObjects() { $object1 = new ComparisonClass(); $object2 = new ComparisonClass(); $this->assertIdentical($object1, $object2); } function testReferences () { $thing = "Hello"; $thing_reference = &$thing; $thing_copy = $thing; $this->assertTrue(SimpleTestCompatibility::isReference( $thing, $thing)); $this->assertTrue(SimpleTestCompatibility::isReference( $thing, $thing_reference)); $this->assertFalse(SimpleTestCompatibility::isReference( $thing, $thing_copy)); } function testObjectReferences () { $object = &new ComparisonClass(); $object_reference = &$object; $object_copy = new ComparisonClass(); $object_assignment = $object; $this->assertTrue(SimpleTestCompatibility::isReference( $object, $object)); $this->assertTrue(SimpleTestCompatibility::isReference( $object, $object_reference)); $this->assertFalse(SimpleTestCompatibility::isReference( $object, $object_copy)); if (version_compare(phpversion(), '5', '>=')) { $this->assertTrue(SimpleTestCompatibility::isReference( $object, $object_assignment)); } else { $this->assertFalse(SimpleTestCompatibility::isReference( $object, $object_assignment)); } } function testInteraceComparison() { if (version_compare(phpversion(), '5', '<')) { return; } $object = new ComparisonClassWithInterface(); $this->assertFalse(SimpleTestCompatibility::isA( new ComparisonClass(), 'ComparisonInterface')); $this->assertTrue(SimpleTestCompatibility::isA( new ComparisonClassWithInterface(), 'ComparisonInterface')); } } ?>postfixadmin-2.3.7/tests/simpletest/test/simpletest_test.php0000664000175000017620000000352411157271050024535 0ustar davidpalepurplefail('Should be ignored'); } } class ShouldNeverBeRunEither extends ShouldNeverBeRun { } class TestOfStackTrace extends UnitTestCase { function testCanFindAssertInTrace() { $trace = new SimpleStackTrace(array('assert')); $this->assertEqual( $trace->traceMethod(array(array( 'file' => '/my_test.php', 'line' => 24, 'function' => 'assertSomething'))), ' at [/my_test.php line 24]'); } } class DummyResource { } class TestOfContext extends UnitTestCase { function testCurrentContextIsUnique() { $this->assertReference( SimpleTest::getContext(), SimpleTest::getContext()); } function testContextHoldsCurrentTestCase() { $context = &SimpleTest::getContext(); $this->assertReference($this, $context->getTest()); } function testResourceIsSingleInstanceWithContext() { $context = &new SimpleTestContext(); $this->assertReference( $context->get('DummyResource'), $context->get('DummyResource')); } function testClearingContextResetsResources() { $context = &new SimpleTestContext(); $resource = &$context->get('DummyResource'); $context->clear(); $this->assertClone($resource, $context->get('DummyResource')); } } ?>postfixadmin-2.3.7/tests/simpletest/test/site/0000775000175000017620000000000012301477471021543 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/test/site/savant_style_form.html0000664000175000017620000000146011157271050026162 0ustar davidpalepurple Test of form submission with Savant style controls
    Checkbox A
    Radio B
    postfixadmin-2.3.7/tests/simpletest/test/site/redirect.php0000664000175000017620000000034311157271050024046 0ustar davidpalepurple Redirection test This is a test page for the SimpleTest PHP unit tester postfixadmin-2.3.7/tests/simpletest/test/site/self_form.php0000664000175000017620000000122611157271050024222 0ustar davidpalepurple 0) { $_GET = $HTTP_GET_VARS; } ?> Test of form self submission

    []

    []

    []

    postfixadmin-2.3.7/tests/simpletest/test/site/3.html0000664000175000017620000000014611157271050022565 0ustar davidpalepurple 3 1 postfixadmin-2.3.7/tests/simpletest/test/site/frame_b.html0000664000175000017620000000014511157271050024015 0ustar davidpalepurple B This is frame B
    postfixadmin-2.3.7/tests/simpletest/test/site/timestamp.php0000664000175000017620000000003211157271050024243 0ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/test/site/front_controller_style/0000775000175000017620000000000012301477471026356 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/test/site/front_controller_style/show_request.php0000664000175000017620000000314211157271050031610 0ustar davidpalepurple

    Request

    Protocol version
    Request method
    Accept header

    Cookies

    0) { foreach ($_COOKIE as $key => $value) { print "$key=[$value]
    \n"; } } ?>

    Raw GET data

    GET data

    0) { foreach ($get as $key => $value) { if (is_array($value)) { $value = implode(', ', $value); } print "$key=[$value]
    \n"; } } ?>

    Raw POST data

    POST data

    0) { foreach ($_POST as $key => $value) { print $key . "=["; if (is_array($value)) { print implode(', ', $value); } else { print $value; } print "]
    \n"; } } ?> postfixadmin-2.3.7/tests/simpletest/test/site/front_controller_style/a_page.php0000664000175000017620000000251511157271050030277 0ustar davidpalepurple 0) { $_COOKIE = $HTTP_COOKIE_VARS; } if (count($HTTP_GET_VARS) > 0) { $_GET = $HTTP_GET_VARS; } if (count($HTTP_POST_VARS) > 0) { $_POST = $HTTP_POST_VARS; } if (! isset($_SERVER)) { $_SERVER = $HTTP_SERVER_VARS; } global $HTTP_RAW_POST_DATA; require_once('../page_request.php'); ?> Simple test page with links Simple test page with links

    Links

    Self No page Bare action Empty query Empty link Current directory Down one

    Forms

    postfixadmin-2.3.7/tests/simpletest/test/site/front_controller_style/index.php0000664000175000017620000000351511157271050030173 0ustar davidpalepurple 0) { $_COOKIE = $HTTP_COOKIE_VARS; } if (count($HTTP_GET_VARS) > 0) { $_GET = $HTTP_GET_VARS; } if (count($HTTP_POST_VARS) > 0) { $_POST = $HTTP_POST_VARS; } if (! isset($_SERVER)) { $_SERVER = $HTTP_SERVER_VARS; } global $HTTP_RAW_POST_DATA; require_once('../page_request.php'); ?> Simple test front controller Simple test front controller

    Links

    Index No page Bare action Empty query Empty link Down one

    Forms

    postfixadmin-2.3.7/tests/simpletest/test/site/frame_links.html0000664000175000017620000000031011157271050024706 0ustar davidpalepurple 1 Set one to 2 Exit the frameset postfixadmin-2.3.7/tests/simpletest/test/site/link_confirm.php0000664000175000017620000000104211157271050024714 0ustar davidpalepurple SimpleTest testing links

    A target for the SimpleTest test suite.

    postfixadmin-2.3.7/tests/simpletest/test/site/form_without_action.php0000664000175000017620000000063711157271050026336 0ustar davidpalepurple Test of form submission

    _GET : []

    _POST : []

    postfixadmin-2.3.7/tests/simpletest/test/site/upload_form.html0000664000175000017620000000076011157271050024734 0ustar davidpalepurple Test of file upload


    postfixadmin-2.3.7/tests/simpletest/test/site/base_change_redirect.php0000664000175000017620000000030111157271050026337 0ustar davidpalepurple Redirection test This is a test page for the SimpleTest PHP unit tester postfixadmin-2.3.7/tests/simpletest/test/site/network_confirm.php0000664000175000017620000000460111157271050025454 0ustar davidpalepurple 0) { $_COOKIE = $HTTP_COOKIE_VARS; } if (count($HTTP_GET_VARS) > 0) { $_GET = $HTTP_GET_VARS; } if (count($HTTP_POST_VARS) > 0) { $_POST = $HTTP_POST_VARS; } if (! isset($_SERVER)) { $_SERVER = $HTTP_SERVER_VARS; } global $HTTP_RAW_POST_DATA; require_once('page_request.php'); ?> Simple test target file A target for the SimpleTest test suite.

    Request

    Protocol version
    Request method
    Accept header

    Cookies

    0) { foreach ($_COOKIE as $key => $value) { print htmlentities($key) . "=[" . htmlentities($value) . "]
    \n"; } } ?>

    Raw GET data

    GET data

    0) { foreach ($get as $key => $value) { if (is_array($value)) { $value = implode(', ', $value); } print htmlentities($key) . "=[" . htmlentities($value) . "]
    \n"; } } ?>

    Dump of $_GET data

    '; print_r($_GET); print ''; ?>

    Raw POST data

    POST data

    0) { foreach ($_POST as $key => $value) { print htmlentities($key) . "=["; if (is_array($value)) { print implode(', ', htmlentities($value)); } else { print htmlentities($value); } print "]
    \n"; } } ?> postfixadmin-2.3.7/tests/simpletest/test/site/form_with_false_defaults.html0000664000175000017620000000306611157271050027466 0ustar davidpalepurple Test of form submission








    Radio I
    postfixadmin-2.3.7/tests/simpletest/test/site/frameset.html0000664000175000017620000000046511157271050024235 0ustar davidpalepurple Frameset for testing of SimpleTest This content is for no frames only. postfixadmin-2.3.7/tests/simpletest/test/site/path/0000775000175000017620000000000012301477471022477 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/test/site/path/base_change_redirect.php0000664000175000017620000000027711157271050027307 0ustar davidpalepurple Redirection test This is a test page for the SimpleTest PHP unit tester postfixadmin-2.3.7/tests/simpletest/test/site/path/network_confirm.php0000664000175000017620000000423311157271050026411 0ustar davidpalepurple 0) { $_COOKIE = $HTTP_COOKIE_VARS; } if (count($HTTP_GET_VARS) > 0) { $_GET = $HTTP_GET_VARS; } if (count($HTTP_POST_VARS) > 0) { $_POST = $HTTP_POST_VARS; } if (!isset($_SERVER)) { $_SERVER = $HTTP_SERVER_VARS; } global $HTTP_RAW_POST_DATA; require_once('../page_request.php'); ?> Simple test target file in folder A target for the SimpleTest test suite.

    Request

    Protocol version
    Request method
    Accept header

    Cookies

    0) { foreach ($_COOKIE as $key => $value) { print $key . "=[" . $value . "]
    \n"; } } ?>

    Raw GET data

    GET data

    0) { foreach ($get as $key => $value) { if (is_array($value)) { $value = implode(', ', $value); } print $key . "=[" . $value . "]
    \n"; } } ?>

    Raw POST data

    POST data

    0) { foreach ($_POST as $key => $value) { print $key . "=["; if (is_array($value)) { print implode(', ', $value); } else { print $value; } print "]
    \n"; } } ?> postfixadmin-2.3.7/tests/simpletest/test/site/path/show_cookies.php0000664000175000017620000000074411157271050025702 0ustar davidpalepurple 0) { $_COOKIE = $HTTP_COOKIE_VARS; } ?> Simple test target file A target for the SimpleTest test suite that displays cookies.

    Cookies

    0) { foreach ($_COOKIE as $key => $value) { print $key . "=" . $value . ";"; } } ?> postfixadmin-2.3.7/tests/simpletest/test/site/double_base_change_redirect.php0000664000175000017620000000030611157271050027676 0ustar davidpalepurple Redirection test This is a test page for the SimpleTest PHP unit tester postfixadmin-2.3.7/tests/simpletest/test/site/multiple_widget_form.html0000664000175000017620000000430211157271050026642 0ustar davidpalepurple Test of form submission

    Multiple checkboxes B
    PHP compatible



    postfixadmin-2.3.7/tests/simpletest/test/site/frame_a.html0000664000175000017620000000014511157271050024014 0ustar davidpalepurple A This is frame A
    postfixadmin-2.3.7/tests/simpletest/test/site/form_with_unnamed_submit.html0000664000175000017620000000067111157271050027516 0ustar davidpalepurple Test of form submission

    postfixadmin-2.3.7/tests/simpletest/test/site/one_page_frameset.html0000664000175000017620000000037411157271050026071 0ustar davidpalepurple Frameset for testing of SimpleTest This content is for no frames only. postfixadmin-2.3.7/tests/simpletest/test/site/counting_frameset.html0000664000175000017620000000051111157271050026133 0ustar davidpalepurple Frameset for testing of SimpleTest This content is for no frames only. postfixadmin-2.3.7/tests/simpletest/test/site/protected/0000775000175000017620000000000012301477471023534 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/test/site/protected/.htaccess0000664000175000017620000000022511157271050025322 0ustar davidpalepurpleAuthName "Test of basic authentication" AuthType Basic AuthUserFile /home/marcus/projects/lastcraft/www/test/protected/.htpasswd require valid-user postfixadmin-2.3.7/tests/simpletest/test/site/protected/3.html0000664000175000017620000000014611157271050024556 0ustar davidpalepurple 3 1 postfixadmin-2.3.7/tests/simpletest/test/site/protected/network_confirm.php0000664000175000017620000000422111157271050027443 0ustar davidpalepurple 0) { $_COOKIE = $HTTP_COOKIE_VARS; } if (count($HTTP_GET_VARS) > 0) { $_GET = $HTTP_GET_VARS; } if (count($HTTP_POST_VARS) > 0) { $_POST = $HTTP_POST_VARS; } if (!isset($_SERVER)) { $_SERVER = $HTTP_SERVER_VARS; } global $HTTP_RAW_POST_DATA; require_once('../page_request.php'); ?> Simple test target file A target for the SimpleTest test suite.

    Request

    Protocol version
    Request method
    Accept header

    Cookies

    0) { foreach ($_COOKIE as $key => $value) { print $key . "=[" . $value . "]
    \n"; } } ?>

    Raw GET data

    GET data

    0) { foreach ($get as $key => $value) { if (is_array($value)) { $value = implode(', ', $value); } print $key . "=[" . $value . "]
    \n"; } } ?>

    Raw POST data

    POST data

    0) { foreach ($_POST as $key => $value) { print $key . "=["; if (is_array($value)) { print implode(', ', $value); } else { print $value; } print "]
    \n"; } } ?> postfixadmin-2.3.7/tests/simpletest/test/site/protected/1.html0000664000175000017620000000014611157271050024554 0ustar davidpalepurple 1 2 postfixadmin-2.3.7/tests/simpletest/test/site/protected/.htpasswd0000664000175000017620000000002311157271050025356 0ustar davidpalepurpletest:wOGY3sAo.zsek postfixadmin-2.3.7/tests/simpletest/test/site/protected/2.html0000664000175000017620000000014611157271050024555 0ustar davidpalepurple 2 3 postfixadmin-2.3.7/tests/simpletest/test/site/protected/local_redirect.php0000664000175000017620000000027411157271050027214 0ustar davidpalepurple Redirection test This is a test page for the SimpleTest PHP unit tester postfixadmin-2.3.7/tests/simpletest/test/site/protected/htaccess0000664000175000017620000000022411157271050025243 0ustar davidpalepurpleAuthName "SimpleTest basic authentication" AuthType Basic AuthUserFile /web/guide/lastcraft/public_html/test/protected/.htpasswd require valid-user postfixadmin-2.3.7/tests/simpletest/test/site/1.html0000664000175000017620000000014611157271050022563 0ustar davidpalepurple 1 2 postfixadmin-2.3.7/tests/simpletest/test/site/upload_handler.php0000664000175000017620000000115011157271050025223 0ustar davidpalepurple Test of file upload

    postfixadmin-2.3.7/tests/simpletest/test/site/slow_page.php0000664000175000017620000000020411157271050024221 0ustar davidpalepurple Slow page This page takes at least two seconds postfixadmin-2.3.7/tests/simpletest/test/site/2.html0000664000175000017620000000014611157271050022564 0ustar davidpalepurple 2 3 postfixadmin-2.3.7/tests/simpletest/test/site/local_redirect.php0000664000175000017620000000027411157271050025223 0ustar davidpalepurple Redirection test This is a test page for the SimpleTest PHP unit tester postfixadmin-2.3.7/tests/simpletest/test/site/search.png0000664000175000017620000000235411157271050023513 0ustar davidpalepurplePNG  IHDR6@NbKGD pHYs  d_tIME n9yIDATxXOH#W͐MT BFAE-B[Лϛڞ<t'%c[L"qFKzpI&<}}FD6,x `&''{3PL$8Ay$ON)cD4NqjZOY9'!'8ᜓygi>Oa~LLjz=@,&%*!j 1((JG*BuXBrrE0 9Jsc h4^+b1WJ3D^5RR)1ƺ[JӶm}lV}ByوTc4վ8j?98~lh !ȶmj6cl&""HJS"T2 iB lj\|ߧ؂AD˲ JywX^^6`ooe10H$8 È\.hDh\N}4 0˯:~;W.UŅ)Jl6iItQ"yW/װYYYQ+ j,[8uvȰ4DXu?5xLn0pppMݎh%wzv.B@F98>91|ͷVT:93kA;`kkK !9XO/ mV0//ʄhZj!"Rae۫b{ m.dYyG:Ji>]VUϪT*R},.zBDd8fV"d&_ Bi鳳3麽AH ^dz2Z 8G: Vg|*`a||a`ll 1r9`ll#iFFF055H׀14 ҘgaJ%<<4.^ VYiebbB"4o(ǀ>})>T_zGYd* Aԋh$IENDB`postfixadmin-2.3.7/tests/simpletest/test/site/page_request.php0000664000175000017620000000332111157271050024730 0ustar davidpalepurple_parsed = array(); foreach ($statements as $statement) { if (strpos($statement, '=') === false) { continue; } $this->_parseStatement($statement); } } /** @access private */ function _parseStatement($statement) { list($key, $value) = explode('=', $statement); $key = urldecode($key); if (preg_match('/(.*)\[\]$/', $key, $matches)) { $key = $matches[1]; if (! isset($this->_parsed[$key])) { $this->_parsed[$key] = array(); } $this->_addValue($key, $value); } elseif (isset($this->_parsed[$key])) { $this->_addValue($key, $value); } else { $this->_setValue($key, $value); } } /** @access private */ function _addValue($key, $value) { if (! is_array($this->_parsed[$key])) { $this->_parsed[$key] = array($this->_parsed[$key]); } $this->_parsed[$key][] = urldecode($value); } /** @access private */ function _setValue($key, $value) { $this->_parsed[$key] = urldecode($value); } function getAll() { return $this->_parsed; } function get() { $request = &new PageRequest($_SERVER['QUERY_STRING']); return $request->getAll(); } function post() { global $HTTP_RAW_POST_DATA; $request = &new PageRequest($HTTP_RAW_POST_DATA); return $request->getAll(); } } ?>postfixadmin-2.3.7/tests/simpletest/test/site/nested_frameset.html0000664000175000017620000000050711157271050025574 0ustar davidpalepurple Nested frameset for testing of SimpleTest This content is for no frames only. postfixadmin-2.3.7/tests/simpletest/test/site/form.html0000664000175000017620000000366511157271050023377 0ustar davidpalepurple Test of form submission






    Radio G





    postfixadmin-2.3.7/tests/simpletest/test/site/cookie_based_counter.php0000664000175000017620000000037311157271050026416 0ustar davidpalepurple Cookie Counter postfixadmin-2.3.7/tests/simpletest/test/site/messy_frameset.html0000664000175000017620000000131611157271050025451 0ustar davidpalepurple Frameset for testing of SimpleTest postfixadmin-2.3.7/tests/simpletest/test/site/form_with_mixed_post_and_get.html0000664000175000017620000000106311157271050030334 0ustar davidpalepurple Test of form submission


    postfixadmin-2.3.7/tests/simpletest/test/site/set_cookies.php0000664000175000017620000000120411157271050024551 0ustar davidpalepurple SimpleTest testing links

    A target for the SimpleTest test suite. All it does is set some cookies which you can see here.

    postfixadmin-2.3.7/tests/simpletest/test/site/form_with_tricky_defaults.html0000664000175000017620000000311111157271050027670 0ustar davidpalepurple Test of form submission






    Radio I
    postfixadmin-2.3.7/tests/simpletest/test/site/form_data_encoded_form.html0000664000175000017620000000372411157271050027070 0ustar davidpalepurple Test of form submission






    Radio G





    postfixadmin-2.3.7/tests/simpletest/test/test_with_parse_error.php0000664000175000017620000000025711157271050025722 0ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/test/url_test.php0000664000175000017620000004606311157271050023153 0ustar davidpalepurpleassertEqual($url->getScheme(), ''); $this->assertEqual($url->getHost(), ''); $this->assertEqual($url->getScheme('http'), 'http'); $this->assertEqual($url->getHost('localhost'), 'localhost'); $this->assertEqual($url->getPath(), ''); } function testBasicParsing() { $url = new SimpleUrl('https://www.lastcraft.com/test/'); $this->assertEqual($url->getScheme(), 'https'); $this->assertEqual($url->getHost(), 'www.lastcraft.com'); $this->assertEqual($url->getPath(), '/test/'); } function testRelativeUrls() { $url = new SimpleUrl('../somewhere.php'); $this->assertEqual($url->getScheme(), false); $this->assertEqual($url->getHost(), false); $this->assertEqual($url->getPath(), '../somewhere.php'); } function testParseBareParameter() { $url = new SimpleUrl('?a'); $this->assertEqual($url->getPath(), ''); $this->assertEqual($url->getEncodedRequest(), '?a'); $url->addRequestParameter('x', 'X'); $this->assertEqual($url->getEncodedRequest(), '?a=&x=X'); } function testParseEmptyParameter() { $url = new SimpleUrl('?a='); $this->assertEqual($url->getPath(), ''); $this->assertEqual($url->getEncodedRequest(), '?a='); $url->addRequestParameter('x', 'X'); $this->assertEqual($url->getEncodedRequest(), '?a=&x=X'); } function testParseParameterPair() { $url = new SimpleUrl('?a=A'); $this->assertEqual($url->getPath(), ''); $this->assertEqual($url->getEncodedRequest(), '?a=A'); $url->addRequestParameter('x', 'X'); $this->assertEqual($url->getEncodedRequest(), '?a=A&x=X'); } function testParseMultipleParameters() { $url = new SimpleUrl('?a=A&b=B'); $this->assertEqual($url->getEncodedRequest(), '?a=A&b=B'); $url->addRequestParameter('x', 'X'); $this->assertEqual($url->getEncodedRequest(), '?a=A&b=B&x=X'); } function testParsingParameterMixture() { $url = new SimpleUrl('?a=A&b=&c'); $this->assertEqual($url->getEncodedRequest(), '?a=A&b=&c'); $url->addRequestParameter('x', 'X'); $this->assertEqual($url->getEncodedRequest(), '?a=A&b=&c=&x=X'); } function testAddParametersFromScratch() { $url = new SimpleUrl(''); $url->addRequestParameter('a', 'A'); $this->assertEqual($url->getEncodedRequest(), '?a=A'); $url->addRequestParameter('b', 'B'); $this->assertEqual($url->getEncodedRequest(), '?a=A&b=B'); $url->addRequestParameter('a', 'aaa'); $this->assertEqual($url->getEncodedRequest(), '?a=A&b=B&a=aaa'); } function testClearingParameters() { $url = new SimpleUrl(''); $url->addRequestParameter('a', 'A'); $url->clearRequest(); $this->assertIdentical($url->getEncodedRequest(), ''); } function testEncodingParameters() { $url = new SimpleUrl(''); $url->addRequestParameter('a', '?!"\'#~@[]{}:;<>,./|$%^&*()_+-='); $this->assertIdentical( $request = $url->getEncodedRequest(), '?a=%3F%21%22%27%23%7E%40%5B%5D%7B%7D%3A%3B%3C%3E%2C.%2F%7C%A3%24%25%5E%26%2A%28%29_%2B-%3D'); } function testDecodingParameters() { $url = new SimpleUrl('?a=%3F%21%22%27%23%7E%40%5B%5D%7B%7D%3A%3B%3C%3E%2C.%2F%7C%A3%24%25%5E%26%2A%28%29_%2B-%3D'); $this->assertEqual( $url->getEncodedRequest(), '?a=' . urlencode('?!"\'#~@[]{}:;<>,./|$%^&*()_+-=')); } function testSettingCordinates() { $url = new SimpleUrl(''); $url->setCoordinates('32', '45'); $this->assertIdentical($url->getX(), 32); $this->assertIdentical($url->getY(), 45); $this->assertEqual($url->getEncodedRequest(), ''); } function testParseCordinates() { $url = new SimpleUrl('?32,45'); $this->assertIdentical($url->getX(), 32); $this->assertIdentical($url->getY(), 45); } function testClearingCordinates() { $url = new SimpleUrl('?32,45'); $url->setCoordinates(); $this->assertIdentical($url->getX(), false); $this->assertIdentical($url->getY(), false); } function testParsingParameterCordinateMixture() { $url = new SimpleUrl('?a=A&b=&c?32,45'); $this->assertIdentical($url->getX(), 32); $this->assertIdentical($url->getY(), 45); $this->assertEqual($url->getEncodedRequest(), '?a=A&b=&c'); } function testParsingParameterWithBadCordinates() { $url = new SimpleUrl('?a=A&b=&c?32'); $this->assertIdentical($url->getX(), false); $this->assertIdentical($url->getY(), false); $this->assertEqual($url->getEncodedRequest(), '?a=A&b=&c?32'); } function testPageSplitting() { $url = new SimpleUrl('./here/../there/somewhere.php'); $this->assertEqual($url->getPath(), './here/../there/somewhere.php'); $this->assertEqual($url->getPage(), 'somewhere.php'); $this->assertEqual($url->getBasePath(), './here/../there/'); } function testAbsolutePathPageSplitting() { $url = new SimpleUrl("http://host.com/here/there/somewhere.php"); $this->assertEqual($url->getPath(), "/here/there/somewhere.php"); $this->assertEqual($url->getPage(), "somewhere.php"); $this->assertEqual($url->getBasePath(), "/here/there/"); } function testSplittingUrlWithNoPageGivesEmptyPage() { $url = new SimpleUrl('/here/there/'); $this->assertEqual($url->getPath(), '/here/there/'); $this->assertEqual($url->getPage(), ''); $this->assertEqual($url->getBasePath(), '/here/there/'); } function testPathNormalisation() { $this->assertEqual( SimpleUrl::normalisePath('https://host.com/I/am/here/../there/somewhere.php'), 'https://host.com/I/am/there/somewhere.php'); } // regression test for #1535407 function testPathNormalisationWithSinglePeriod() { $this->assertEqual( SimpleUrl::normalisePath('https://host.com/I/am/here/./../there/somewhere.php'), 'https://host.com/I/am/there/somewhere.php'); } function testUsernameAndPasswordAreUrlDecoded() { $url = new SimpleUrl('http://' . urlencode('test@test') . ':' . urlencode('$!@*&%') . '@www.lastcraft.com'); $this->assertEqual($url->getUsername(), 'test@test'); $this->assertEqual($url->getPassword(), '$!@*&%'); } function testBlitz() { $this->assertUrl( "https://username:password@www.somewhere.com:243/this/that/here.php?a=1&b=2#anchor", array("https", "username", "password", "www.somewhere.com", 243, "/this/that/here.php", "com", "?a=1&b=2", "anchor"), array("a" => "1", "b" => "2")); $this->assertUrl( "username:password@www.somewhere.com/this/that/here.php?a=1", array(false, "username", "password", "www.somewhere.com", false, "/this/that/here.php", "com", "?a=1", false), array("a" => "1")); $this->assertUrl( "username:password@somewhere.com:243?1,2", array(false, "username", "password", "somewhere.com", 243, "/", "com", "", false), array(), array(1, 2)); $this->assertUrl( "https://www.somewhere.com", array("https", false, false, "www.somewhere.com", false, "/", "com", "", false)); $this->assertUrl( "username@www.somewhere.com:243#anchor", array(false, "username", false, "www.somewhere.com", 243, "/", "com", "", "anchor")); $this->assertUrl( "/this/that/here.php?a=1&b=2?3,4", array(false, false, false, false, false, "/this/that/here.php", false, "?a=1&b=2", false), array("a" => "1", "b" => "2"), array(3, 4)); $this->assertUrl( "username@/here.php?a=1&b=2", array(false, "username", false, false, false, "/here.php", false, "?a=1&b=2", false), array("a" => "1", "b" => "2")); } function testAmbiguousHosts() { $this->assertUrl( "tigger", array(false, false, false, false, false, "tigger", false, "", false)); $this->assertUrl( "/tigger", array(false, false, false, false, false, "/tigger", false, "", false)); $this->assertUrl( "//tigger", array(false, false, false, "tigger", false, "/", false, "", false)); $this->assertUrl( "//tigger/", array(false, false, false, "tigger", false, "/", false, "", false)); $this->assertUrl( "tigger.com", array(false, false, false, "tigger.com", false, "/", "com", "", false)); $this->assertUrl( "me.net/tigger", array(false, false, false, "me.net", false, "/tigger", "net", "", false)); } function testAsString() { $this->assertPreserved('https://www.here.com'); $this->assertPreserved('http://me:secret@www.here.com'); $this->assertPreserved('http://here/there'); $this->assertPreserved('http://here/there?a=A&b=B'); $this->assertPreserved('http://here/there?a=1&a=2'); $this->assertPreserved('http://here/there?a=1&a=2?9,8'); $this->assertPreserved('http://host?a=1&a=2'); $this->assertPreserved('http://host#stuff'); $this->assertPreserved('http://me:secret@www.here.com/a/b/c/here.html?a=A?7,6'); $this->assertPreserved('http://www.here.com/?a=A__b=B'); } function assertUrl($raw, $parts, $params = false, $coords = false) { if (! is_array($params)) { $params = array(); } $url = new SimpleUrl($raw); $this->assertIdentical($url->getScheme(), $parts[0], "[$raw] scheme -> %s"); $this->assertIdentical($url->getUsername(), $parts[1], "[$raw] username -> %s"); $this->assertIdentical($url->getPassword(), $parts[2], "[$raw] password -> %s"); $this->assertIdentical($url->getHost(), $parts[3], "[$raw] host -> %s"); $this->assertIdentical($url->getPort(), $parts[4], "[$raw] port -> %s"); $this->assertIdentical($url->getPath(), $parts[5], "[$raw] path -> %s"); $this->assertIdentical($url->getTld(), $parts[6], "[$raw] tld -> %s"); $this->assertIdentical($url->getEncodedRequest(), $parts[7], "[$raw] encoded -> %s"); $this->assertIdentical($url->getFragment(), $parts[8], "[$raw] fragment -> %s"); if ($coords) { $this->assertIdentical($url->getX(), $coords[0], "[$raw] x -> %s"); $this->assertIdentical($url->getY(), $coords[1], "[$raw] y -> %s"); } } function testUrlWithTwoSlashesInPath() { $url = new SimpleUrl('/article/categoryedit/insert//'); $this->assertEqual($url->getPath(), '/article/categoryedit/insert//'); } function assertPreserved($string) { $url = new SimpleUrl($string); $this->assertEqual($url->asString(), $string); } } class TestOfAbsoluteUrls extends UnitTestCase { function testMakingAbsolute() { $url = new SimpleUrl('../there/somewhere.php'); $this->assertEqual($url->getPath(), '../there/somewhere.php'); $absolute = $url->makeAbsolute('https://host.com:1234/I/am/here/'); $this->assertEqual($absolute->getScheme(), 'https'); $this->assertEqual($absolute->getHost(), 'host.com'); $this->assertEqual($absolute->getPort(), 1234); $this->assertEqual($absolute->getPath(), '/I/am/there/somewhere.php'); } function testMakingAnEmptyUrlAbsolute() { $url = new SimpleUrl(''); $this->assertEqual($url->getPath(), ''); $absolute = $url->makeAbsolute('http://host.com/I/am/here/page.html'); $this->assertEqual($absolute->getScheme(), 'http'); $this->assertEqual($absolute->getHost(), 'host.com'); $this->assertEqual($absolute->getPath(), '/I/am/here/page.html'); } function testMakingAnEmptyUrlAbsoluteWithMissingPageName() { $url = new SimpleUrl(''); $this->assertEqual($url->getPath(), ''); $absolute = $url->makeAbsolute('http://host.com/I/am/here/'); $this->assertEqual($absolute->getScheme(), 'http'); $this->assertEqual($absolute->getHost(), 'host.com'); $this->assertEqual($absolute->getPath(), '/I/am/here/'); } function testMakingAShortQueryUrlAbsolute() { $url = new SimpleUrl('?a#b'); $this->assertEqual($url->getPath(), ''); $absolute = $url->makeAbsolute('http://host.com/I/am/here/'); $this->assertEqual($absolute->getScheme(), 'http'); $this->assertEqual($absolute->getHost(), 'host.com'); $this->assertEqual($absolute->getPath(), '/I/am/here/'); $this->assertEqual($absolute->getEncodedRequest(), '?a'); $this->assertEqual($absolute->getFragment(), 'b'); } function testMakingADirectoryUrlAbsolute() { $url = new SimpleUrl('hello/'); $this->assertEqual($url->getPath(), 'hello/'); $this->assertEqual($url->getBasePath(), 'hello/'); $this->assertEqual($url->getPage(), ''); $absolute = $url->makeAbsolute('http://host.com/I/am/here/page.html'); $this->assertEqual($absolute->getPath(), '/I/am/here/hello/'); } function testMakingARootUrlAbsolute() { $url = new SimpleUrl('/'); $this->assertEqual($url->getPath(), '/'); $absolute = $url->makeAbsolute('http://host.com/I/am/here/page.html'); $this->assertEqual($absolute->getPath(), '/'); } function testMakingARootPageUrlAbsolute() { $url = new SimpleUrl('/here.html'); $absolute = $url->makeAbsolute('http://host.com/I/am/here/page.html'); $this->assertEqual($absolute->getPath(), '/here.html'); } function testCarryAuthenticationFromRootPage() { $url = new SimpleUrl('here.html'); $absolute = $url->makeAbsolute('http://test:secret@host.com/'); $this->assertEqual($absolute->getPath(), '/here.html'); $this->assertEqual($absolute->getUsername(), 'test'); $this->assertEqual($absolute->getPassword(), 'secret'); } function testMakingCoordinateUrlAbsolute() { $url = new SimpleUrl('?1,2'); $this->assertEqual($url->getPath(), ''); $absolute = $url->makeAbsolute('http://host.com/I/am/here/'); $this->assertEqual($absolute->getScheme(), 'http'); $this->assertEqual($absolute->getHost(), 'host.com'); $this->assertEqual($absolute->getPath(), '/I/am/here/'); $this->assertEqual($absolute->getX(), 1); $this->assertEqual($absolute->getY(), 2); } function testMakingAbsoluteAppendedPath() { $url = new SimpleUrl('./there/somewhere.php'); $absolute = $url->makeAbsolute('https://host.com/here/'); $this->assertEqual($absolute->getPath(), '/here/there/somewhere.php'); } function testMakingAbsoluteBadlyFormedAppendedPath() { $url = new SimpleUrl('there/somewhere.php'); $absolute = $url->makeAbsolute('https://host.com/here/'); $this->assertEqual($absolute->getPath(), '/here/there/somewhere.php'); } function testMakingAbsoluteHasNoEffectWhenAlreadyAbsolute() { $url = new SimpleUrl('https://test:secret@www.lastcraft.com:321/stuff/?a=1#f'); $absolute = $url->makeAbsolute('http://host.com/here/'); $this->assertEqual($absolute->getScheme(), 'https'); $this->assertEqual($absolute->getUsername(), 'test'); $this->assertEqual($absolute->getPassword(), 'secret'); $this->assertEqual($absolute->getHost(), 'www.lastcraft.com'); $this->assertEqual($absolute->getPort(), 321); $this->assertEqual($absolute->getPath(), '/stuff/'); $this->assertEqual($absolute->getEncodedRequest(), '?a=1'); $this->assertEqual($absolute->getFragment(), 'f'); } function testMakingAbsoluteCarriesAuthenticationWhenAlreadyAbsolute() { $url = new SimpleUrl('https://www.lastcraft.com'); $absolute = $url->makeAbsolute('http://test:secret@host.com/here/'); $this->assertEqual($absolute->getHost(), 'www.lastcraft.com'); $this->assertEqual($absolute->getUsername(), 'test'); $this->assertEqual($absolute->getPassword(), 'secret'); } function testMakingHostOnlyAbsoluteDoesNotCarryAnyOtherInformation() { $url = new SimpleUrl('http://www.lastcraft.com'); $absolute = $url->makeAbsolute('https://host.com:81/here/'); $this->assertEqual($absolute->getScheme(), 'http'); $this->assertEqual($absolute->getHost(), 'www.lastcraft.com'); $this->assertIdentical($absolute->getPort(), false); $this->assertEqual($absolute->getPath(), '/'); } } class TestOfFrameUrl extends UnitTestCase { function testTargetAttachment() { $url = new SimpleUrl('http://www.site.com/home.html'); $this->assertIdentical($url->getTarget(), false); $url->setTarget('A frame'); $this->assertIdentical($url->getTarget(), 'A frame'); } } ?>postfixadmin-2.3.7/tests/simpletest/test/expectation_test.php0000664000175000017620000001613511157271050024671 0ustar davidpalepurpleassertTrue($is_true->test(true)); $this->assertFalse($is_true->test(false)); } function testStringMatch() { $hello = &new EqualExpectation("Hello"); $this->assertTrue($hello->test("Hello")); $this->assertFalse($hello->test("Goodbye")); } function testInteger() { $fifteen = &new EqualExpectation(15); $this->assertTrue($fifteen->test(15)); $this->assertFalse($fifteen->test(14)); } function testFloat() { $pi = &new EqualExpectation(3.14); $this->assertTrue($pi->test(3.14)); $this->assertFalse($pi->test(3.15)); } function testArray() { $colours = &new EqualExpectation(array("r", "g", "b")); $this->assertTrue($colours->test(array("r", "g", "b"))); $this->assertFalse($colours->test(array("g", "b", "r"))); } function testHash() { $is_blue = &new EqualExpectation(array("r" => 0, "g" => 0, "b" => 255)); $this->assertTrue($is_blue->test(array("r" => 0, "g" => 0, "b" => 255))); $this->assertFalse($is_blue->test(array("r" => 0, "g" => 255, "b" => 0))); } function testHashWithOutOfOrderKeysShouldStillMatch() { $any_order = &new EqualExpectation(array('a' => 1, 'b' => 2)); $this->assertTrue($any_order->test(array('b' => 2, 'a' => 1))); } } class TestOfWithin extends UnitTestCase { function testWithinFloatingPointMargin() { $within = new WithinMarginExpectation(1.0, 0.2); $this->assertFalse($within->test(0.7)); $this->assertTrue($within->test(0.8)); $this->assertTrue($within->test(0.9)); $this->assertTrue($within->test(1.1)); $this->assertTrue($within->test(1.2)); $this->assertFalse($within->test(1.3)); } function testOutsideFloatingPointMargin() { $within = new OutsideMarginExpectation(1.0, 0.2); $this->assertTrue($within->test(0.7)); $this->assertFalse($within->test(0.8)); $this->assertFalse($within->test(1.2)); $this->assertTrue($within->test(1.3)); } } class TestOfInequality extends UnitTestCase { function testStringMismatch() { $not_hello = &new NotEqualExpectation("Hello"); $this->assertTrue($not_hello->test("Goodbye")); $this->assertFalse($not_hello->test("Hello")); } } class RecursiveNasty { var $_me; function RecursiveNasty() { $this->_me = $this; } } class TestOfIdentity extends UnitTestCase { function testType() { $string = &new IdenticalExpectation("37"); $this->assertTrue($string->test("37")); $this->assertFalse($string->test(37)); $this->assertFalse($string->test("38")); } function _testNastyPhp5Bug() { $this->assertFalse(new RecursiveNasty() != new RecursiveNasty()); } function _testReallyHorribleRecursiveStructure() { $hopeful = &new IdenticalExpectation(new RecursiveNasty()); $this->assertTrue($hopeful->test(new RecursiveNasty())); } } class TestOfNonIdentity extends UnitTestCase { function testType() { $string = &new NotIdenticalExpectation("37"); $this->assertTrue($string->test("38")); $this->assertTrue($string->test(37)); $this->assertFalse($string->test("37")); } } class TestOfPatterns extends UnitTestCase { function testWanted() { $pattern = &new PatternExpectation('/hello/i'); $this->assertTrue($pattern->test("Hello world")); $this->assertFalse($pattern->test("Goodbye world")); } function testUnwanted() { $pattern = &new NoPatternExpectation('/hello/i'); $this->assertFalse($pattern->test("Hello world")); $this->assertTrue($pattern->test("Goodbye world")); } } class ExpectedMethodTarget { function hasThisMethod() {} } class TestOfMethodExistence extends UnitTestCase { function testHasMethod() { $instance = &new ExpectedMethodTarget(); $expectation = &new MethodExistsExpectation('hasThisMethod'); $this->assertTrue($expectation->test($instance)); $expectation = &new MethodExistsExpectation('doesNotHaveThisMethod'); $this->assertFalse($expectation->test($instance)); } } class TestOfIsA extends UnitTestCase { function testString() { $expectation = &new IsAExpectation('string'); $this->assertTrue($expectation->test('Hello')); $this->assertFalse($expectation->test(5)); } function testBoolean() { $expectation = &new IsAExpectation('boolean'); $this->assertTrue($expectation->test(true)); $this->assertFalse($expectation->test(1)); } function testBool() { $expectation = &new IsAExpectation('bool'); $this->assertTrue($expectation->test(true)); $this->assertFalse($expectation->test(1)); } function testDouble() { $expectation = &new IsAExpectation('double'); $this->assertTrue($expectation->test(5.0)); $this->assertFalse($expectation->test(5)); } function testFloat() { $expectation = &new IsAExpectation('float'); $this->assertTrue($expectation->test(5.0)); $this->assertFalse($expectation->test(5)); } function testReal() { $expectation = &new IsAExpectation('real'); $this->assertTrue($expectation->test(5.0)); $this->assertFalse($expectation->test(5)); } function testInteger() { $expectation = &new IsAExpectation('integer'); $this->assertTrue($expectation->test(5)); $this->assertFalse($expectation->test(5.0)); } function testInt() { $expectation = &new IsAExpectation('int'); $this->assertTrue($expectation->test(5)); $this->assertFalse($expectation->test(5.0)); } } class TestOfNotA extends UnitTestCase { function testString() { $expectation = &new NotAExpectation('string'); $this->assertFalse($expectation->test('Hello')); $this->assertTrue($expectation->test(5)); } } ?>postfixadmin-2.3.7/tests/simpletest/test/shell_tester_test.php0000664000175000017620000000265711157271050025047 0ustar davidpalepurple_mock_shell; } function testGenericEquality() { $this->assertEqual('a', 'a'); $this->assertNotEqual('a', 'A'); } function testExitCode() { $this->_mock_shell = &new MockSimpleShell(); $this->_mock_shell->setReturnValue('execute', 0); $this->_mock_shell->expectOnce('execute', array('ls')); $this->assertTrue($this->execute('ls')); $this->assertExitCode(0); } function testOutput() { $this->_mock_shell = &new MockSimpleShell(); $this->_mock_shell->setReturnValue('execute', 0); $this->_mock_shell->setReturnValue('getOutput', "Line 1\nLine 2\n"); $this->assertOutput("Line 1\nLine 2\n"); } function testOutputPatterns() { $this->_mock_shell = &new MockSimpleShell(); $this->_mock_shell->setReturnValue('execute', 0); $this->_mock_shell->setReturnValue('getOutput', "Line 1\nLine 2\n"); $this->assertOutputPattern('/line/i'); $this->assertNoOutputPattern('/line 2/'); } } ?>postfixadmin-2.3.7/tests/simpletest/test/visual_test.php0000664000175000017620000004413311157271050023650 0ustar davidpalepurple_a = $a; } } class PassingUnitTestCaseOutput extends UnitTestCase { function testOfResults() { $this->pass('Pass'); } function testTrue() { $this->assertTrue(true); } function testFalse() { $this->assertFalse(false); } function testExpectation() { $expectation = &new EqualExpectation(25, 'My expectation message: %s'); $this->assert($expectation, 25, 'My assert message : %s'); } function testNull() { $this->assertNull(null, "%s -> Pass"); $this->assertNotNull(false, "%s -> Pass"); } function testType() { $this->assertIsA("hello", "string", "%s -> Pass"); $this->assertIsA($this, "PassingUnitTestCaseOutput", "%s -> Pass"); $this->assertIsA($this, "UnitTestCase", "%s -> Pass"); } function testTypeEquality() { $this->assertEqual("0", 0, "%s -> Pass"); } function testNullEquality() { $this->assertNotEqual(null, 1, "%s -> Pass"); $this->assertNotEqual(1, null, "%s -> Pass"); } function testIntegerEquality() { $this->assertNotEqual(1, 2, "%s -> Pass"); } function testStringEquality() { $this->assertEqual("a", "a", "%s -> Pass"); $this->assertNotEqual("aa", "ab", "%s -> Pass"); } function testHashEquality() { $this->assertEqual(array("a" => "A", "b" => "B"), array("b" => "B", "a" => "A"), "%s -> Pass"); } function testWithin() { $this->assertWithinMargin(5, 5.4, 0.5, "%s -> Pass"); } function testOutside() { $this->assertOutsideMargin(5, 5.6, 0.5, "%s -> Pass"); } function testStringIdentity() { $a = "fred"; $b = $a; $this->assertIdentical($a, $b, "%s -> Pass"); } function testTypeIdentity() { $a = "0"; $b = 0; $this->assertNotIdentical($a, $b, "%s -> Pass"); } function testNullIdentity() { $this->assertNotIdentical(null, 1, "%s -> Pass"); $this->assertNotIdentical(1, null, "%s -> Pass"); } function testHashIdentity() { } function testObjectEquality() { $this->assertEqual(new TestDisplayClass(4), new TestDisplayClass(4), "%s -> Pass"); $this->assertNotEqual(new TestDisplayClass(4), new TestDisplayClass(5), "%s -> Pass"); } function testObjectIndentity() { $this->assertIdentical(new TestDisplayClass(false), new TestDisplayClass(false), "%s -> Pass"); $this->assertNotIdentical(new TestDisplayClass(false), new TestDisplayClass(0), "%s -> Pass"); } function testReference() { $a = "fred"; $b = &$a; $this->assertReference($a, $b, "%s -> Pass"); } function testCloneOnDifferentObjects() { $a = "fred"; $b = $a; $c = "Hello"; $this->assertClone($a, $b, "%s -> Pass"); } function testPatterns() { $this->assertPattern('/hello/i', "Hello there", "%s -> Pass"); $this->assertNoPattern('/hello/', "Hello there", "%s -> Pass"); } function testLongStrings() { $text = ""; for ($i = 0; $i < 10; $i++) { $text .= "0123456789"; } $this->assertEqual($text, $text); } } class FailingUnitTestCaseOutput extends UnitTestCase { function testOfResults() { $this->fail('Fail'); // Fail. } function testTrue() { $this->assertTrue(false); // Fail. } function testFalse() { $this->assertFalse(true); // Fail. } function testExpectation() { $expectation = &new EqualExpectation(25, 'My expectation message: %s'); $this->assert($expectation, 24, 'My assert message : %s'); // Fail. } function testNull() { $this->assertNull(false, "%s -> Fail"); // Fail. $this->assertNotNull(null, "%s -> Fail"); // Fail. } function testType() { $this->assertIsA(14, "string", "%s -> Fail"); // Fail. $this->assertIsA(14, "TestOfUnitTestCaseOutput", "%s -> Fail"); // Fail. $this->assertIsA($this, "TestReporter", "%s -> Fail"); // Fail. } function testTypeEquality() { $this->assertNotEqual("0", 0, "%s -> Fail"); // Fail. } function testNullEquality() { $this->assertEqual(null, 1, "%s -> Fail"); // Fail. $this->assertEqual(1, null, "%s -> Fail"); // Fail. } function testIntegerEquality() { $this->assertEqual(1, 2, "%s -> Fail"); // Fail. } function testStringEquality() { $this->assertNotEqual("a", "a", "%s -> Fail"); // Fail. $this->assertEqual("aa", "ab", "%s -> Fail"); // Fail. } function testHashEquality() { $this->assertEqual(array("a" => "A", "b" => "B"), array("b" => "B", "a" => "Z"), "%s -> Fail"); } function testWithin() { $this->assertWithinMargin(5, 5.6, 0.5, "%s -> Fail"); // Fail. } function testOutside() { $this->assertOutsideMargin(5, 5.4, 0.5, "%s -> Fail"); // Fail. } function testStringIdentity() { $a = "fred"; $b = $a; $this->assertNotIdentical($a, $b, "%s -> Fail"); // Fail. } function testTypeIdentity() { $a = "0"; $b = 0; $this->assertIdentical($a, $b, "%s -> Fail"); // Fail. } function testNullIdentity() { $this->assertIdentical(null, 1, "%s -> Fail"); // Fail. $this->assertIdentical(1, null, "%s -> Fail"); // Fail. } function testHashIdentity() { $this->assertIdentical(array("a" => "A", "b" => "B"), array("b" => "B", "a" => "A"), "%s -> fail"); // Fail. } function testObjectEquality() { $this->assertNotEqual(new TestDisplayClass(4), new TestDisplayClass(4), "%s -> Fail"); // Fail. $this->assertEqual(new TestDisplayClass(4), new TestDisplayClass(5), "%s -> Fail"); // Fail. } function testObjectIndentity() { $this->assertNotIdentical(new TestDisplayClass(false), new TestDisplayClass(false), "%s -> Fail"); // Fail. $this->assertIdentical(new TestDisplayClass(false), new TestDisplayClass(0), "%s -> Fail"); // Fail. } function testReference() { $a = "fred"; $b = &$a; $this->assertClone($a, $b, "%s -> Fail"); // Fail. } function testCloneOnDifferentObjects() { $a = "fred"; $b = $a; $c = "Hello"; $this->assertClone($a, $c, "%s -> Fail"); // Fail. } function testPatterns() { $this->assertPattern('/hello/', "Hello there", "%s -> Fail"); // Fail. $this->assertNoPattern('/hello/i', "Hello there", "%s -> Fail"); // Fail. } function testLongStrings() { $text = ""; for ($i = 0; $i < 10; $i++) { $text .= "0123456789"; } $this->assertEqual($text . $text, $text . "a" . $text); // Fail. } } class VisualTestOfErrors extends UnitTestCase { function testDumping() { $this->dump(array('Hello'), 'Displaying a variable'); } function testErrorDisplay() { trigger_error('Default'); // Exception. trigger_error('Error', E_USER_ERROR); // Exception. trigger_error('Warning', E_USER_WARNING); // Exception. trigger_error('Notice', E_USER_NOTICE); // Exception. } function testErrorTrap() { $this->expectError(); // Pass. trigger_error('Error 1'); } function testErrorText() { $this->expectError('Error 2', "%s -> Pass"); $this->expectError('Error 2b', "%s -> Fail"); // Fail. trigger_error('Error 2'); $this->dump('This should lie between the two errors'); trigger_error('Error 3'); } function testErrorPatterns() { $this->expectError(new PatternExpectation('/Error 2/'), "%s -> Pass"); $this->expectError(new PatternExpectation('/Error 2/'), "%s -> Fail"); // Fail. trigger_error('Error 2'); $this->dump('This should lie between the two errors'); trigger_error('Error 3'); } function testExceptionTrap() { if (version_compare(phpversion(), '5') >= 0) { eval('throw new Exception("Ouch!");'); $this->message('Should not be here'); } else { trigger_error('No exceptions in PHP4'); } } function testExceptionExpectationShowsErrorWhenNoException() { if (version_compare(phpversion(), '5') >= 0) { $this->expectException(); } else { trigger_error('No exceptions in PHP4'); } } function testExceptionExpectationShowsPassWhenException() { if (version_compare(phpversion(), '5') >= 0) { $this->expectException(); eval('throw new Exception("Ouch!");'); } else { trigger_error('No exceptions in PHP4'); } } function testSignal() { $fred = "signal as a string"; $this->signal("Signal", $fred); // Signal. } } class Dummy { function Dummy() { } function a() { } } Mock::generate('Dummy'); class TestOfMockObjectsOutput extends UnitTestCase { function testCallCounts() { $dummy = &new MockDummy(); $dummy->expectCallCount('a', 1, 'My message: %s'); $dummy->a(); $dummy->a(); } function testMinimumCallCounts() { $dummy = &new MockDummy(); $dummy->expectMinimumCallCount('a', 2, 'My message: %s'); $dummy->a(); $dummy->a(); } function testEmptyMatching() { $dummy = &new MockDummy(); $dummy->expectArguments('a', array()); $dummy->a(); $dummy->a(null); // Fail. } function testEmptyMatchingWithCustomMessage() { $dummy = &new MockDummy(); $dummy->expectArguments('a', array(), 'My expectation message: %s'); $dummy->a(); $dummy->a(null); // Fail. } function testNullMatching() { $dummy = &new MockDummy(); $dummy->expectArguments('a', array(null)); $dummy->a(null); $dummy->a(); // Fail. } function testBooleanMatching() { $dummy = &new MockDummy(); $dummy->expectArguments('a', array(true, false)); $dummy->a(true, false); $dummy->a(true, true); // Fail. } function testIntegerMatching() { $dummy = &new MockDummy(); $dummy->expectArguments('a', array(32, 33)); $dummy->a(32, 33); $dummy->a(32, 34); // Fail. } function testFloatMatching() { $dummy = &new MockDummy(); $dummy->expectArguments('a', array(3.2, 3.3)); $dummy->a(3.2, 3.3); $dummy->a(3.2, 3.4); // Fail. } function testStringMatching() { $dummy = &new MockDummy(); $dummy->expectArguments('a', array('32', '33')); $dummy->a('32', '33'); $dummy->a('32', '34'); // Fail. } function testEmptyMatchingWithCustomExpectationMessage() { $dummy = &new MockDummy(); $dummy->expectArguments( 'a', array(new EqualExpectation('A', 'My part expectation message: %s')), 'My expectation message: %s'); $dummy->a('A'); $dummy->a('B'); // Fail. } function testArrayMatching() { $dummy = &new MockDummy(); $dummy->expectArguments('a', array(array(32), array(33))); $dummy->a(array(32), array(33)); $dummy->a(array(32), array('33')); // Fail. } function testObjectMatching() { $a = new Dummy(); $a->a = 'a'; $b = new Dummy(); $b->b = 'b'; $dummy = &new MockDummy(); $dummy->expectArguments('a', array($a, $b)); $dummy->a($a, $b); $dummy->a($a, $a); // Fail. } function testBigList() { $dummy = &new MockDummy(); $dummy->expectArguments('a', array(false, 0, 1, 1.0)); $dummy->a(false, 0, 1, 1.0); $dummy->a(true, false, 2, 2.0); // Fail. } } class TestOfPastBugs extends UnitTestCase { function testMixedTypes() { $this->assertEqual(array(), null, "%s -> Pass"); $this->assertIdentical(array(), null, "%s -> Fail"); // Fail. } function testMockWildcards() { $dummy = &new MockDummy(); $dummy->expectArguments('a', array('*', array(33))); $dummy->a(array(32), array(33)); $dummy->a(array(32), array('33')); // Fail. } } class TestOfVisualShell extends ShellTestCase { function testDump() { $this->execute('ls'); $this->dumpOutput(); $this->execute('dir'); $this->dumpOutput(); } function testDumpOfList() { $this->execute('ls'); $this->dump($this->getOutputAsList()); } } class PassesAsWellReporter extends HtmlReporter { function _getCss() { return parent::_getCss() . ' .pass { color: darkgreen; }'; } function paintPass($message) { parent::paintPass($message); print "Pass: "; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); print implode(" -> ", $breadcrumb); print " -> " . htmlentities($message) . "
    \n"; } function paintSignal($type, &$payload) { print "$type: "; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); print implode(" -> ", $breadcrumb); print " -> " . htmlentities(serialize($payload)) . "
    \n"; } } class TestOfSkippingNoMatterWhat extends UnitTestCase { function skip() { $this->skipIf(true, 'Always skipped -> %s'); } function testFail() { $this->fail('This really shouldn\'t have happened'); } } class TestOfSkippingOrElse extends UnitTestCase { function skip() { $this->skipUnless(false, 'Always skipped -> %s'); } function testFail() { $this->fail('This really shouldn\'t have happened'); } } class TestOfSkippingTwiceOver extends UnitTestCase { function skip() { $this->skipIf(true, 'First reason -> %s'); $this->skipIf(true, 'Second reason -> %s'); } function testFail() { $this->fail('This really shouldn\'t have happened'); } } class TestThatShouldNotBeSkipped extends UnitTestCase { function skip() { $this->skipIf(false); $this->skipUnless(true); } function testFail() { $this->fail('We should see this message'); } function testPass() { $this->pass('We should see this message'); } } $test = &new TestSuite('Visual test with 50 passes, 50 fails and 7 exceptions'); $test->addTestCase(new PassingUnitTestCaseOutput()); $test->addTestCase(new FailingUnitTestCaseOutput()); $test->addTestCase(new VisualTestOfErrors()); $test->addTestCase(new TestOfMockObjectsOutput()); $test->addTestCase(new TestOfPastBugs()); $test->addTestCase(new TestOfVisualShell()); $test->addTestCase(new TestOfSkippingNoMatterWhat()); $test->addTestCase(new TestOfSkippingOrElse()); $test->addTestCase(new TestOfSkippingTwiceOver()); $test->addTestCase(new TestThatShouldNotBeSkipped()); if (isset($_GET['xml']) || in_array('xml', (isset($argv) ? $argv : array()))) { $reporter = &new XmlReporter(); } elseif (TextReporter::inCli()) { $reporter = &new TextReporter(); } else { $reporter = &new PassesAsWellReporter(); } if (isset($_GET['dry']) || in_array('dry', (isset($argv) ? $argv : array()))) { $reporter->makeDry(); } exit ($test->run($reporter) ? 0 : 1); ?>postfixadmin-2.3.7/tests/simpletest/test/page_test.php0000664000175000017620000011417511157271050023265 0ustar davidpalepurple 'http://somewhere')); $tag->addContent('Label'); $page = &new MockSimplePage(); $page->expectArguments('acceptTag', array($tag)); $page->expectCallCount('acceptTag', 1); $builder = &new PartialSimplePageBuilder(); $builder->setReturnReference('_createPage', $page); $builder->setReturnReference('_createParser', new MockSimpleHtmlSaxParser()); $builder->SimplePageBuilder(); $builder->parse(new MockSimpleHttpResponse()); $this->assertTrue($builder->startElement( 'a', array('href' => 'http://somewhere'))); $this->assertTrue($builder->addContent('Label')); $this->assertTrue($builder->endElement('a')); } function testLinkWithId() { $tag = &new SimpleAnchorTag(array("href" => "http://somewhere", "id" => "44")); $tag->addContent("Label"); $page = &new MockSimplePage(); $page->expectArguments("acceptTag", array($tag)); $page->expectCallCount("acceptTag", 1); $builder = &new PartialSimplePageBuilder(); $builder->setReturnReference('_createPage', $page); $builder->setReturnReference('_createParser', new MockSimpleHtmlSaxParser()); $builder->SimplePageBuilder(); $builder->parse(new MockSimpleHttpResponse()); $this->assertTrue($builder->startElement( "a", array("href" => "http://somewhere", "id" => "44"))); $this->assertTrue($builder->addContent("Label")); $this->assertTrue($builder->endElement("a")); } function testLinkExtraction() { $tag = &new SimpleAnchorTag(array("href" => "http://somewhere")); $tag->addContent("Label"); $page = &new MockSimplePage(); $page->expectArguments("acceptTag", array($tag)); $page->expectCallCount("acceptTag", 1); $builder = &new PartialSimplePageBuilder(); $builder->setReturnReference('_createPage', $page); $builder->setReturnReference('_createParser', new MockSimpleHtmlSaxParser()); $builder->SimplePageBuilder(); $builder->parse(new MockSimpleHttpResponse()); $this->assertTrue($builder->addContent("Starting stuff")); $this->assertTrue($builder->startElement( "a", array("href" => "http://somewhere"))); $this->assertTrue($builder->addContent("Label")); $this->assertTrue($builder->endElement("a")); $this->assertTrue($builder->addContent("Trailing stuff")); } function testMultipleLinks() { $a1 = new SimpleAnchorTag(array("href" => "http://somewhere")); $a1->addContent("1"); $a2 = new SimpleAnchorTag(array("href" => "http://elsewhere")); $a2->addContent("2"); $page = &new MockSimplePage(); $page->expectArgumentsAt(0, "acceptTag", array($a1)); $page->expectArgumentsAt(1, "acceptTag", array($a2)); $page->expectCallCount("acceptTag", 2); $builder = &new PartialSimplePageBuilder(); $builder->setReturnReference('_createPage', $page); $builder->setReturnReference('_createParser', new MockSimpleHtmlSaxParser()); $builder->SimplePageBuilder(); $builder->parse(new MockSimpleHttpResponse()); $builder->startElement("a", array("href" => "http://somewhere")); $builder->addContent("1"); $builder->endElement("a"); $builder->addContent("Padding"); $builder->startElement("a", array("href" => "http://elsewhere")); $builder->addContent("2"); $builder->endElement("a"); } function testTitle() { $tag = &new SimpleTitleTag(array()); $tag->addContent("HereThere"); $page = &new MockSimplePage(); $page->expectArguments("acceptTag", array($tag)); $page->expectCallCount("acceptTag", 1); $builder = &new PartialSimplePageBuilder(); $builder->setReturnReference('_createPage', $page); $builder->setReturnReference('_createParser', new MockSimpleHtmlSaxParser()); $builder->SimplePageBuilder(); $builder->parse(new MockSimpleHttpResponse()); $builder->startElement("title", array()); $builder->addContent("Here"); $builder->addContent("There"); $builder->endElement("title"); } function testForm() { $page = &new MockSimplePage(); $page->expectOnce("acceptFormStart", array(new SimpleFormTag(array()))); $page->expectOnce("acceptFormEnd", array()); $builder = &new PartialSimplePageBuilder(); $builder->setReturnReference('_createPage', $page); $builder->setReturnReference('_createParser', new MockSimpleHtmlSaxParser()); $builder->SimplePageBuilder(); $builder->parse(new MockSimpleHttpResponse()); $builder->startElement("form", array()); $builder->addContent("Stuff"); $builder->endElement("form"); } } class TestOfPageParsing extends UnitTestCase { function testParseMechanics() { $parser = &new MockSimpleHtmlSaxParser(); $parser->expectOnce('parse', array('stuff')); $page = &new MockSimplePage(); $page->expectOnce('acceptPageEnd'); $builder = &new PartialSimplePageBuilder(); $builder->setReturnReference('_createPage', $page); $builder->setReturnReference('_createParser', $parser); $builder->SimplePageBuilder(); $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', 'stuff'); $builder->parse($response); } } class TestOfErrorPage extends UnitTestCase { function testInterface() { $page = &new SimplePage(); $this->assertEqual($page->getTransportError(), 'No page fetched yet'); $this->assertIdentical($page->getRaw(), false); $this->assertIdentical($page->getHeaders(), false); $this->assertIdentical($page->getMimeType(), false); $this->assertIdentical($page->getResponseCode(), false); $this->assertIdentical($page->getAuthentication(), false); $this->assertIdentical($page->getRealm(), false); $this->assertFalse($page->hasFrames()); $this->assertIdentical($page->getAbsoluteUrls(), array()); $this->assertIdentical($page->getRelativeUrls(), array()); $this->assertIdentical($page->getTitle(), false); } } class TestOfPageHeaders extends UnitTestCase { function testUrlAccessor() { $headers = &new MockSimpleHttpHeaders(); $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getHeaders', $headers); $response->setReturnValue('getMethod', 'POST'); $response->setReturnValue('getUrl', new SimpleUrl('here')); $response->setReturnValue('getRequestData', array('a' => 'A')); $page = &new SimplePage($response); $this->assertEqual($page->getMethod(), 'POST'); $this->assertEqual($page->getUrl(), new SimpleUrl('here')); $this->assertEqual($page->getRequestData(), array('a' => 'A')); } function testTransportError() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getError', 'Ouch'); $page = &new SimplePage($response); $this->assertEqual($page->getTransportError(), 'Ouch'); } function testHeadersAccessor() { $headers = &new MockSimpleHttpHeaders(); $headers->setReturnValue('getRaw', 'My: Headers'); $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getHeaders', $headers); $page = &new SimplePage($response); $this->assertEqual($page->getHeaders(), 'My: Headers'); } function testMimeAccessor() { $headers = &new MockSimpleHttpHeaders(); $headers->setReturnValue('getMimeType', 'text/html'); $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getHeaders', $headers); $page = &new SimplePage($response); $this->assertEqual($page->getMimeType(), 'text/html'); } function testResponseAccessor() { $headers = &new MockSimpleHttpHeaders(); $headers->setReturnValue('getResponseCode', 301); $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getHeaders', $headers); $page = &new SimplePage($response); $this->assertIdentical($page->getResponseCode(), 301); } function testAuthenticationAccessors() { $headers = &new MockSimpleHttpHeaders(); $headers->setReturnValue('getAuthentication', 'Basic'); $headers->setReturnValue('getRealm', 'Secret stuff'); $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getHeaders', $headers); $page = &new SimplePage($response); $this->assertEqual($page->getAuthentication(), 'Basic'); $this->assertEqual($page->getRealm(), 'Secret stuff'); } } class TestOfHtmlPage extends UnitTestCase { function testRawAccessor() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', 'Raw HTML'); $page = &new SimplePage($response); $this->assertEqual($page->getRaw(), 'Raw HTML'); } function testTextAccessor() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', 'Some "messy" HTML'); $page = &new SimplePage($response); $this->assertEqual($page->getText(), 'Some "messy" HTML'); } function testNoLinks() { $page = &new SimplePage(new MockSimpleHttpResponse()); $this->assertIdentical($page->getAbsoluteUrls(), array(), 'abs->%s'); $this->assertIdentical($page->getRelativeUrls(), array(), 'rel->%s'); $this->assertIdentical($page->getUrlsByLabel('Label'), array()); } function testAddAbsoluteLink() { $link = &new SimpleAnchorTag(array('href' => 'http://somewhere.com')); $link->addContent('Label'); $page = &new SimplePage(new MockSimpleHttpResponse()); $page->AcceptTag($link); $this->assertEqual($page->getAbsoluteUrls(), array('http://somewhere.com'), 'abs->%s'); $this->assertIdentical($page->getRelativeUrls(), array(), 'rel->%s'); $this->assertEqual( $page->getUrlsByLabel('Label'), array(new SimpleUrl('http://somewhere.com'))); } function testAddStrictRelativeLink() { $link = &new SimpleAnchorTag(array('href' => './somewhere.php')); $link->addContent('Label'); $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getUrl', new SimpleUrl('http://host/')); $page = &new SimplePage($response); $page->AcceptTag($link); $this->assertEqual($page->getAbsoluteUrls(), array(), 'abs->%s'); $this->assertIdentical($page->getRelativeUrls(), array('./somewhere.php'), 'rel->%s'); $this->assertEqual( $page->getUrlsByLabel('Label'), array(new SimpleUrl('http://host/somewhere.php'))); } function testAddRelativeLink() { $link = &new SimpleAnchorTag(array('href' => 'somewhere.php')); $link->addContent('Label'); $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getUrl', new SimpleUrl('http://host/')); $page = &new SimplePage($response); $page->AcceptTag($link); $this->assertEqual($page->getAbsoluteUrls(), array(), 'abs->%s'); $this->assertIdentical($page->getRelativeUrls(), array('somewhere.php'), 'rel->%s'); $this->assertEqual( $page->getUrlsByLabel('Label'), array(new SimpleUrl('http://host/somewhere.php'))); } function testLinkIds() { $link = &new SimpleAnchorTag(array('href' => './somewhere.php', 'id' => 33)); $link->addContent('Label'); $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getUrl', new SimpleUrl('http://host/')); $page = &new SimplePage($response); $page->AcceptTag($link); $this->assertEqual( $page->getUrlsByLabel('Label'), array(new SimpleUrl('http://host/somewhere.php'))); $this->assertFalse($page->getUrlById(0)); $this->assertEqual( $page->getUrlById(33), new SimpleUrl('http://host/somewhere.php')); } function testFindLinkWithNormalisation() { $link = &new SimpleAnchorTag(array('href' => './somewhere.php', 'id' => 33)); $link->addContent(' Long & thin '); $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getUrl', new SimpleUrl('http://host/')); $page = &new SimplePage($response); $page->AcceptTag($link); $this->assertEqual( $page->getUrlsByLabel('Long & thin'), array(new SimpleUrl('http://host/somewhere.php'))); } function testFindLinkWithImage() { $link = &new SimpleAnchorTag(array('href' => './somewhere.php', 'id' => 33)); $link->addContent('<A picture>'); $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getUrl', new SimpleUrl('http://host/')); $page = &new SimplePage($response); $page->AcceptTag($link); $this->assertEqual( $page->getUrlsByLabel(''), array(new SimpleUrl('http://host/somewhere.php'))); } function testTitleSetting() { $title = &new SimpleTitleTag(array()); $title->addContent('Title'); $page = &new SimplePage(new MockSimpleHttpResponse()); $page->AcceptTag($title); $this->assertEqual($page->getTitle(), 'Title'); } function testFramesetAbsence() { $url = new SimpleUrl('here'); $response = new MockSimpleHttpResponse(); $response->setReturnValue('getUrl', $url); $page = &new SimplePage($response); $this->assertFalse($page->hasFrames()); $this->assertIdentical($page->getFrameset(), false); } function testHasEmptyFrameset() { $page = &new SimplePage(new MockSimpleHttpResponse()); $page->acceptFramesetStart(new SimpleTag('frameset', array())); $page->acceptFramesetEnd(); $this->assertTrue($page->hasFrames()); $this->assertIdentical($page->getFrameset(), array()); } function testFramesInPage() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getUrl', new SimpleUrl('http://here')); $page = &new SimplePage($response); $page->acceptFrame(new SimpleFrameTag(array('src' => '1.html'))); $page->acceptFramesetStart(new SimpleTag('frameset', array())); $page->acceptFrame(new SimpleFrameTag(array('src' => '2.html'))); $page->acceptFrame(new SimpleFrameTag(array('src' => '3.html'))); $page->acceptFramesetEnd(); $page->acceptFrame(new SimpleFrameTag(array('src' => '4.html'))); $this->assertTrue($page->hasFrames()); $this->assertIdentical($page->getFrameset(), array( 1 => new SimpleUrl('http://here/2.html'), 2 => new SimpleUrl('http://here/3.html'))); } function testNamedFramesInPage() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getUrl', new SimpleUrl('http://here')); $page = &new SimplePage($response); $page->acceptFramesetStart(new SimpleTag('frameset', array())); $page->acceptFrame(new SimpleFrameTag(array('src' => '1.html'))); $page->acceptFrame(new SimpleFrameTag(array('src' => '2.html', 'name' => 'A'))); $page->acceptFrame(new SimpleFrameTag(array('src' => '3.html', 'name' => 'B'))); $page->acceptFrame(new SimpleFrameTag(array('src' => '4.html'))); $page->acceptFramesetEnd(); $this->assertTrue($page->hasFrames()); $this->assertIdentical($page->getFrameset(), array( 1 => new SimpleUrl('http://here/1.html'), 'A' => new SimpleUrl('http://here/2.html'), 'B' => new SimpleUrl('http://here/3.html'), 4 => new SimpleUrl('http://here/4.html'))); } } class TestOfFormsCreatedFromEventStream extends UnitTestCase { function testFormCanBeSubmitted() { $page = &new SimplePage(new MockSimpleHttpResponse()); $page->acceptFormStart( new SimpleFormTag(array('method' => 'GET', 'action' => 'here.php'))); $page->AcceptTag( new SimpleSubmitTag(array('type' => 'submit', 'name' => 's'))); $page->acceptFormEnd(); $form = &$page->getFormBySubmit(new SimpleByLabel('Submit')); $this->assertEqual( $form->submitButton(new SimpleByLabel('Submit')), new SimpleGetEncoding(array('s' => 'Submit'))); } function testInputFieldCanBeReadBack() { $page = &new SimplePage(new MockSimpleHttpResponse()); $page->acceptFormStart( new SimpleFormTag(array("method" => "GET", "action" => "here.php"))); $page->AcceptTag( new SimpleTextTag(array("type" => "text", "name" => "a", "value" => "A"))); $page->AcceptTag( new SimpleSubmitTag(array("type" => "submit", "name" => "s"))); $page->acceptFormEnd(); $this->assertEqual($page->getField(new SimpleByName('a')), 'A'); } function testInputFieldCanBeReadBackByLabel() { $label = &new SimpleLabelTag(array()); $page = &new SimplePage(new MockSimpleHttpResponse()); $page->acceptFormStart( new SimpleFormTag(array("method" => "GET", "action" => "here.php"))); $page->acceptLabelStart($label); $label->addContent('l'); $page->AcceptTag( new SimpleTextTag(array("type" => "text", "name" => "a", "value" => "A"))); $page->acceptLabelEnd(); $page->AcceptTag( new SimpleSubmitTag(array("type" => "submit", "name" => "s"))); $page->acceptFormEnd(); $this->assertEqual($page->getField(new SimpleByLabel('l')), 'A'); } } class TestOfPageScraping extends UnitTestCase { function &parse($response) { $builder = &new SimplePageBuilder(); $page = &$builder->parse($response); return $page; } function testEmptyPage() { $page = &new SimplePage(new MockSimpleHttpResponse()); $this->assertIdentical($page->getAbsoluteUrls(), array()); $this->assertIdentical($page->getRelativeUrls(), array()); $this->assertIdentical($page->getTitle(), false); } function testUninterestingPage() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '

    Stuff

    '); $page = &$this->parse($response); $this->assertIdentical($page->getAbsoluteUrls(), array()); $this->assertIdentical($page->getRelativeUrls(), array()); } function testLinksPage() { $raw = ''; $raw .= '
    There'; $raw .= 'That page'; $raw .= ''; $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', $raw); $response->setReturnValue('getUrl', new SimpleUrl('http://www.here.com/a/index.html')); $page = &$this->parse($response); $this->assertIdentical( $page->getAbsoluteUrls(), array('http://there.com/that.html')); $this->assertIdentical( $page->getRelativeUrls(), array('there.html')); $this->assertIdentical( $page->getUrlsByLabel('There'), array(new SimpleUrl('http://www.here.com/a/there.html'))); $this->assertEqual( $page->getUrlById('0'), new SimpleUrl('http://there.com/that.html')); } function testTitle() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', 'Me'); $page = &$this->parse($response); $this->assertEqual($page->getTitle(), 'Me'); } function testNastyTitle() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue( 'getContent', ' <b>Me&Me
    '); $page = &$this->parse($response); $this->assertEqual($page->getTitle(), "Me&Me"); } function testCompleteForm() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '
    ' . '' . '
    '); $page = &$this->parse($response); $this->assertEqual($page->getField(new SimpleByName('here')), "Hello"); } function testUnclosedForm() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '
    ' . '' . ''); $page = &$this->parse($response); $this->assertEqual($page->getField(new SimpleByName('here')), "Hello"); } function testEmptyFrameset() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue( 'getContent', ''); $page = &$this->parse($response); $this->assertTrue($page->hasFrames()); $this->assertIdentical($page->getFrameset(), array()); } function testSingleFrame() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue( 'getContent', ''); $response->setReturnValue('getUrl', new SimpleUrl('http://host/')); $page = &$this->parse($response); $this->assertTrue($page->hasFrames()); $this->assertIdentical( $page->getFrameset(), array(1 => new SimpleUrl('http://host/a.html'))); } function testSingleFrameInNestedFrameset() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '' . '' . ''); $response->setReturnValue('getUrl', new SimpleUrl('http://host/')); $page = &$this->parse($response); $this->assertTrue($page->hasFrames()); $this->assertIdentical( $page->getFrameset(), array(1 => new SimpleUrl('http://host/a.html'))); } function testFrameWithNoSource() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue( 'getContent', ''); $page = &$this->parse($response); $this->assertTrue($page->hasFrames()); $this->assertIdentical($page->getFrameset(), array()); } function testFramesCollectedWithNestedFramesetTags() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '' . '' . '' . '' . ''); $response->setReturnValue('getUrl', new SimpleUrl('http://host/')); $page = &$this->parse($response); $this->assertTrue($page->hasFrames()); $this->assertIdentical($page->getFrameset(), array( 1 => new SimpleUrl('http://host/a.html'), 2 => new SimpleUrl('http://host/b.html'), 3 => new SimpleUrl('http://host/c.html'))); } function testNamedFrames() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '' . '' . '' . '' . '' . ''); $response->setReturnValue('getUrl', new SimpleUrl('http://host/')); $page = &$this->parse($response); $this->assertTrue($page->hasFrames()); $this->assertIdentical($page->getFrameset(), array( 1 => new SimpleUrl('http://host/a.html'), '_one' => new SimpleUrl('http://host/b.html'), 3 => new SimpleUrl('http://host/c.html'), '_two' => new SimpleUrl('http://host/d.html'))); } function testFindFormByLabel() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue( 'getContent', '
    '); $page = &$this->parse($response); $this->assertNull($page->getFormBySubmit(new SimpleByLabel('submit'))); $this->assertNull($page->getFormBySubmit(new SimpleByName('submit'))); $this->assertIsA( $page->getFormBySubmit(new SimpleByLabel('Submit')), 'SimpleForm'); } function testConfirmSubmitAttributesAreCaseSensitive() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue( 'getContent', '
    '); $page = &$this->parse($response); $this->assertIsA( $page->getFormBySubmit(new SimpleByName('S')), 'SimpleForm'); $this->assertIsA( $page->getFormBySubmit(new SimpleByLabel('S')), 'SimpleForm'); } function testFindFormByImage() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '
    ' . '' . '
    '); $page = &$this->parse($response); $this->assertIsA( $page->getFormByImage(new SimpleByLabel('Label')), 'SimpleForm'); $this->assertIsA( $page->getFormByImage(new SimpleByName('me')), 'SimpleForm'); $this->assertIsA( $page->getFormByImage(new SimpleById(100)), 'SimpleForm'); } function testFindFormByButtonTag() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '
    ' . '' . '
    '); $page = &$this->parse($response); $this->assertNull($page->getFormBySubmit(new SimpleByLabel('b'))); $this->assertNull($page->getFormBySubmit(new SimpleByLabel('B'))); $this->assertIsA( $page->getFormBySubmit(new SimpleByName('b')), 'SimpleForm'); $this->assertIsA( $page->getFormBySubmit(new SimpleByLabel('BBB')), 'SimpleForm'); } function testFindFormById() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue( 'getContent', '
    '); $page = &$this->parse($response); $this->assertNull($page->getFormById(54)); $this->assertIsA($page->getFormById(55), 'SimpleForm'); } function testReadingTextField() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '
    ' . '' . '' . '
    '); $page = &$this->parse($response); $this->assertNull($page->getField(new SimpleByName('missing'))); $this->assertIdentical($page->getField(new SimpleByName('a')), ''); $this->assertIdentical($page->getField(new SimpleByName('b')), 'bbb'); } function testReadingTextFieldIsCaseInsensitive() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '
    ' . '' . '' . '
    '); $page = &$this->parse($response); $this->assertNull($page->getField(new SimpleByName('missing'))); $this->assertIdentical($page->getField(new SimpleByName('a')), ''); $this->assertIdentical($page->getField(new SimpleByName('b')), 'bbb'); } function testSettingTextField() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '
    ' . '' . '' . '' . '
    '); $page = &$this->parse($response); $this->assertTrue($page->setField(new SimpleByName('a'), 'aaa')); $this->assertEqual($page->getField(new SimpleByName('a')), 'aaa'); $this->assertTrue($page->setField(new SimpleById(3), 'bbb')); $this->assertEqual($page->getField(new SimpleBYId(3)), 'bbb'); $this->assertFalse($page->setField(new SimpleByName('z'), 'zzz')); $this->assertNull($page->getField(new SimpleByName('z'))); } function testSettingTextFieldByEnclosingLabel() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '
    ' . '' . '
    '); $page = &$this->parse($response); $this->assertEqual($page->getField(new SimpleByName('a')), 'A'); $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'A'); $this->assertTrue($page->setField(new SimpleByLabel('Stuff'), 'aaa')); $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'aaa'); } function testGettingTextFieldByEnclosingLabelWithConflictingOtherFields() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '
    ' . '' . '' . '
    '); $page = &$this->parse($response); $this->assertEqual($page->getField(new SimpleByName('a')), 'A'); $this->assertEqual($page->getField(new SimpleByName('b')), 'B'); $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'A'); } function testSettingTextFieldByExternalLabel() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '
    ' . '' . '' . '
    '); $page = &$this->parse($response); $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'A'); $this->assertTrue($page->setField(new SimpleByLabel('Stuff'), 'aaa')); $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'aaa'); } function testReadingTextArea() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '
    ' . '' . '' . '
    '); $page = &$this->parse($response); $this->assertEqual($page->getField(new SimpleByName('a')), 'aaa'); } function testSettingTextArea() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '
    ' . '' . '' . '
    '); $page = &$this->parse($response); $this->assertTrue($page->setField(new SimpleByName('a'), 'AAA')); $this->assertEqual($page->getField(new SimpleByName('a')), 'AAA'); } function testSettingSelectionField() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '
    ' . '' . '' . '
    '); $page = &$this->parse($response); $this->assertEqual($page->getField(new SimpleByName('a')), 'bbb'); $this->assertFalse($page->setField(new SimpleByName('a'), 'ccc')); $this->assertTrue($page->setField(new SimpleByName('a'), 'aaa')); $this->assertEqual($page->getField(new SimpleByName('a')), 'aaa'); } function testSettingSelectionFieldByEnclosingLabel() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '
    ' . '' . '
    '); $page = &$this->parse($response); $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'A'); $this->assertTrue($page->setField(new SimpleByLabel('Stuff'), 'B')); $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'B'); } function testSettingRadioButtonByEnclosingLabel() { $response = &new MockSimpleHttpResponse(); $response->setReturnValue('getContent', '
    ' . '' . '' . '
    '); $page = &$this->parse($response); $this->assertEqual($page->getField(new SimpleByLabel('A')), 'a'); $this->assertTrue($page->setField(new SimpleBylabel('B'), 'b')); $this->assertEqual($page->getField(new SimpleByLabel('B')), 'b'); } } ?>postfixadmin-2.3.7/tests/simpletest/test/dumper_test.php0000664000175000017620000000636511157271050023646 0ustar davidpalepurpleassertEqual( $dumper->clipString("Hello", 6), "Hello", "Hello, 6->%s"); $this->assertEqual( $dumper->clipString("Hello", 5), "Hello", "Hello, 5->%s"); $this->assertEqual( $dumper->clipString("Hello world", 3), "Hel...", "Hello world, 3->%s"); $this->assertEqual( $dumper->clipString("Hello world", 6, 3), "Hello ...", "Hello world, 6, 3->%s"); $this->assertEqual( $dumper->clipString("Hello world", 3, 6), "...o w...", "Hello world, 3, 6->%s"); $this->assertEqual( $dumper->clipString("Hello world", 4, 11), "...orld", "Hello world, 4, 11->%s"); $this->assertEqual( $dumper->clipString("Hello world", 4, 12), "...orld", "Hello world, 4, 12->%s"); } function testDescribeNull() { $dumper = new SimpleDumper(); $this->assertPattern('/null/i', $dumper->describeValue(null)); } function testDescribeBoolean() { $dumper = new SimpleDumper(); $this->assertPattern('/boolean/i', $dumper->describeValue(true)); $this->assertPattern('/true/i', $dumper->describeValue(true)); $this->assertPattern('/false/i', $dumper->describeValue(false)); } function testDescribeString() { $dumper = new SimpleDumper(); $this->assertPattern('/string/i', $dumper->describeValue('Hello')); $this->assertPattern('/Hello/', $dumper->describeValue('Hello')); } function testDescribeInteger() { $dumper = new SimpleDumper(); $this->assertPattern('/integer/i', $dumper->describeValue(35)); $this->assertPattern('/35/', $dumper->describeValue(35)); } function testDescribeFloat() { $dumper = new SimpleDumper(); $this->assertPattern('/float/i', $dumper->describeValue(0.99)); $this->assertPattern('/0\.99/', $dumper->describeValue(0.99)); } function testDescribeArray() { $dumper = new SimpleDumper(); $this->assertPattern('/array/i', $dumper->describeValue(array(1, 4))); $this->assertPattern('/2/i', $dumper->describeValue(array(1, 4))); } function testDescribeObject() { $dumper = new SimpleDumper(); $this->assertPattern( '/object/i', $dumper->describeValue(new DumperDummy())); $this->assertPattern( '/DumperDummy/i', $dumper->describeValue(new DumperDummy())); } } ?>postfixadmin-2.3.7/tests/simpletest/test/test_groups.php0000664000175000017620000000643111157271050023663 0ustar davidpalepurpleTestSuite('Unit tests'); $path = dirname(__FILE__); $this->addTestFile($path . '/errors_test.php'); if (version_compare(phpversion(), '5') >= 0) { $this->addTestFile($path . '/exceptions_test.php'); } $this->addTestFile($path . '/compatibility_test.php'); $this->addTestFile($path . '/simpletest_test.php'); $this->addTestFile($path . '/dumper_test.php'); $this->addTestFile($path . '/expectation_test.php'); $this->addTestFile($path . '/unit_tester_test.php'); if (version_compare(phpversion(), '5', '>=')) { $this->addTestFile($path . '/reflection_php5_test.php'); } else { $this->addTestFile($path . '/reflection_php4_test.php'); } $this->addTestFile($path . '/mock_objects_test.php'); if (version_compare(phpversion(), '5', '>=')) { $this->addTestFile($path . '/interfaces_test.php'); } $this->addTestFile($path . '/collector_test.php'); $this->addTestFile($path . '/adapter_test.php'); $this->addTestFile($path . '/socket_test.php'); $this->addTestFile($path . '/encoding_test.php'); $this->addTestFile($path . '/url_test.php'); $this->addTestFile($path . '/cookies_test.php'); $this->addTestFile($path . '/http_test.php'); $this->addTestFile($path . '/authentication_test.php'); $this->addTestFile($path . '/user_agent_test.php'); $this->addTestFile($path . '/parser_test.php'); $this->addTestFile($path . '/tag_test.php'); $this->addTestFile($path . '/form_test.php'); $this->addTestFile($path . '/page_test.php'); $this->addTestFile($path . '/frames_test.php'); $this->addTestFile($path . '/browser_test.php'); $this->addTestFile($path . '/web_tester_test.php'); $this->addTestFile($path . '/shell_tester_test.php'); $this->addTestFile($path . '/xml_test.php'); } } // Uncomment and modify the following line if you are accessing // the net via a proxy server. // // SimpleTest::useProxy('http://my-proxy', 'optional username', 'optional password'); class AllTests extends TestSuite { function AllTests() { $this->TestSuite('All tests for SimpleTest ' . SimpleTest::getVersion()); $this->addTestCase(new UnitTests()); $this->addTestFile(dirname(__FILE__) . '/shell_test.php'); $this->addTestFile(dirname(__FILE__) . '/live_test.php'); $this->addTestFile(dirname(__FILE__) . '/acceptance_test.php'); } } ?>postfixadmin-2.3.7/tests/simpletest/test/parser_test.php0000664000175000017620000005673211157271050023651 0ustar davidpalepurpleassertFalse($regex->match("Hello", $match)); $this->assertEqual($match, ""); } function testNoSubject() { $regex = &new ParallelRegex(false); $regex->addPattern(".*"); $this->assertTrue($regex->match("", $match)); $this->assertEqual($match, ""); } function testMatchAll() { $regex = &new ParallelRegex(false); $regex->addPattern(".*"); $this->assertTrue($regex->match("Hello", $match)); $this->assertEqual($match, "Hello"); } function testCaseSensitive() { $regex = &new ParallelRegex(true); $regex->addPattern("abc"); $this->assertTrue($regex->match("abcdef", $match)); $this->assertEqual($match, "abc"); $this->assertTrue($regex->match("AAABCabcdef", $match)); $this->assertEqual($match, "abc"); } function testCaseInsensitive() { $regex = &new ParallelRegex(false); $regex->addPattern("abc"); $this->assertTrue($regex->match("abcdef", $match)); $this->assertEqual($match, "abc"); $this->assertTrue($regex->match("AAABCabcdef", $match)); $this->assertEqual($match, "ABC"); } function testMatchMultiple() { $regex = &new ParallelRegex(true); $regex->addPattern("abc"); $regex->addPattern("ABC"); $this->assertTrue($regex->match("abcdef", $match)); $this->assertEqual($match, "abc"); $this->assertTrue($regex->match("AAABCabcdef", $match)); $this->assertEqual($match, "ABC"); $this->assertFalse($regex->match("Hello", $match)); } function testPatternLabels() { $regex = &new ParallelRegex(false); $regex->addPattern("abc", "letter"); $regex->addPattern("123", "number"); $this->assertIdentical($regex->match("abcdef", $match), "letter"); $this->assertEqual($match, "abc"); $this->assertIdentical($regex->match("0123456789", $match), "number"); $this->assertEqual($match, "123"); } } class TestOfStateStack extends UnitTestCase { function testStartState() { $stack = &new SimpleStateStack("one"); $this->assertEqual($stack->getCurrent(), "one"); } function testExhaustion() { $stack = &new SimpleStateStack("one"); $this->assertFalse($stack->leave()); } function testStateMoves() { $stack = &new SimpleStateStack("one"); $stack->enter("two"); $this->assertEqual($stack->getCurrent(), "two"); $stack->enter("three"); $this->assertEqual($stack->getCurrent(), "three"); $this->assertTrue($stack->leave()); $this->assertEqual($stack->getCurrent(), "two"); $stack->enter("third"); $this->assertEqual($stack->getCurrent(), "third"); $this->assertTrue($stack->leave()); $this->assertTrue($stack->leave()); $this->assertEqual($stack->getCurrent(), "one"); } } class TestParser { function accept() { } function a() { } function b() { } } Mock::generate('TestParser'); class TestOfLexer extends UnitTestCase { function testEmptyPage() { $handler = &new MockTestParser(); $handler->expectNever("accept"); $handler->setReturnValue("accept", true); $handler->expectNever("accept"); $handler->setReturnValue("accept", true); $lexer = &new SimpleLexer($handler); $lexer->addPattern("a+"); $this->assertTrue($lexer->parse("")); } function testSinglePattern() { $handler = &new MockTestParser(); $handler->expectArgumentsAt(0, "accept", array("aaa", LEXER_MATCHED)); $handler->expectArgumentsAt(1, "accept", array("x", LEXER_UNMATCHED)); $handler->expectArgumentsAt(2, "accept", array("a", LEXER_MATCHED)); $handler->expectArgumentsAt(3, "accept", array("yyy", LEXER_UNMATCHED)); $handler->expectArgumentsAt(4, "accept", array("a", LEXER_MATCHED)); $handler->expectArgumentsAt(5, "accept", array("x", LEXER_UNMATCHED)); $handler->expectArgumentsAt(6, "accept", array("aaa", LEXER_MATCHED)); $handler->expectArgumentsAt(7, "accept", array("z", LEXER_UNMATCHED)); $handler->expectCallCount("accept", 8); $handler->setReturnValue("accept", true); $lexer = &new SimpleLexer($handler); $lexer->addPattern("a+"); $this->assertTrue($lexer->parse("aaaxayyyaxaaaz")); } function testMultiplePattern() { $handler = &new MockTestParser(); $target = array("a", "b", "a", "bb", "x", "b", "a", "xxxxxx", "a", "x"); for ($i = 0; $i < count($target); $i++) { $handler->expectArgumentsAt($i, "accept", array($target[$i], '*')); } $handler->expectCallCount("accept", count($target)); $handler->setReturnValue("accept", true); $lexer = &new SimpleLexer($handler); $lexer->addPattern("a+"); $lexer->addPattern("b+"); $this->assertTrue($lexer->parse("ababbxbaxxxxxxax")); } } class TestOfLexerModes extends UnitTestCase { function testIsolatedPattern() { $handler = &new MockTestParser(); $handler->expectArgumentsAt(0, "a", array("a", LEXER_MATCHED)); $handler->expectArgumentsAt(1, "a", array("b", LEXER_UNMATCHED)); $handler->expectArgumentsAt(2, "a", array("aa", LEXER_MATCHED)); $handler->expectArgumentsAt(3, "a", array("bxb", LEXER_UNMATCHED)); $handler->expectArgumentsAt(4, "a", array("aaa", LEXER_MATCHED)); $handler->expectArgumentsAt(5, "a", array("x", LEXER_UNMATCHED)); $handler->expectArgumentsAt(6, "a", array("aaaa", LEXER_MATCHED)); $handler->expectArgumentsAt(7, "a", array("x", LEXER_UNMATCHED)); $handler->expectCallCount("a", 8); $handler->setReturnValue("a", true); $lexer = &new SimpleLexer($handler, "a"); $lexer->addPattern("a+", "a"); $lexer->addPattern("b+", "b"); $this->assertTrue($lexer->parse("abaabxbaaaxaaaax")); } function testModeChange() { $handler = &new MockTestParser(); $handler->expectArgumentsAt(0, "a", array("a", LEXER_MATCHED)); $handler->expectArgumentsAt(1, "a", array("b", LEXER_UNMATCHED)); $handler->expectArgumentsAt(2, "a", array("aa", LEXER_MATCHED)); $handler->expectArgumentsAt(3, "a", array("b", LEXER_UNMATCHED)); $handler->expectArgumentsAt(4, "a", array("aaa", LEXER_MATCHED)); $handler->expectArgumentsAt(0, "b", array(":", LEXER_ENTER)); $handler->expectArgumentsAt(1, "b", array("a", LEXER_UNMATCHED)); $handler->expectArgumentsAt(2, "b", array("b", LEXER_MATCHED)); $handler->expectArgumentsAt(3, "b", array("a", LEXER_UNMATCHED)); $handler->expectArgumentsAt(4, "b", array("bb", LEXER_MATCHED)); $handler->expectArgumentsAt(5, "b", array("a", LEXER_UNMATCHED)); $handler->expectArgumentsAt(6, "b", array("bbb", LEXER_MATCHED)); $handler->expectArgumentsAt(7, "b", array("a", LEXER_UNMATCHED)); $handler->expectCallCount("a", 5); $handler->expectCallCount("b", 8); $handler->setReturnValue("a", true); $handler->setReturnValue("b", true); $lexer = &new SimpleLexer($handler, "a"); $lexer->addPattern("a+", "a"); $lexer->addEntryPattern(":", "a", "b"); $lexer->addPattern("b+", "b"); $this->assertTrue($lexer->parse("abaabaaa:ababbabbba")); } function testNesting() { $handler = &new MockTestParser(); $handler->setReturnValue("a", true); $handler->setReturnValue("b", true); $handler->expectArgumentsAt(0, "a", array("aa", LEXER_MATCHED)); $handler->expectArgumentsAt(1, "a", array("b", LEXER_UNMATCHED)); $handler->expectArgumentsAt(2, "a", array("aa", LEXER_MATCHED)); $handler->expectArgumentsAt(3, "a", array("b", LEXER_UNMATCHED)); $handler->expectArgumentsAt(0, "b", array("(", LEXER_ENTER)); $handler->expectArgumentsAt(1, "b", array("bb", LEXER_MATCHED)); $handler->expectArgumentsAt(2, "b", array("a", LEXER_UNMATCHED)); $handler->expectArgumentsAt(3, "b", array("bb", LEXER_MATCHED)); $handler->expectArgumentsAt(4, "b", array(")", LEXER_EXIT)); $handler->expectArgumentsAt(4, "a", array("aa", LEXER_MATCHED)); $handler->expectArgumentsAt(5, "a", array("b", LEXER_UNMATCHED)); $handler->expectCallCount("a", 6); $handler->expectCallCount("b", 5); $lexer = &new SimpleLexer($handler, "a"); $lexer->addPattern("a+", "a"); $lexer->addEntryPattern("(", "a", "b"); $lexer->addPattern("b+", "b"); $lexer->addExitPattern(")", "b"); $this->assertTrue($lexer->parse("aabaab(bbabb)aab")); } function testSingular() { $handler = &new MockTestParser(); $handler->setReturnValue("a", true); $handler->setReturnValue("b", true); $handler->expectArgumentsAt(0, "a", array("aa", LEXER_MATCHED)); $handler->expectArgumentsAt(1, "a", array("aa", LEXER_MATCHED)); $handler->expectArgumentsAt(2, "a", array("xx", LEXER_UNMATCHED)); $handler->expectArgumentsAt(3, "a", array("xx", LEXER_UNMATCHED)); $handler->expectArgumentsAt(0, "b", array("b", LEXER_SPECIAL)); $handler->expectArgumentsAt(1, "b", array("bbb", LEXER_SPECIAL)); $handler->expectCallCount("a", 4); $handler->expectCallCount("b", 2); $lexer = &new SimpleLexer($handler, "a"); $lexer->addPattern("a+", "a"); $lexer->addSpecialPattern("b+", "a", "b"); $this->assertTrue($lexer->parse("aabaaxxbbbxx")); } function testUnwindTooFar() { $handler = &new MockTestParser(); $handler->setReturnValue("a", true); $handler->expectArgumentsAt(0, "a", array("aa", LEXER_MATCHED)); $handler->expectArgumentsAt(1, "a", array(")", LEXER_EXIT)); $handler->expectCallCount("a", 2); $lexer = &new SimpleLexer($handler, "a"); $lexer->addPattern("a+", "a"); $lexer->addExitPattern(")", "a"); $this->assertFalse($lexer->parse("aa)aa")); } } class TestOfLexerHandlers extends UnitTestCase { function testModeMapping() { $handler = &new MockTestParser(); $handler->setReturnValue("a", true); $handler->expectArgumentsAt(0, "a", array("aa", LEXER_MATCHED)); $handler->expectArgumentsAt(1, "a", array("(", LEXER_ENTER)); $handler->expectArgumentsAt(2, "a", array("bb", LEXER_MATCHED)); $handler->expectArgumentsAt(3, "a", array("a", LEXER_UNMATCHED)); $handler->expectArgumentsAt(4, "a", array("bb", LEXER_MATCHED)); $handler->expectArgumentsAt(5, "a", array(")", LEXER_EXIT)); $handler->expectArgumentsAt(6, "a", array("b", LEXER_UNMATCHED)); $handler->expectCallCount("a", 7); $lexer = &new SimpleLexer($handler, "mode_a"); $lexer->addPattern("a+", "mode_a"); $lexer->addEntryPattern("(", "mode_a", "mode_b"); $lexer->addPattern("b+", "mode_b"); $lexer->addExitPattern(")", "mode_b"); $lexer->mapHandler("mode_a", "a"); $lexer->mapHandler("mode_b", "a"); $this->assertTrue($lexer->parse("aa(bbabb)b")); } } class TestOfSimpleHtmlLexer extends UnitTestCase { function &createParser() { $parser = &new MockSimpleHtmlSaxParser(); $parser->setReturnValue('acceptStartToken', true); $parser->setReturnValue('acceptEndToken', true); $parser->setReturnValue('acceptAttributeToken', true); $parser->setReturnValue('acceptEntityToken', true); $parser->setReturnValue('acceptTextToken', true); $parser->setReturnValue('ignore', true); return $parser; } function testNoContent() { $parser = &$this->createParser(); $parser->expectNever('acceptStartToken'); $parser->expectNever('acceptEndToken'); $parser->expectNever('acceptAttributeToken'); $parser->expectNever('acceptEntityToken'); $parser->expectNever('acceptTextToken'); $lexer = &new SimpleHtmlLexer($parser); $this->assertTrue($lexer->parse('')); } function testUninteresting() { $parser = &$this->createParser(); $parser->expectOnce('acceptTextToken', array('', '*')); $lexer = &new SimpleHtmlLexer($parser); $this->assertTrue($lexer->parse('')); } function testSkipCss() { $parser = &$this->createParser(); $parser->expectNever('acceptTextToken'); $parser->expectAtLeastOnce('ignore'); $lexer = &new SimpleHtmlLexer($parser); $this->assertTrue($lexer->parse("")); } function testSkipJavaScript() { $parser = &$this->createParser(); $parser->expectNever('acceptTextToken'); $parser->expectAtLeastOnce('ignore'); $lexer = &new SimpleHtmlLexer($parser); $this->assertTrue($lexer->parse("")); } function testSkipHtmlComments() { $parser = &$this->createParser(); $parser->expectNever('acceptTextToken'); $parser->expectAtLeastOnce('ignore'); $lexer = &new SimpleHtmlLexer($parser); $this->assertTrue($lexer->parse("")); } function testTagWithNoAttributes() { $parser = &$this->createParser(); $parser->expectAt(0, 'acceptStartToken', array('expectAt(1, 'acceptStartToken', array('>', '*')); $parser->expectCallCount('acceptStartToken', 2); $parser->expectOnce('acceptTextToken', array('Hello', '*')); $parser->expectOnce('acceptEndToken', array('', '*')); $lexer = &new SimpleHtmlLexer($parser); $this->assertTrue($lexer->parse('Hello')); } function testTagWithAttributes() { $parser = &$this->createParser(); $parser->expectOnce('acceptTextToken', array('label', '*')); $parser->expectAt(0, 'acceptStartToken', array('expectAt(1, 'acceptStartToken', array('href', '*')); $parser->expectAt(2, 'acceptStartToken', array('>', '*')); $parser->expectCallCount('acceptStartToken', 3); $parser->expectAt(0, 'acceptAttributeToken', array('= "', '*')); $parser->expectAt(1, 'acceptAttributeToken', array('here.html', '*')); $parser->expectAt(2, 'acceptAttributeToken', array('"', '*')); $parser->expectCallCount('acceptAttributeToken', 3); $parser->expectOnce('acceptEndToken', array('', '*')); $lexer = &new SimpleHtmlLexer($parser); $this->assertTrue($lexer->parse('label')); } } class TestOfHtmlSaxParser extends UnitTestCase { function &createListener() { $listener = &new MockSimpleSaxListener(); $listener->setReturnValue('startElement', true); $listener->setReturnValue('addContent', true); $listener->setReturnValue('endElement', true); return $listener; } function testFramesetTag() { $listener = &$this->createListener(); $listener->expectOnce('startElement', array('frameset', array())); $listener->expectOnce('addContent', array('Frames')); $listener->expectOnce('endElement', array('frameset')); $parser = &new SimpleHtmlSaxParser($listener); $this->assertTrue($parser->parse('Frames')); } function testTagWithUnquotedAttributes() { $listener = &$this->createListener(); $listener->expectOnce( 'startElement', array('input', array('name' => 'a.b.c', 'value' => 'd'))); $parser = &new SimpleHtmlSaxParser($listener); $this->assertTrue($parser->parse('')); } function testTagInsideContent() { $listener = &$this->createListener(); $listener->expectOnce('startElement', array('a', array())); $listener->expectAt(0, 'addContent', array('')); $listener->expectAt(1, 'addContent', array('')); $parser = &new SimpleHtmlSaxParser($listener); $this->assertTrue($parser->parse('')); } function testTagWithInternalContent() { $listener = &$this->createListener(); $listener->expectOnce('startElement', array('a', array())); $listener->expectOnce('addContent', array('label')); $listener->expectOnce('endElement', array('a')); $parser = &new SimpleHtmlSaxParser($listener); $this->assertTrue($parser->parse('label')); } function testLinkAddress() { $listener = &$this->createListener(); $listener->expectOnce('startElement', array('a', array('href' => 'here.html'))); $listener->expectOnce('addContent', array('label')); $listener->expectOnce('endElement', array('a')); $parser = &new SimpleHtmlSaxParser($listener); $this->assertTrue($parser->parse("label")); } function testEncodedAttribute() { $listener = &$this->createListener(); $listener->expectOnce('startElement', array('a', array('href' => 'here&there.html'))); $listener->expectOnce('addContent', array('label')); $listener->expectOnce('endElement', array('a')); $parser = &new SimpleHtmlSaxParser($listener); $this->assertTrue($parser->parse("label")); } function testTagWithId() { $listener = &$this->createListener(); $listener->expectOnce('startElement', array('a', array('id' => '0'))); $listener->expectOnce('addContent', array('label')); $listener->expectOnce('endElement', array('a')); $parser = &new SimpleHtmlSaxParser($listener); $this->assertTrue($parser->parse('label')); } function testTagWithEmptyAttributes() { $listener = &$this->createListener(); $listener->expectOnce( 'startElement', array('option', array('value' => '', 'selected' => ''))); $listener->expectOnce('addContent', array('label')); $listener->expectOnce('endElement', array('option')); $parser = &new SimpleHtmlSaxParser($listener); $this->assertTrue($parser->parse('')); } function testComplexTagWithLotsOfCaseVariations() { $listener = &$this->createListener(); $listener->expectOnce( 'startElement', array('a', array('href' => 'here.html', 'style' => "'cool'"))); $listener->expectOnce('addContent', array('label')); $listener->expectOnce('endElement', array('a')); $parser = &new SimpleHtmlSaxParser($listener); $this->assertTrue($parser->parse('label')); } function testXhtmlSelfClosingTag() { $listener = &$this->createListener(); $listener->expectOnce( 'startElement', array('input', array('type' => 'submit', 'name' => 'N', 'value' => 'V'))); $parser = &new SimpleHtmlSaxParser($listener); $this->assertTrue($parser->parse('')); } function testNestedFrameInFrameset() { $listener = &$this->createListener(); $listener->expectAt(0, 'startElement', array('frameset', array())); $listener->expectAt(1, 'startElement', array('frame', array('src' => 'frame.html'))); $listener->expectCallCount('startElement', 2); $listener->expectOnce('addContent', array('Hello')); $listener->expectOnce('endElement', array('frameset')); $parser = &new SimpleHtmlSaxParser($listener); $this->assertTrue($parser->parse( 'Hello')); } } class TestOfTextExtraction extends UnitTestCase { function testSpaceNormalisation() { $this->assertEqual( SimpleHtmlSaxParser::normalise("\nOne\tTwo \nThree\t"), 'One Two Three'); } function testTagSuppression() { $this->assertEqual( SimpleHtmlSaxParser::normalise('Hello'), 'Hello'); } function testAdjoiningTagSuppression() { $this->assertEqual( SimpleHtmlSaxParser::normalise('HelloGoodbye'), 'HelloGoodbye'); } function testExtractImageAltTextWithDifferentQuotes() { $this->assertEqual( SimpleHtmlSaxParser::normalise('One\'Two\'Three'), 'One Two Three'); } function testExtractImageAltTextMultipleTimes() { $this->assertEqual( SimpleHtmlSaxParser::normalise('OneTwoThree'), 'One Two Three'); } function testHtmlEntityTranslation() { $this->assertEqual( SimpleHtmlSaxParser::normalise('<>"&'), '<>"&'); } } ?>postfixadmin-2.3.7/tests/simpletest/test/acceptance_test.php0000664000175000017620000020145111157271050024431 0ustar davidpalepurpleaddHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); $this->assertTrue($browser->get('http://www.lastcraft.com/test/network_confirm.php')); $this->assertPattern('/target for the SimpleTest/', $browser->getContent()); $this->assertPattern('/Request method.*?
    GET<\/dd>/', $browser->getContent()); $this->assertEqual($browser->getTitle(), 'Simple test target file'); $this->assertEqual($browser->getResponseCode(), 200); $this->assertEqual($browser->getMimeType(), 'text/html'); } function testPost() { $browser = &new SimpleBrowser(); $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); $this->assertTrue($browser->post('http://www.lastcraft.com/test/network_confirm.php')); $this->assertPattern('/target for the SimpleTest/', $browser->getContent()); $this->assertPattern('/Request method.*?
    POST<\/dd>/', $browser->getContent()); } function testAbsoluteLinkFollowing() { $browser = &new SimpleBrowser(); $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); $browser->get('http://www.lastcraft.com/test/link_confirm.php'); $this->assertTrue($browser->clickLink('Absolute')); $this->assertPattern('/target for the SimpleTest/', $browser->getContent()); } function testRelativeLinkFollowing() { $browser = &new SimpleBrowser(); $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); $browser->get('http://www.lastcraft.com/test/link_confirm.php'); $this->assertTrue($browser->clickLink('Relative')); $this->assertPattern('/target for the SimpleTest/', $browser->getContent()); } function testUnifiedClickLinkClicking() { $browser = &new SimpleBrowser(); $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); $browser->get('http://www.lastcraft.com/test/link_confirm.php'); $this->assertTrue($browser->click('Relative')); $this->assertPattern('/target for the SimpleTest/', $browser->getContent()); } function testIdLinkFollowing() { $browser = &new SimpleBrowser(); $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); $browser->get('http://www.lastcraft.com/test/link_confirm.php'); $this->assertTrue($browser->clickLinkById(1)); $this->assertPattern('/target for the SimpleTest/', $browser->getContent()); } function testCookieReading() { $browser = &new SimpleBrowser(); $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); $browser->get('http://www.lastcraft.com/test/set_cookies.php'); $this->assertEqual($browser->getCurrentCookieValue('session_cookie'), 'A'); $this->assertEqual($browser->getCurrentCookieValue('short_cookie'), 'B'); $this->assertEqual($browser->getCurrentCookieValue('day_cookie'), 'C'); } function testSimpleSubmit() { $browser = &new SimpleBrowser(); $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); $browser->get('http://www.lastcraft.com/test/form.html'); $this->assertTrue($browser->clickSubmit('Go!')); $this->assertPattern('/Request method.*?
    POST<\/dd>/', $browser->getContent()); $this->assertPattern('/go=\[Go!\]/', $browser->getContent()); } function testUnifiedClickCanSubmit() { $browser = &new SimpleBrowser(); $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); $browser->get('http://www.lastcraft.com/test/form.html'); $this->assertTrue($browser->click('Go!')); $this->assertPattern('/go=\[Go!\]/', $browser->getContent()); } } class TestOfLiveFetching extends WebTestCase { function setUp() { $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); } function testGet() { $this->assertTrue($this->get('http://www.lastcraft.com/test/network_confirm.php')); $this->assertEqual($this->getUrl(), 'http://www.lastcraft.com/test/network_confirm.php'); $this->assertText('target for the SimpleTest'); $this->assertPattern('/Request method.*?
    GET<\/dd>/'); $this->assertTitle('Simple test target file'); $this->assertTitle(new PatternExpectation('/target file/')); $this->assertResponse(200); $this->assertMime('text/html'); $this->assertHeader('connection', 'close'); $this->assertHeader('connection', new PatternExpectation('/los/')); } function testSlowGet() { $this->assertTrue($this->get('http://www.lastcraft.com/test/slow_page.php')); } function testTimedOutGet() { $this->setConnectionTimeout(1); $this->ignoreErrors(); $this->assertFalse($this->get('http://www.lastcraft.com/test/slow_page.php')); } function testPost() { $this->assertTrue($this->post('http://www.lastcraft.com/test/network_confirm.php')); $this->assertText('target for the SimpleTest'); $this->assertPattern('/Request method.*?
    POST<\/dd>/'); } function testGetWithData() { $this->get('http://www.lastcraft.com/test/network_confirm.php', array("a" => "aaa")); $this->assertPattern('/Request method.*?
    GET<\/dd>/'); $this->assertText('a=[aaa]'); } function testPostWithData() { $this->post('http://www.lastcraft.com/test/network_confirm.php', array("a" => "aaa")); $this->assertPattern('/Request method.*?
    POST<\/dd>/'); $this->assertText('a=[aaa]'); } function testRelativeGet() { $this->get('http://www.lastcraft.com/test/link_confirm.php'); $this->assertTrue($this->get('network_confirm.php')); $this->assertText('target for the SimpleTest'); } function testRelativePost() { $this->post('http://www.lastcraft.com/test/link_confirm.php'); $this->assertTrue($this->post('network_confirm.php')); $this->assertText('target for the SimpleTest'); } function testLinkAssertions() { $this->get('http://www.lastcraft.com/test/link_confirm.php'); $this->assertLink('Absolute', 'http://www.lastcraft.com/test/network_confirm.php'); $this->assertLink('Absolute', new PatternExpectation('/confirm/')); $this->assertClickable('Absolute'); } function testAbsoluteLinkFollowing() { $this->get('http://www.lastcraft.com/test/link_confirm.php'); $this->assertTrue($this->clickLink('Absolute')); $this->assertText('target for the SimpleTest'); } function testRelativeLinkFollowing() { $this->get('http://www.lastcraft.com/test/link_confirm.php'); $this->assertTrue($this->clickLink('Relative')); $this->assertText('target for the SimpleTest'); } function testLinkIdFollowing() { $this->get('http://www.lastcraft.com/test/link_confirm.php'); $this->assertLinkById(1); $this->assertTrue($this->clickLinkById(1)); $this->assertText('target for the SimpleTest'); } function testAbsoluteUrlBehavesAbsolutely() { $this->get('http://www.lastcraft.com/test/link_confirm.php'); $this->get('http://www.lastcraft.com'); $this->assertText('No guarantee of quality is given or even intended'); } } class TestOfLivePageLinkingWithMinimalLinks extends WebTestCase { function setUp() { $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); } function testClickToExplicitelyNamedSelfReturns() { $this->get('http://www.lastcraft.com/test/front_controller_style/a_page.php'); $this->assertEqual($this->getUrl(), 'http://www.lastcraft.com/test/front_controller_style/a_page.php'); $this->assertTitle('Simple test page with links'); $this->assertLink('Self'); $this->clickLink('Self'); $this->assertTitle('Simple test page with links'); } function testClickToMissingPageReturnsToSamePage() { $this->get('http://www.lastcraft.com/test/front_controller_style/a_page.php'); $this->clickLink('No page'); $this->assertTitle('Simple test page with links'); $this->assertText('[action=no_page]'); } function testClickToBareActionReturnsToSamePage() { $this->get('http://www.lastcraft.com/test/front_controller_style/a_page.php'); $this->clickLink('Bare action'); $this->assertTitle('Simple test page with links'); $this->assertText('[action=]'); } function testClickToSingleQuestionMarkReturnsToSamePage() { $this->get('http://www.lastcraft.com/test/front_controller_style/a_page.php'); $this->clickLink('Empty query'); $this->assertTitle('Simple test page with links'); } function testClickToEmptyStringReturnsToSamePage() { $this->get('http://www.lastcraft.com/test/front_controller_style/a_page.php'); $this->clickLink('Empty link'); $this->assertTitle('Simple test page with links'); } function testClickToSingleDotGoesToCurrentDirectory() { $this->get('http://www.lastcraft.com/test/front_controller_style/a_page.php'); $this->clickLink('Current directory'); $this->assertTitle('Simple test front controller'); } function testClickBackADirectoryLevel() { $this->get('http://www.lastcraft.com/test/front_controller_style/'); $this->clickLink('Down one'); $this->assertText('Index of /test'); } } class TestOfLiveFrontControllerEmulation extends WebTestCase { function setUp() { $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); } function testJumpToNamedPage() { $this->get('http://www.lastcraft.com/test/front_controller_style/'); $this->assertText('Simple test front controller'); $this->clickLink('Index'); $this->assertResponse(200); $this->assertText('[action=index]'); } function testJumpToUnnamedPage() { $this->get('http://www.lastcraft.com/test/front_controller_style/'); $this->clickLink('No page'); $this->assertResponse(200); $this->assertText('Simple test front controller'); $this->assertText('[action=no_page]'); } function testJumpToUnnamedPageWithBareParameter() { $this->get('http://www.lastcraft.com/test/front_controller_style/'); $this->clickLink('Bare action'); $this->assertResponse(200); $this->assertText('Simple test front controller'); $this->assertText('[action=]'); } function testJumpToUnnamedPageWithEmptyQuery() { $this->get('http://www.lastcraft.com/test/front_controller_style/'); $this->clickLink('Empty query'); $this->assertResponse(200); $this->assertPattern('/Simple test front controller/'); $this->assertPattern('/raw get data.*?\[\].*?get data/si'); } function testJumpToUnnamedPageWithEmptyLink() { $this->get('http://www.lastcraft.com/test/front_controller_style/'); $this->clickLink('Empty link'); $this->assertResponse(200); $this->assertPattern('/Simple test front controller/'); $this->assertPattern('/raw get data.*?\[\].*?get data/si'); } function testJumpBackADirectoryLevel() { $this->get('http://www.lastcraft.com/test/front_controller_style/'); $this->clickLink('Down one'); $this->assertText('Index of /test'); } function testSubmitToNamedPage() { $this->get('http://www.lastcraft.com/test/front_controller_style/'); $this->assertText('Simple test front controller'); $this->clickSubmit('Index'); $this->assertResponse(200); $this->assertText('[action=Index]'); } function testSubmitToSameDirectory() { $this->get('http://www.lastcraft.com/test/front_controller_style/index.php'); $this->clickSubmit('Same directory'); $this->assertResponse(200); $this->assertText('[action=Same+directory]'); } function testSubmitToEmptyAction() { $this->get('http://www.lastcraft.com/test/front_controller_style/index.php'); $this->clickSubmit('Empty action'); $this->assertResponse(200); $this->assertText('[action=Empty+action]'); } function testSubmitToNoAction() { $this->get('http://www.lastcraft.com/test/front_controller_style/index.php'); $this->clickSubmit('No action'); $this->assertResponse(200); $this->assertText('[action=No+action]'); } function testSubmitBackADirectoryLevel() { $this->get('http://www.lastcraft.com/test/front_controller_style/'); $this->clickSubmit('Down one'); $this->assertText('Index of /test'); } function testSubmitToNamedPageWithMixedPostAndGet() { $this->get('http://www.lastcraft.com/test/front_controller_style/?a=A'); $this->assertText('Simple test front controller'); $this->clickSubmit('Index post'); $this->assertText('action=[Index post]'); $this->assertNoText('[a=A]'); } function testSubmitToSameDirectoryMixedPostAndGet() { $this->get('http://www.lastcraft.com/test/front_controller_style/index.php?a=A'); $this->clickSubmit('Same directory post'); $this->assertText('action=[Same directory post]'); $this->assertNoText('[a=A]'); } function testSubmitToEmptyActionMixedPostAndGet() { $this->get('http://www.lastcraft.com/test/front_controller_style/index.php?a=A'); $this->clickSubmit('Empty action post'); $this->assertText('action=[Empty action post]'); $this->assertText('[a=A]'); } function testSubmitToNoActionMixedPostAndGet() { $this->get('http://www.lastcraft.com/test/front_controller_style/index.php?a=A'); $this->clickSubmit('No action post'); $this->assertText('action=[No action post]'); $this->assertText('[a=A]'); } } class TestOfLiveHeaders extends WebTestCase { function setUp() { $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); } function testConfirmingHeaderExistence() { $this->get('http://www.lastcraft.com/'); $this->assertHeader('content-type'); $this->assertHeader('content-type', 'text/html'); $this->assertHeaderPattern('content-type', '/HTML/i'); $this->assertNoHeader('WWW-Authenticate'); } } class TestOfLiveRedirects extends WebTestCase { function setUp() { $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); } function testNoRedirects() { $this->setMaximumRedirects(0); $this->get('http://www.lastcraft.com/test/redirect.php'); $this->assertTitle('Redirection test'); } function testRedirects() { $this->setMaximumRedirects(1); $this->get('http://www.lastcraft.com/test/redirect.php'); $this->assertTitle('Simple test target file'); } function testRedirectLosesGetData() { $this->get('http://www.lastcraft.com/test/redirect.php', array('a' => 'aaa')); $this->assertNoText('a=[aaa]'); } function testRedirectKeepsExtraRequestDataOfItsOwn() { $this->get('http://www.lastcraft.com/test/redirect.php'); $this->assertText('r=[rrr]'); } function testRedirectLosesPostData() { $this->post('http://www.lastcraft.com/test/redirect.php', array('a' => 'aaa')); $this->assertTitle('Simple test target file'); $this->assertNoText('a=[aaa]'); } function testRedirectWithBaseUrlChange() { $this->get('http://www.lastcraft.com/test/base_change_redirect.php'); $this->assertTitle('Simple test target file in folder'); $this->get('http://www.lastcraft.com/test/path/base_change_redirect.php'); $this->assertTitle('Simple test target file'); } function testRedirectWithDoubleBaseUrlChange() { $this->get('http://www.lastcraft.com/test/double_base_change_redirect.php'); $this->assertTitle('Simple test target file'); } } class TestOfLiveCookies extends WebTestCase { function setUp() { $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); } function testCookieSettingAndAssertions() { $this->setCookie('a', 'Test cookie a'); $this->setCookie('b', 'Test cookie b', 'www.lastcraft.com'); $this->setCookie('c', 'Test cookie c', 'www.lastcraft.com', 'test'); $this->get('http://www.lastcraft.com/test/network_confirm.php'); $this->assertText('Test cookie a'); $this->assertText('Test cookie b'); $this->assertText('Test cookie c'); $this->assertCookie('a'); $this->assertCookie('b', 'Test cookie b'); $this->assertTrue($this->getCookie('c') == 'Test cookie c'); } function testNoCookieSetWhenCookiesDisabled() { $this->setCookie('a', 'Test cookie a'); $this->ignoreCookies(); $this->get('http://www.lastcraft.com/test/network_confirm.php'); $this->assertNoText('Test cookie a'); } function testCookieReading() { $this->get('http://www.lastcraft.com/test/set_cookies.php'); $this->assertCookie('session_cookie', 'A'); $this->assertCookie('short_cookie', 'B'); $this->assertCookie('day_cookie', 'C'); } function testNoCookieReadingWhenCookiesDisabled() { $this->ignoreCookies(); $this->get('http://www.lastcraft.com/test/set_cookies.php'); $this->assertNoCookie('session_cookie'); $this->assertNoCookie('short_cookie'); $this->assertNoCookie('day_cookie'); } function testCookiePatternAssertions() { $this->get('http://www.lastcraft.com/test/set_cookies.php'); $this->assertCookie('session_cookie', new PatternExpectation('/a/i')); } function testTemporaryCookieExpiry() { $this->get('http://www.lastcraft.com/test/set_cookies.php'); $this->restart(); $this->assertNoCookie('session_cookie'); $this->assertCookie('day_cookie', 'C'); } function testTimedCookieExpiryWith100SecondMargin() { $this->get('http://www.lastcraft.com/test/set_cookies.php'); $this->ageCookies(3600); $this->restart(time() + 100); $this->assertNoCookie('session_cookie'); $this->assertNoCookie('hour_cookie'); $this->assertCookie('day_cookie', 'C'); } function testNoClockOverDriftBy100Seconds() { $this->get('http://www.lastcraft.com/test/set_cookies.php'); $this->restart(time() + 200); $this->assertNoCookie( 'short_cookie', '%s -> Please check your computer clock setting if you are not using NTP'); } function testNoClockUnderDriftBy100Seconds() { $this->get('http://www.lastcraft.com/test/set_cookies.php'); $this->restart(time() + 0); $this->assertCookie( 'short_cookie', 'B', '%s -> Please check your computer clock setting if you are not using NTP'); } function testCookiePath() { $this->get('http://www.lastcraft.com/test/set_cookies.php'); $this->assertNoCookie('path_cookie', 'D'); $this->get('./path/show_cookies.php'); $this->assertPattern('/path_cookie/'); $this->assertCookie('path_cookie', 'D'); } } class TestOfLiveForms extends WebTestCase { function setUp() { $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); } function testSimpleSubmit() { $this->get('http://www.lastcraft.com/test/form.html'); $this->assertTrue($this->clickSubmit('Go!')); $this->assertPattern('/Request method.*?
    POST<\/dd>/'); $this->assertText('go=[Go!]'); } function testDefaultFormValues() { $this->get('http://www.lastcraft.com/test/form.html'); $this->assertFieldByName('a', ''); $this->assertFieldByName('b', 'Default text'); $this->assertFieldByName('c', ''); $this->assertFieldByName('d', 'd1'); $this->assertFieldByName('e', false); $this->assertFieldByName('f', 'on'); $this->assertFieldByName('g', 'g3'); $this->assertFieldByName('h', 2); $this->assertFieldByName('go', 'Go!'); $this->assertClickable('Go!'); $this->assertSubmit('Go!'); $this->assertTrue($this->clickSubmit('Go!')); $this->assertText('go=[Go!]'); $this->assertText('a=[]'); $this->assertText('b=[Default text]'); $this->assertText('c=[]'); $this->assertText('d=[d1]'); $this->assertNoText('e=['); $this->assertText('f=[on]'); $this->assertText('g=[g3]'); } function testFormSubmissionByButtonLabel() { $this->get('http://www.lastcraft.com/test/form.html'); $this->setFieldByName('a', 'aaa'); $this->setFieldByName('b', 'bbb'); $this->setFieldByName('c', 'ccc'); $this->setFieldByName('d', 'D2'); $this->setFieldByName('e', 'on'); $this->setFieldByName('f', false); $this->setFieldByName('g', 'g2'); $this->setFieldByName('h', 1); $this->assertTrue($this->clickSubmit('Go!')); $this->assertText('a=[aaa]'); $this->assertText('b=[bbb]'); $this->assertText('c=[ccc]'); $this->assertText('d=[d2]'); $this->assertText('e=[on]'); $this->assertNoText('f=['); $this->assertText('g=[g2]'); } function testAdditionalFormValues() { $this->get('http://www.lastcraft.com/test/form.html'); $this->assertTrue($this->clickSubmit('Go!', array('add' => 'A'))); $this->assertText('go=[Go!]'); $this->assertText('add=[A]'); } function testFormSubmissionByName() { $this->get('http://www.lastcraft.com/test/form.html'); $this->setFieldByName('a', 'A'); $this->assertTrue($this->clickSubmitByName('go')); $this->assertText('a=[A]'); } function testFormSubmissionByNameAndAdditionalParameters() { $this->get('http://www.lastcraft.com/test/form.html'); $this->assertTrue($this->clickSubmitByName('go', array('add' => 'A'))); $this->assertText('go=[Go!]'); $this->assertText('add=[A]'); } function testFormSubmissionBySubmitButtonLabeledSubmit() { $this->get('http://www.lastcraft.com/test/form.html'); $this->assertTrue($this->clickSubmitByName('test')); $this->assertText('test=[Submit]'); } function testFormSubmissionWithIds() { $this->get('http://www.lastcraft.com/test/form.html'); $this->assertFieldById(1, ''); $this->assertFieldById(2, 'Default text'); $this->assertFieldById(3, ''); $this->assertFieldById(4, 'd1'); $this->assertFieldById(5, false); $this->assertFieldById(6, 'on'); $this->assertFieldById(8, 'g3'); $this->assertFieldById(11, 2); $this->setFieldById(1, 'aaa'); $this->setFieldById(2, 'bbb'); $this->setFieldById(3, 'ccc'); $this->setFieldById(4, 'D2'); $this->setFieldById(5, 'on'); $this->setFieldById(6, false); $this->setFieldById(8, 'g2'); $this->setFieldById(11, 'H1'); $this->assertTrue($this->clickSubmitById(99)); $this->assertText('a=[aaa]'); $this->assertText('b=[bbb]'); $this->assertText('c=[ccc]'); $this->assertText('d=[d2]'); $this->assertText('e=[on]'); $this->assertNoText('f=['); $this->assertText('g=[g2]'); $this->assertText('h=[1]'); $this->assertText('go=[Go!]'); } function testFormSubmissionWithLabels() { $this->get('http://www.lastcraft.com/test/form.html'); $this->assertField('Text A', ''); $this->assertField('Text B', 'Default text'); $this->assertField('Text area C', ''); $this->assertField('Selection D', 'd1'); $this->assertField('Checkbox E', false); $this->assertField('Checkbox F', 'on'); $this->assertField('3', 'g3'); $this->assertField('Selection H', 2); $this->setField('Text A', 'aaa'); $this->setField('Text B', 'bbb'); $this->setField('Text area C', 'ccc'); $this->setField('Selection D', 'D2'); $this->setField('Checkbox E', 'on'); $this->setField('Checkbox F', false); $this->setField('2', 'g2'); $this->setField('Selection H', 'H1'); $this->clickSubmit('Go!'); $this->assertText('a=[aaa]'); $this->assertText('b=[bbb]'); $this->assertText('c=[ccc]'); $this->assertText('d=[d2]'); $this->assertText('e=[on]'); $this->assertNoText('f=['); $this->assertText('g=[g2]'); $this->assertText('h=[1]'); $this->assertText('go=[Go!]'); } function testSettingCheckboxWithBooleanTrueSetsUnderlyingValue() { $this->get('http://www.lastcraft.com/test/form.html'); $this->setField('Checkbox E', true); $this->assertField('Checkbox E', 'on'); $this->clickSubmit('Go!'); $this->assertText('e=[on]'); } function testFormSubmissionWithMixedPostAndGet() { $this->get('http://www.lastcraft.com/test/form_with_mixed_post_and_get.html'); $this->setField('Text A', 'Hello'); $this->assertTrue($this->clickSubmit('Go!')); $this->assertText('a=[Hello]'); $this->assertText('x=[X]'); $this->assertText('y=[Y]'); } function testFormSubmissionWithMixedPostAndEncodedGet() { $this->get('http://www.lastcraft.com/test/form_with_mixed_post_and_get.html'); $this->setField('Text B', 'Hello'); $this->assertTrue($this->clickSubmit('Go encoded!')); $this->assertText('b=[Hello]'); $this->assertText('x=[X]'); $this->assertText('y=[Y]'); } function testFormSubmissionWithoutAction() { $this->get('http://www.lastcraft.com/test/form_without_action.php?test=test'); $this->assertText('_GET : [test]'); $this->assertTrue($this->clickSubmit('Submit Post With Empty Action')); $this->assertText('_GET : [test]'); $this->assertText('_POST : [test]'); } function testImageSubmissionByLabel() { $this->get('http://www.lastcraft.com/test/form.html'); $this->assertImage('Image go!'); $this->assertTrue($this->clickImage('Image go!', 10, 12)); $this->assertText('go_x=[10]'); $this->assertText('go_y=[12]'); } function testImageSubmissionByLabelWithAdditionalParameters() { $this->get('http://www.lastcraft.com/test/form.html'); $this->assertTrue($this->clickImage('Image go!', 10, 12, array('add' => 'A'))); $this->assertText('add=[A]'); } function testImageSubmissionByName() { $this->get('http://www.lastcraft.com/test/form.html'); $this->assertTrue($this->clickImageByName('go', 10, 12)); $this->assertText('go_x=[10]'); $this->assertText('go_y=[12]'); } function testImageSubmissionById() { $this->get('http://www.lastcraft.com/test/form.html'); $this->assertTrue($this->clickImageById(97, 10, 12)); $this->assertText('go_x=[10]'); $this->assertText('go_y=[12]'); } function testButtonSubmissionByLabel() { $this->get('http://www.lastcraft.com/test/form.html'); $this->assertTrue($this->clickSubmit('Button go!', 10, 12)); $this->assertPattern('/go=\[ButtonGo\]/s'); } function testNamelessSubmitSendsNoValue() { $this->get('http://www.lastcraft.com/test/form_with_unnamed_submit.html'); $this->click('Go!'); $this->assertNoText('Go!'); $this->assertNoText('submit'); } function testNamelessImageSendsXAndYValues() { $this->get('http://www.lastcraft.com/test/form_with_unnamed_submit.html'); $this->clickImage('Image go!', 4, 5); $this->assertNoText('ImageGo'); $this->assertText('x=[4]'); $this->assertText('y=[5]'); } function testNamelessButtonSendsNoValue() { $this->get('http://www.lastcraft.com/test/form_with_unnamed_submit.html'); $this->click('Button Go!'); $this->assertNoText('ButtonGo'); } function testSelfSubmit() { $this->get('http://www.lastcraft.com/test/self_form.php'); $this->assertNoText('[Submitted]'); $this->assertNoText('[Wrong form]'); $this->assertTrue($this->clickSubmit()); $this->assertText('[Submitted]'); $this->assertNoText('[Wrong form]'); $this->assertTitle('Test of form self submission'); } function testSelfSubmitWithParameters() { $this->get('http://www.lastcraft.com/test/self_form.php'); $this->setFieldByName('visible', 'Resent'); $this->assertTrue($this->clickSubmit()); $this->assertText('[Resent]'); } function testSettingOfBlankOption() { $this->get('http://www.lastcraft.com/test/form.html'); $this->assertTrue($this->setFieldByName('d', '')); $this->clickSubmit('Go!'); $this->assertText('d=[]'); } function testAssertingFieldValueWithPattern() { $this->get('http://www.lastcraft.com/test/form.html'); $this->setField('c', 'A very long string'); $this->assertField('c', new PatternExpectation('/very long/')); } function testSendingMultipartFormDataEncodedForm() { $this->get('http://www.lastcraft.com/test/form_data_encoded_form.html'); $this->assertField('Text A', ''); $this->assertField('Text B', 'Default text'); $this->assertField('Text area C', ''); $this->assertField('Selection D', 'd1'); $this->assertField('Checkbox E', false); $this->assertField('Checkbox F', 'on'); $this->assertField('3', 'g3'); $this->assertField('Selection H', 2); $this->setField('Text A', 'aaa'); $this->setField('Text B', 'bbb'); $this->setField('Text area C', 'ccc'); $this->setField('Selection D', 'D2'); $this->setField('Checkbox E', 'on'); $this->setField('Checkbox F', false); $this->setField('2', 'g2'); $this->setField('Selection H', 'H1'); $this->assertTrue($this->clickSubmit('Go!')); $this->assertText('a=[aaa]'); $this->assertText('b=[bbb]'); $this->assertText('c=[ccc]'); $this->assertText('d=[d2]'); $this->assertText('e=[on]'); $this->assertNoText('f=['); $this->assertText('g=[g2]'); $this->assertText('h=[1]'); $this->assertText('go=[Go!]'); } function testSettingVariousBlanksInFields() { $this->get('http://www.lastcraft.com/test/form_with_false_defaults.html'); $this->assertField('Text A', ''); $this->setField('Text A', '0'); $this->assertField('Text A', '0'); $this->assertField('Text area B', ''); $this->setField('Text area B', '0'); $this->assertField('Text area B', '0'); $this->assertField('Text area C', " "); $this->assertField('Selection D', ''); $this->setField('Selection D', 'D2'); $this->assertField('Selection D', 'D2'); $this->setField('Selection D', 'D3'); $this->assertField('Selection D', '0'); $this->setField('Selection D', 'D4'); $this->assertField('Selection D', '?'); $this->assertField('Checkbox E', ''); $this->assertField('Checkbox F', 'on'); $this->assertField('Checkbox G', '0'); $this->assertField('Checkbox H', '?'); $this->assertFieldByName('i', 'on'); $this->setFieldByName('i', ''); $this->assertFieldByName('i', ''); $this->setFieldByName('i', '0'); $this->assertFieldByName('i', '0'); $this->setFieldByName('i', '?'); $this->assertFieldByName('i', '?'); } function testSubmissionOfBlankFields() { $this->get('http://www.lastcraft.com/test/form_with_false_defaults.html'); $this->setField('Text A', ''); $this->setField('Text area B', ''); $this->setFieldByName('i', ''); $this->click('Go!'); $this->assertText('a=[]'); $this->assertText('b=[]'); $this->assertPattern('/c=\[ \]/'); $this->assertText('d=[]'); $this->assertText('e=[]'); $this->assertText('i=[]'); } function testSubmissionOfEmptyValues() { $this->get('http://www.lastcraft.com/test/form_with_false_defaults.html'); $this->setField('Selection D', 'D2'); $this->click('Go!'); $this->assertText('a=[]'); $this->assertText('b=[]'); $this->assertText('d=[D2]'); $this->assertText('f=[on]'); $this->assertText('i=[on]'); } function testSubmissionOfZeroes() { $this->get('http://www.lastcraft.com/test/form_with_false_defaults.html'); $this->setField('Text A', '0'); $this->setField('Text area B', '0'); $this->setField('Selection D', 'D3'); $this->setFieldByName('i', '0'); $this->click('Go!'); $this->assertText('a=[0]'); $this->assertText('b=[0]'); $this->assertText('d=[0]'); $this->assertText('g=[0]'); $this->assertText('i=[0]'); } function testSubmissionOfQuestionMarks() { $this->get('http://www.lastcraft.com/test/form_with_false_defaults.html'); $this->setField('Text A', '?'); $this->setField('Text area B', '?'); $this->setField('Selection D', 'D4'); $this->setFieldByName('i', '?'); $this->click('Go!'); $this->assertText('a=[?]'); $this->assertText('b=[?]'); $this->assertText('d=[?]'); $this->assertText('h=[?]'); $this->assertText('i=[?]'); } function testSubmissionOfHtmlEncodedValues() { $this->get('http://www.lastcraft.com/test/form_with_tricky_defaults.html'); $this->assertField('Text A', '&\'"<>'); $this->assertField('Text B', '"'); $this->assertField('Text area C', '&\'"<>'); $this->assertField('Selection D', "'"); $this->assertField('Checkbox E', '&\'"<>'); $this->assertField('Checkbox F', false); $this->assertFieldByname('i', "'"); $this->click('Go!'); $this->assertText('a=[&\'"<>, "]'); $this->assertText('c=[&\'"<>]'); $this->assertText("d=[']"); $this->assertText('e=[&\'"<>]'); $this->assertText("i=[']"); } } class TestOfLiveMultiValueWidgets extends WebTestCase { function setUp() { $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); } function testDefaultFormValueSubmission() { $this->get('http://www.lastcraft.com/test/multiple_widget_form.html'); $this->assertFieldByName('a', array('a2', 'a3')); $this->assertFieldByName('b', array('b2', 'b3')); $this->assertFieldByName('c[]', array('c2', 'c3')); $this->assertFieldByName('d', array('2', '3')); $this->assertFieldByName('e', array('2', '3')); $this->assertTrue($this->clickSubmit('Go!')); $this->assertText('a=[a2, a3]'); $this->assertText('b=[b2, b3]'); $this->assertText('c=[c2, c3]'); $this->assertText('d=[2, 3]'); $this->assertText('e=[2, 3]'); } function testSubmittingMultipleValues() { $this->get('http://www.lastcraft.com/test/multiple_widget_form.html'); $this->setFieldByName('a', array('a1', 'a4')); $this->assertFieldByName('a', array('a1', 'a4')); $this->assertFieldByName('a', array('a4', 'a1')); $this->setFieldByName('b', array('b1', 'b4')); $this->assertFieldByName('b', array('b1', 'b4')); $this->setFieldByName('c[]', array('c1', 'c4')); $this->assertField('c[]', array('c1', 'c4')); $this->setFieldByName('d', array('1', '4')); $this->assertField('d', array('1', '4')); $this->setFieldByName('e', array('e1', 'e4')); $this->assertField('e', array('1', '4')); $this->assertTrue($this->clickSubmit('Go!')); $this->assertText('a=[a1, a4]'); $this->assertText('b=[b1, b4]'); $this->assertText('c=[c1, c4]'); $this->assertText('d=[1, 4]'); $this->assertText('e=[1, 4]'); } function testSettingByOptionValue() { $this->get('http://www.lastcraft.com/test/multiple_widget_form.html'); $this->setFieldByName('d', array('1', '4')); $this->assertField('d', array('1', '4')); $this->assertTrue($this->clickSubmit('Go!')); $this->assertText('d=[1, 4]'); } function testSubmittingMultipleValuesByLabel() { $this->get('http://www.lastcraft.com/test/multiple_widget_form.html'); $this->setField('Multiple selection A', array('a1', 'a4')); $this->assertField('Multiple selection A', array('a1', 'a4')); $this->assertField('Multiple selection A', array('a4', 'a1')); $this->setField('multiple selection C', array('c1', 'c4')); $this->assertField('multiple selection C', array('c1', 'c4')); $this->assertTrue($this->clickSubmit('Go!')); $this->assertText('a=[a1, a4]'); $this->assertText('c=[c1, c4]'); } function testSavantStyleHiddenFieldDefaults() { $this->get('http://www.lastcraft.com/test/savant_style_form.html'); $this->assertFieldByName('a', array('a0')); $this->assertFieldByName('b', array('b0')); $this->assertTrue($this->clickSubmit('Go!')); $this->assertText('a=[a0]'); $this->assertText('b=[b0]'); } function testSavantStyleHiddenDefaultsAreOverridden() { $this->get('http://www.lastcraft.com/test/savant_style_form.html'); $this->assertTrue($this->setFieldByName('a', array('a1'))); $this->assertTrue($this->setFieldByName('b', 'b1')); $this->assertTrue($this->clickSubmit('Go!')); $this->assertText('a=[a1]'); $this->assertText('b=[b1]'); } function testSavantStyleFormSettingById() { $this->get('http://www.lastcraft.com/test/savant_style_form.html'); $this->assertFieldById(1, array('a0')); $this->assertFieldById(4, array('b0')); $this->assertTrue($this->setFieldById(2, 'a1')); $this->assertTrue($this->setFieldById(5, 'b1')); $this->assertTrue($this->clickSubmitById(99)); $this->assertText('a=[a1]'); $this->assertText('b=[b1]'); } } class TestOfFileUploads extends WebTestCase { function setUp() { $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); } function testSingleFileUpload() { $this->get('http://www.lastcraft.com/test/upload_form.html'); $this->assertTrue($this->setField('Content:', dirname(__FILE__) . '/support/upload_sample.txt')); $this->assertField('Content:', dirname(__FILE__) . '/support/upload_sample.txt'); $this->click('Go!'); $this->assertText('Sample for testing file upload'); } function testMultipleFileUpload() { $this->get('http://www.lastcraft.com/test/upload_form.html'); $this->assertTrue($this->setField('Content:', dirname(__FILE__) . '/support/upload_sample.txt')); $this->assertTrue($this->setField('Supplemental:', dirname(__FILE__) . '/support/supplementary_upload_sample.txt')); $this->assertField('Supplemental:', dirname(__FILE__) . '/support/supplementary_upload_sample.txt'); $this->click('Go!'); $this->assertText('Sample for testing file upload'); $this->assertText('Some more text content'); } function testBinaryFileUpload() { $this->get('http://www.lastcraft.com/test/upload_form.html'); $this->assertTrue($this->setField('Content:', dirname(__FILE__) . '/support/latin1_sample')); $this->click('Go!'); $this->assertText( implode('', file(dirname(__FILE__) . '/support/latin1_sample'))); } } class TestOfLiveHistoryNavigation extends WebTestCase { function setUp() { $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); } function testRetry() { $this->get('http://www.lastcraft.com/test/cookie_based_counter.php'); $this->assertPattern('/count: 1/i'); $this->retry(); $this->assertPattern('/count: 2/i'); $this->retry(); $this->assertPattern('/count: 3/i'); } function testOfBackButton() { $this->get('http://www.lastcraft.com/test/1.html'); $this->clickLink('2'); $this->assertTitle('2'); $this->assertTrue($this->back()); $this->assertTitle('1'); $this->assertTrue($this->forward()); $this->assertTitle('2'); $this->assertFalse($this->forward()); } function testGetRetryResubmitsData() { $this->assertTrue($this->get( 'http://www.lastcraft.com/test/network_confirm.php?a=aaa')); $this->assertPattern('/Request method.*?
    GET<\/dd>/'); $this->assertText('a=[aaa]'); $this->retry(); $this->assertPattern('/Request method.*?
    GET<\/dd>/'); $this->assertText('a=[aaa]'); } function testGetRetryResubmitsExtraData() { $this->assertTrue($this->get( 'http://www.lastcraft.com/test/network_confirm.php', array('a' => 'aaa'))); $this->assertPattern('/Request method.*?
    GET<\/dd>/'); $this->assertText('a=[aaa]'); $this->retry(); $this->assertPattern('/Request method.*?
    GET<\/dd>/'); $this->assertText('a=[aaa]'); } function testPostRetryResubmitsData() { $this->assertTrue($this->post( 'http://www.lastcraft.com/test/network_confirm.php', array('a' => 'aaa'))); $this->assertPattern('/Request method.*?
    POST<\/dd>/'); $this->assertText('a=[aaa]'); $this->retry(); $this->assertPattern('/Request method.*?
    POST<\/dd>/'); $this->assertText('a=[aaa]'); } function testGetRetryResubmitsRepeatedData() { $this->assertTrue($this->get( 'http://www.lastcraft.com/test/network_confirm.php?a=1&a=2')); $this->assertPattern('/Request method.*?
    GET<\/dd>/'); $this->assertText('a=[1, 2]'); $this->retry(); $this->assertPattern('/Request method.*?
    GET<\/dd>/'); $this->assertText('a=[1, 2]'); } } class TestOfLiveAuthentication extends WebTestCase { function setUp() { $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); } function testChallengeFromProtectedPage() { $this->get('http://www.lastcraft.com/test/protected/'); $this->assertResponse(401); $this->assertAuthentication('Basic'); $this->assertRealm('SimpleTest basic authentication'); $this->assertRealm(new PatternExpectation('/simpletest/i')); $this->authenticate('test', 'secret'); $this->assertResponse(200); $this->retry(); $this->assertResponse(200); } function testTrailingSlashImpliedWithinRealm() { $this->get('http://www.lastcraft.com/test/protected/'); $this->authenticate('test', 'secret'); $this->assertResponse(200); $this->get('http://www.lastcraft.com/test/protected'); $this->assertResponse(200); } function testTrailingSlashImpliedSettingRealm() { $this->get('http://www.lastcraft.com/test/protected'); $this->authenticate('test', 'secret'); $this->assertResponse(200); $this->get('http://www.lastcraft.com/test/protected/'); $this->assertResponse(200); } function testEncodedAuthenticationFetchesPage() { $this->get('http://test:secret@www.lastcraft.com/test/protected/'); $this->assertResponse(200); } function testEncodedAuthenticationFetchesPageAfterTrailingSlashRedirect() { $this->get('http://test:secret@www.lastcraft.com/test/protected'); $this->assertResponse(200); } function testRealmExtendsToWholeDirectory() { $this->get('http://www.lastcraft.com/test/protected/1.html'); $this->authenticate('test', 'secret'); $this->clickLink('2'); $this->assertResponse(200); $this->clickLink('3'); $this->assertResponse(200); } function testRedirectKeepsAuthentication() { $this->get('http://www.lastcraft.com/test/protected/local_redirect.php'); $this->authenticate('test', 'secret'); $this->assertTitle('Simple test target file'); } function testRedirectKeepsEncodedAuthentication() { $this->get('http://test:secret@www.lastcraft.com/test/protected/local_redirect.php'); $this->assertResponse(200); $this->assertTitle('Simple test target file'); } function testSessionRestartLosesAuthentication() { $this->get('http://www.lastcraft.com/test/protected/'); $this->authenticate('test', 'secret'); $this->assertResponse(200); $this->restart(); $this->get('http://www.lastcraft.com/test/protected/'); $this->assertResponse(401); } } class TestOfLoadingFrames extends WebTestCase { function setUp() { $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); } function testNoFramesContentWhenFramesDisabled() { $this->ignoreFrames(); $this->get('http://www.lastcraft.com/test/one_page_frameset.html'); $this->assertTitle('Frameset for testing of SimpleTest'); $this->assertText('This content is for no frames only'); } function testPatternMatchCanReadTheOnlyFrame() { $this->get('http://www.lastcraft.com/test/one_page_frameset.html'); $this->assertText('A target for the SimpleTest test suite'); $this->assertNoText('This content is for no frames only'); } function testMessyFramesetResponsesByName() { $this->assertTrue($this->get( 'http://www.lastcraft.com/test/messy_frameset.html')); $this->assertTitle('Frameset for testing of SimpleTest'); $this->assertTrue($this->setFrameFocus('Front controller')); $this->assertResponse(200); $this->assertText('Simple test front controller'); $this->assertTrue($this->setFrameFocus('One')); $this->assertResponse(200); $this->assertLink('2'); $this->assertTrue($this->setFrameFocus('Frame links')); $this->assertResponse(200); $this->assertLink('Set one to 2'); $this->assertTrue($this->setFrameFocus('Counter')); $this->assertResponse(200); $this->assertText('Count: 1'); $this->assertTrue($this->setFrameFocus('Redirected')); $this->assertResponse(200); $this->assertText('r=rrr'); $this->assertTrue($this->setFrameFocus('Protected')); $this->assertResponse(401); $this->assertTrue($this->setFrameFocus('Protected redirect')); $this->assertResponse(401); $this->assertTrue($this->setFrameFocusByIndex(1)); $this->assertResponse(200); $this->assertText('Simple test front controller'); $this->assertTrue($this->setFrameFocusByIndex(2)); $this->assertResponse(200); $this->assertLink('2'); $this->assertTrue($this->setFrameFocusByIndex(3)); $this->assertResponse(200); $this->assertLink('Set one to 2'); $this->assertTrue($this->setFrameFocusByIndex(4)); $this->assertResponse(200); $this->assertText('Count: 1'); $this->assertTrue($this->setFrameFocusByIndex(5)); $this->assertResponse(200); $this->assertText('r=rrr'); $this->assertTrue($this->setFrameFocusByIndex(6)); $this->assertResponse(401); $this->assertTrue($this->setFrameFocusByIndex(7)); } function testReloadingFramesetPage() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->assertText('Count: 1'); $this->retry(); $this->assertText('Count: 2'); $this->retry(); $this->assertText('Count: 3'); } function testReloadingSingleFrameWithCookieCounter() { $this->get('http://www.lastcraft.com/test/counting_frameset.html'); $this->setFrameFocus('a'); $this->assertText('Count: 1'); $this->setFrameFocus('b'); $this->assertText('Count: 2'); $this->setFrameFocus('a'); $this->retry(); $this->assertText('Count: 3'); $this->retry(); $this->assertText('Count: 4'); $this->setFrameFocus('b'); $this->assertText('Count: 2'); } function testReloadingFrameWhenUnfocusedReloadsWholeFrameset() { $this->get('http://www.lastcraft.com/test/counting_frameset.html'); $this->setFrameFocus('a'); $this->assertText('Count: 1'); $this->setFrameFocus('b'); $this->assertText('Count: 2'); $this->clearFrameFocus('a'); $this->retry(); $this->assertTitle('Frameset for testing of SimpleTest'); $this->setFrameFocus('a'); $this->assertText('Count: 3'); $this->setFrameFocus('b'); $this->assertText('Count: 4'); } function testClickingNormalLinkReplacesJustThatFrame() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->clickLink('2'); $this->assertLink('3'); $this->assertText('Simple test front controller'); } function testJumpToNamedPageReplacesJustThatFrame() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->assertPattern('/Simple test front controller/'); $this->clickLink('Index'); $this->assertResponse(200); $this->assertText('[action=index]'); $this->assertText('Count: 1'); } function testJumpToUnnamedPageReplacesJustThatFrame() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->clickLink('No page'); $this->assertResponse(200); $this->assertText('Simple test front controller'); $this->assertText('[action=no_page]'); $this->assertText('Count: 1'); } function testJumpToUnnamedPageWithBareParameterReplacesJustThatFrame() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->clickLink('Bare action'); $this->assertResponse(200); $this->assertText('Simple test front controller'); $this->assertText('[action=]'); $this->assertText('Count: 1'); } function testJumpToUnnamedPageWithEmptyQueryReplacesJustThatFrame() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->clickLink('Empty query'); $this->assertResponse(200); $this->assertPattern('/Simple test front controller/'); $this->assertPattern('/raw get data.*?\[\].*?get data/si'); $this->assertPattern('/Count: 1/'); } function testJumpToUnnamedPageWithEmptyLinkReplacesJustThatFrame() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->clickLink('Empty link'); $this->assertResponse(200); $this->assertPattern('/Simple test front controller/'); $this->assertPattern('/raw get data.*?\[\].*?get data/si'); $this->assertPattern('/Count: 1/'); } function testJumpBackADirectoryLevelReplacesJustThatFrame() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->clickLink('Down one'); $this->assertPattern('/index of \/test/i'); $this->assertPattern('/Count: 1/'); } function testSubmitToNamedPageReplacesJustThatFrame() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->assertPattern('/Simple test front controller/'); $this->clickSubmit('Index'); $this->assertResponse(200); $this->assertText('[action=Index]'); $this->assertText('Count: 1'); } function testSubmitToSameDirectoryReplacesJustThatFrame() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->clickSubmit('Same directory'); $this->assertResponse(200); $this->assertText('[action=Same+directory]'); $this->assertText('Count: 1'); } function testSubmitToEmptyActionReplacesJustThatFrame() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->clickSubmit('Empty action'); $this->assertResponse(200); $this->assertText('[action=Empty+action]'); $this->assertText('Count: 1'); } function testSubmitToNoActionReplacesJustThatFrame() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->clickSubmit('No action'); $this->assertResponse(200); $this->assertText('[action=No+action]'); $this->assertText('Count: 1'); } function testSubmitBackADirectoryLevelReplacesJustThatFrame() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->clickSubmit('Down one'); $this->assertPattern('/index of \/test/i'); $this->assertPattern('/Count: 1/'); } function testTopLinkExitsFrameset() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->clickLink('Exit the frameset'); $this->assertTitle('Simple test target file'); } function testLinkInOnePageCanLoadAnother() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->assertNoLink('3'); $this->clickLink('Set one to 2'); $this->assertLink('3'); $this->assertNoLink('2'); $this->assertTitle('Frameset for testing of SimpleTest'); } } class TestOfFrameAuthentication extends WebTestCase { function setUp() { $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); } function testUnauthenticatedFrameSendsChallenge() { $this->get('http://www.lastcraft.com/test/protected/'); $this->setFrameFocus('Protected'); $this->assertAuthentication('Basic'); $this->assertRealm('SimpleTest basic authentication'); $this->assertResponse(401); } function testCanReadFrameFromAlreadyAuthenticatedRealm() { $this->get('http://www.lastcraft.com/test/protected/'); $this->authenticate('test', 'secret'); $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->setFrameFocus('Protected'); $this->assertResponse(200); $this->assertText('A target for the SimpleTest test suite'); } function testCanAuthenticateFrame() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->setFrameFocus('Protected'); $this->authenticate('test', 'secret'); $this->assertResponse(200); $this->assertText('A target for the SimpleTest test suite'); $this->clearFrameFocus(); $this->assertText('Count: 1'); } function testCanAuthenticateRedirectedFrame() { $this->get('http://www.lastcraft.com/test/messy_frameset.html'); $this->setFrameFocus('Protected redirect'); $this->assertResponse(401); $this->authenticate('test', 'secret'); $this->assertResponse(200); $this->assertText('A target for the SimpleTest test suite'); $this->clearFrameFocus(); $this->assertText('Count: 1'); } } class TestOfNestedFrames extends WebTestCase { function setUp() { $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); } function testCanNavigateToSpecificContent() { $this->get('http://www.lastcraft.com/test/nested_frameset.html'); $this->assertTitle('Nested frameset for testing of SimpleTest'); $this->assertPattern('/This is frame A/'); $this->assertPattern('/This is frame B/'); $this->assertPattern('/Simple test front controller/'); $this->assertLink('2'); $this->assertLink('Set one to 2'); $this->assertPattern('/Count: 1/'); $this->assertPattern('/r=rrr/'); $this->setFrameFocus('pair'); $this->assertPattern('/This is frame A/'); $this->assertPattern('/This is frame B/'); $this->assertNoPattern('/Simple test front controller/'); $this->assertNoLink('2'); $this->setFrameFocus('aaa'); $this->assertPattern('/This is frame A/'); $this->assertNoPattern('/This is frame B/'); $this->clearFrameFocus(); $this->assertResponse(200); $this->setFrameFocus('messy'); $this->assertResponse(200); $this->setFrameFocus('Front controller'); $this->assertResponse(200); $this->assertPattern('/Simple test front controller/'); $this->assertNoLink('2'); } function testReloadingFramesetPage() { $this->get('http://www.lastcraft.com/test/nested_frameset.html'); $this->assertPattern('/Count: 1/'); $this->retry(); $this->assertPattern('/Count: 2/'); $this->retry(); $this->assertPattern('/Count: 3/'); } function testRetryingNestedPageOnlyRetriesThatSet() { $this->get('http://www.lastcraft.com/test/nested_frameset.html'); $this->assertPattern('/Count: 1/'); $this->setFrameFocus('messy'); $this->retry(); $this->assertPattern('/Count: 2/'); $this->setFrameFocus('Counter'); $this->retry(); $this->assertPattern('/Count: 3/'); $this->clearFrameFocus(); $this->setFrameFocus('messy'); $this->setFrameFocus('Front controller'); $this->retry(); $this->clearFrameFocus(); $this->assertPattern('/Count: 3/'); } function testAuthenticatingNestedPage() { $this->get('http://www.lastcraft.com/test/nested_frameset.html'); $this->setFrameFocus('messy'); $this->setFrameFocus('Protected'); $this->assertAuthentication('Basic'); $this->assertRealm('SimpleTest basic authentication'); $this->assertResponse(401); $this->authenticate('test', 'secret'); $this->assertResponse(200); $this->assertPattern('/A target for the SimpleTest test suite/'); } } ?> postfixadmin-2.3.7/tests/simpletest/selector.php0000664000175000017620000000706611157271050022153 0ustar davidpalepurple_name = $name; } /** * Compares with name attribute of widget. * @param SimpleWidget $widget Control to compare. * @access public */ function isMatch($widget) { return ($widget->getName() == $this->_name); } } /** * Used to extract form elements for testing against. * Searches by visible label or alt text. * @package SimpleTest * @subpackage WebTester */ class SimpleByLabel { var $_label; /** * Stashes the name for later comparison. * @param string $label Visible text to match. */ function SimpleByLabel($label) { $this->_label = $label; } /** * Comparison. Compares visible text of widget or * related label. * @param SimpleWidget $widget Control to compare. * @access public */ function isMatch($widget) { if (! method_exists($widget, 'isLabel')) { return false; } return $widget->isLabel($this->_label); } } /** * Used to extract form elements for testing against. * Searches dy id attribute. * @package SimpleTest * @subpackage WebTester */ class SimpleById { var $_id; /** * Stashes the name for later comparison. * @param string $id ID atribute to match. */ function SimpleById($id) { $this->_id = $id; } /** * Comparison. Compares id attribute of widget. * @param SimpleWidget $widget Control to compare. * @access public */ function isMatch($widget) { return $widget->isId($this->_id); } } /** * Used to extract form elements for testing against. * Searches by visible label, name or alt text. * @package SimpleTest * @subpackage WebTester */ class SimpleByLabelOrName { var $_label; /** * Stashes the name/label for later comparison. * @param string $label Visible text to match. */ function SimpleByLabelOrName($label) { $this->_label = $label; } /** * Comparison. Compares visible text of widget or * related label or name. * @param SimpleWidget $widget Control to compare. * @access public */ function isMatch($widget) { if (method_exists($widget, 'isLabel')) { if ($widget->isLabel($this->_label)) { return true; } } return ($widget->getName() == $this->_label); } } ?>postfixadmin-2.3.7/tests/simpletest/test_case.php0000664000175000017620000005714611157271050022311 0ustar davidpalepurple= 0) { require_once(dirname(__FILE__) . '/exceptions.php'); require_once(dirname(__FILE__) . '/reflection_php5.php'); } else { require_once(dirname(__FILE__) . '/reflection_php4.php'); } if (! defined('SIMPLE_TEST')) { /** * @ignore */ define('SIMPLE_TEST', dirname(__FILE__) . DIRECTORY_SEPARATOR); } /**#@-*/ /** * Basic test case. This is the smallest unit of a test * suite. It searches for * all methods that start with the the string "test" and * runs them. Working test cases extend this class. * @package SimpleTest * @subpackage UnitTester */ class SimpleTestCase { var $_label = false; var $_reporter; var $_observers; var $_should_skip = false; /** * Sets up the test with no display. * @param string $label If no test name is given then * the class name is used. * @access public */ function SimpleTestCase($label = false) { if ($label) { $this->_label = $label; } } /** * Accessor for the test name for subclasses. * @return string Name of the test. * @access public */ function getLabel() { return $this->_label ? $this->_label : get_class($this); } /** * This is a placeholder for skipping tests. In this * method you place skipIf() and skipUnless() calls to * set the skipping state. * @access public */ function skip() { } /** * Will issue a message to the reporter and tell the test * case to skip if the incoming flag is true. * @param string $should_skip Condition causing the tests to be skipped. * @param string $message Text of skip condition. * @access public */ function skipIf($should_skip, $message = '%s') { if ($should_skip && ! $this->_should_skip) { $this->_should_skip = true; $message = sprintf($message, 'Skipping [' . get_class($this) . ']'); $this->_reporter->paintSkip($message . $this->getAssertionLine()); } } /** * Will issue a message to the reporter and tell the test * case to skip if the incoming flag is false. * @param string $shouldnt_skip Condition causing the tests to be run. * @param string $message Text of skip condition. * @access public */ function skipUnless($shouldnt_skip, $message = false) { $this->skipIf(! $shouldnt_skip, $message); } /** * Used to invoke the single tests. * @return SimpleInvoker Individual test runner. * @access public */ function &createInvoker() { $invoker = &new SimpleErrorTrappingInvoker(new SimpleInvoker($this)); if (version_compare(phpversion(), '5') >= 0) { $invoker = &new SimpleExceptionTrappingInvoker($invoker); } return $invoker; } /** * Uses reflection to run every method within itself * starting with the string "test" unless a method * is specified. * @param SimpleReporter $reporter Current test reporter. * @return boolean True if all tests passed. * @access public */ function run(&$reporter) { $context = &SimpleTest::getContext(); $context->setTest($this); $context->setReporter($reporter); $this->_reporter = &$reporter; $reporter->paintCaseStart($this->getLabel()); $this->skip(); if (! $this->_should_skip) { foreach ($this->getTests() as $method) { if ($reporter->shouldInvoke($this->getLabel(), $method)) { $invoker = &$this->_reporter->createInvoker($this->createInvoker()); $invoker->before($method); $invoker->invoke($method); $invoker->after($method); } } } $reporter->paintCaseEnd($this->getLabel()); unset($this->_reporter); return $reporter->getStatus(); } /** * Gets a list of test names. Normally that will * be all internal methods that start with the * name "test". This method should be overridden * if you want a different rule. * @return array List of test names. * @access public */ function getTests() { $methods = array(); foreach (get_class_methods(get_class($this)) as $method) { if ($this->_isTest($method)) { $methods[] = $method; } } return $methods; } /** * Tests to see if the method is a test that should * be run. Currently any method that starts with 'test' * is a candidate unless it is the constructor. * @param string $method Method name to try. * @return boolean True if test method. * @access protected */ function _isTest($method) { if (strtolower(substr($method, 0, 4)) == 'test') { return ! SimpleTestCompatibility::isA($this, strtolower($method)); } return false; } /** * Announces the start of the test. * @param string $method Test method just started. * @access public */ function before($method) { $this->_reporter->paintMethodStart($method); $this->_observers = array(); } /** * Sets up unit test wide variables at the start * of each test method. To be overridden in * actual user test cases. * @access public */ function setUp() { } /** * Clears the data set in the setUp() method call. * To be overridden by the user in actual user test cases. * @access public */ function tearDown() { } /** * Announces the end of the test. Includes private clean up. * @param string $method Test method just finished. * @access public */ function after($method) { for ($i = 0; $i < count($this->_observers); $i++) { $this->_observers[$i]->atTestEnd($method, $this); } $this->_reporter->paintMethodEnd($method); } /** * Sets up an observer for the test end. * @param object $observer Must have atTestEnd() * method. * @access public */ function tell(&$observer) { $this->_observers[] = &$observer; } /** * @deprecated */ function pass($message = "Pass") { if (! isset($this->_reporter)) { trigger_error('Can only make assertions within test methods'); } $this->_reporter->paintPass( $message . $this->getAssertionLine()); return true; } /** * Sends a fail event with a message. * @param string $message Message to send. * @access public */ function fail($message = "Fail") { if (! isset($this->_reporter)) { trigger_error('Can only make assertions within test methods'); } $this->_reporter->paintFail( $message . $this->getAssertionLine()); return false; } /** * Formats a PHP error and dispatches it to the * reporter. * @param integer $severity PHP error code. * @param string $message Text of error. * @param string $file File error occoured in. * @param integer $line Line number of error. * @access public */ function error($severity, $message, $file, $line) { if (! isset($this->_reporter)) { trigger_error('Can only make assertions within test methods'); } $this->_reporter->paintError( "Unexpected PHP error [$message] severity [$severity] in [$file line $line]"); } /** * Formats an exception and dispatches it to the * reporter. * @param Exception $exception Object thrown. * @access public */ function exception($exception) { $this->_reporter->paintException($exception); } /** * @deprecated */ function signal($type, &$payload) { if (! isset($this->_reporter)) { trigger_error('Can only make assertions within test methods'); } $this->_reporter->paintSignal($type, $payload); } /** * Runs an expectation directly, for extending the * tests with new expectation classes. * @param SimpleExpectation $expectation Expectation subclass. * @param mixed $compare Value to compare. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assert(&$expectation, $compare, $message = '%s') { if ($expectation->test($compare)) { return $this->pass(sprintf( $message, $expectation->overlayMessage($compare, $this->_reporter->getDumper()))); } else { return $this->fail(sprintf( $message, $expectation->overlayMessage($compare, $this->_reporter->getDumper()))); } } /** * @deprecated */ function assertExpectation(&$expectation, $compare, $message = '%s') { return $this->assert($expectation, $compare, $message); } /** * Uses a stack trace to find the line of an assertion. * @return string Line number of first assert* * method embedded in format string. * @access public */ function getAssertionLine() { $trace = new SimpleStackTrace(array('assert', 'expect', 'pass', 'fail', 'skip')); return $trace->traceMethod(); } /** * Sends a formatted dump of a variable to the * test suite for those emergency debugging * situations. * @param mixed $variable Variable to display. * @param string $message Message to display. * @return mixed The original variable. * @access public */ function dump($variable, $message = false) { $dumper = $this->_reporter->getDumper(); $formatted = $dumper->dump($variable); if ($message) { $formatted = $message . "\n" . $formatted; } $this->_reporter->paintFormattedMessage($formatted); return $variable; } /** * @deprecated */ function sendMessage($message) { $this->_reporter->PaintMessage($message); } /** * Accessor for the number of subtests. * @return integer Number of test cases. * @access public * @static */ function getSize() { return 1; } } /** * This is a composite test class for combining * test cases and other RunnableTest classes into * a group test. * @package SimpleTest * @subpackage UnitTester */ class TestSuite { var $_label; var $_test_cases; var $_old_track_errors; var $_xdebug_is_enabled; /** * Sets the name of the test suite. * @param string $label Name sent at the start and end * of the test. * @access public */ function TestSuite($label = false) { $this->_label = $label ? $label : get_class($this); $this->_test_cases = array(); $this->_old_track_errors = ini_get('track_errors'); $this->_xdebug_is_enabled = function_exists('xdebug_is_enabled') ? xdebug_is_enabled() : false; } /** * Accessor for the test name for subclasses. * @return string Name of the test. * @access public */ function getLabel() { return $this->_label; } /** * Adds a test into the suite. Can be either a group * test or some other unit test. * @param SimpleTestCase $test_case Suite or individual test * case implementing the * runnable test interface. * @access public */ function addTestCase(&$test_case) { $this->_test_cases[] = &$test_case; } /** * Adds a test into the suite by class name. The class will * be instantiated as needed. * @param SimpleTestCase $test_case Suite or individual test * case implementing the * runnable test interface. * @access public */ function addTestClass($class) { if ($this->_getBaseTestCase($class) == 'testsuite' || $this->_getBaseTestCase($class) == 'grouptest') { $this->_test_cases[] = &new $class(); } else { $this->_test_cases[] = $class; } } /** * Builds a group test from a library of test cases. * The new group is composed into this one. * @param string $test_file File name of library with * test case classes. * @access public */ function addTestFile($test_file) { $existing_classes = get_declared_classes(); if ($error = $this->_requireWithError($test_file)) { $this->addTestCase(new BadTestSuite($test_file, $error)); return; } $classes = $this->_selectRunnableTests($existing_classes, get_declared_classes()); if (count($classes) == 0) { $this->addTestCase(new BadTestSuite($test_file, "No runnable test cases in [$test_file]")); return; } $group = &$this->_createGroupFromClasses($test_file, $classes); $this->addTestCase($group); } /** * Requires a source file recording any syntax errors. * @param string $file File name to require in. * @return string/boolean An error message on failure or false * if no errors. * @access private */ function _requireWithError($file) { $this->_enableErrorReporting(); include($file); $error = isset($php_errormsg) ? $php_errormsg : false; $this->_disableErrorReporting(); $self_inflicted_errors = array( '/Assigning the return value of new by reference/i', '/var: Deprecated/i', '/Non-static method/i'); foreach ($self_inflicted_errors as $pattern) { if (preg_match($pattern, $error)) { return false; } } return $error; } /** * Sets up detection of parse errors. Note that XDebug * interferes with this and has to be disabled. This is * to make sure the correct error code is returned * from unattended scripts. * @access private */ function _enableErrorReporting() { if ($this->_xdebug_is_enabled) { xdebug_disable(); } ini_set('track_errors', true); } /** * Resets detection of parse errors to their old values. * This is to make sure the correct error code is returned * from unattended scripts. * @access private */ function _disableErrorReporting() { ini_set('track_errors', $this->_old_track_errors); if ($this->_xdebug_is_enabled) { xdebug_enable(); } } /** * Calculates the incoming test cases from a before * and after list of loaded classes. Skips abstract * classes. * @param array $existing_classes Classes before require(). * @param array $new_classes Classes after require(). * @return array New classes which are test * cases that shouldn't be ignored. * @access private */ function _selectRunnableTests($existing_classes, $new_classes) { $classes = array(); foreach ($new_classes as $class) { if (in_array($class, $existing_classes)) { continue; } if ($this->_getBaseTestCase($class)) { $reflection = new SimpleReflection($class); if ($reflection->isAbstract()) { SimpleTest::ignore($class); } $classes[] = $class; } } return $classes; } /** * Builds a group test from a class list. * @param string $title Title of new group. * @param array $classes Test classes. * @return TestSuite Group loaded with the new * test cases. * @access private */ function &_createGroupFromClasses($title, $classes) { SimpleTest::ignoreParentsIfIgnored($classes); $group = &new TestSuite($title); foreach ($classes as $class) { if (! SimpleTest::isIgnored($class)) { $group->addTestClass($class); } } return $group; } /** * Test to see if a class is derived from the * SimpleTestCase class. * @param string $class Class name. * @access private */ function _getBaseTestCase($class) { while ($class = get_parent_class($class)) { $class = strtolower($class); if ($class == 'simpletestcase' || $class == 'testsuite' || $class == 'grouptest') { return $class; } } return false; } /** * Delegates to a visiting collector to add test * files. * @param string $path Path to scan from. * @param SimpleCollector $collector Directory scanner. * @access public */ function collect($path, &$collector) { $collector->collect($this, $path); } /** * Invokes run() on all of the held test cases, instantiating * them if necessary. * @param SimpleReporter $reporter Current test reporter. * @access public */ function run(&$reporter) { $reporter->paintGroupStart($this->getLabel(), $this->getSize()); for ($i = 0, $count = count($this->_test_cases); $i < $count; $i++) { if (is_string($this->_test_cases[$i])) { $class = $this->_test_cases[$i]; $test = &new $class(); $test->run($reporter); unset($test); } else { $this->_test_cases[$i]->run($reporter); } } $reporter->paintGroupEnd($this->getLabel()); return $reporter->getStatus(); } /** * Number of contained test cases. * @return integer Total count of cases in the group. * @access public */ function getSize() { $count = 0; foreach ($this->_test_cases as $case) { if (is_string($case)) { $count++; } else { $count += $case->getSize(); } } return $count; } } /** * @package SimpleTest * @subpackage UnitTester * @deprecated */ class GroupTest extends TestSuite { } /** * This is a failing group test for when a test suite hasn't * loaded properly. * @package SimpleTest * @subpackage UnitTester */ class BadTestSuite { var $_label; var $_error; /** * Sets the name of the test suite and error message. * @param string $label Name sent at the start and end * of the test. * @access public */ function BadTestSuite($label, $error) { $this->_label = $label; $this->_error = $error; } /** * Accessor for the test name for subclasses. * @return string Name of the test. * @access public */ function getLabel() { return $this->_label; } /** * Sends a single error to the reporter. * @param SimpleReporter $reporter Current test reporter. * @access public */ function run(&$reporter) { $reporter->paintGroupStart($this->getLabel(), $this->getSize()); $reporter->paintFail('Bad TestSuite [' . $this->getLabel() . '] with error [' . $this->_error . ']'); $reporter->paintGroupEnd($this->getLabel()); return $reporter->getStatus(); } /** * Number of contained test cases. Always zero. * @return integer Total count of cases in the group. * @access public */ function getSize() { return 0; } } /** * @package SimpleTest * @subpackage UnitTester * @deprecated */ class BadGroupTest extends BadTestSuite { } ?>postfixadmin-2.3.7/tests/simpletest/remote.php0000664000175000017620000000752111157271050021622 0ustar davidpalepurple_url = $url; $this->_dry_url = $dry_url ? $dry_url : $url; $this->_size = false; } /** * Accessor for the test name for subclasses. * @return string Name of the test. * @access public */ function getLabel() { return $this->_url; } /** * Runs the top level test for this class. Currently * reads the data as a single chunk. I'll fix this * once I have added iteration to the browser. * @param SimpleReporter $reporter Target of test results. * @returns boolean True if no failures. * @access public */ function run(&$reporter) { $browser = &$this->_createBrowser(); $xml = $browser->get($this->_url); if (! $xml) { trigger_error('Cannot read remote test URL [' . $this->_url . ']'); return false; } $parser = &$this->_createParser($reporter); if (! $parser->parse($xml)) { trigger_error('Cannot parse incoming XML from [' . $this->_url . ']'); return false; } return true; } /** * Creates a new web browser object for fetching * the XML report. * @return SimpleBrowser New browser. * @access protected */ function &_createBrowser() { $browser = &new SimpleBrowser(); return $browser; } /** * Creates the XML parser. * @param SimpleReporter $reporter Target of test results. * @return SimpleTestXmlListener XML reader. * @access protected */ function &_createParser(&$reporter) { $parser = &new SimpleTestXmlParser($reporter); return $parser; } /** * Accessor for the number of subtests. * @return integer Number of test cases. * @access public */ function getSize() { if ($this->_size === false) { $browser = &$this->_createBrowser(); $xml = $browser->get($this->_dry_url); if (! $xml) { trigger_error('Cannot read remote test URL [' . $this->_dry_url . ']'); return false; } $reporter = &new SimpleReporter(); $parser = &$this->_createParser($reporter); if (! $parser->parse($xml)) { trigger_error('Cannot parse incoming XML from [' . $this->_dry_url . ']'); return false; } $this->_size = $reporter->getTestCaseCount(); } return $this->_size; } } ?>postfixadmin-2.3.7/tests/simpletest/xml.php0000664000175000017620000005273711157271050021140 0ustar davidpalepurpleSimpleReporter(); $this->_namespace = ($namespace ? $namespace . ':' : ''); $this->_indent = $indent; } /** * Calculates the pretty printing indent level * from the current level of nesting. * @param integer $offset Extra indenting level. * @return string Leading space. * @access protected */ function _getIndent($offset = 0) { return str_repeat( $this->_indent, count($this->getTestList()) + $offset); } /** * Converts character string to parsed XML * entities string. * @param string text Unparsed character data. * @return string Parsed character data. * @access public */ function toParsedXml($text) { return str_replace( array('&', '<', '>', '"', '\''), array('&', '<', '>', '"', '''), $text); } /** * Paints the start of a group test. * @param string $test_name Name of test that is starting. * @param integer $size Number of test cases starting. * @access public */ function paintGroupStart($test_name, $size) { parent::paintGroupStart($test_name, $size); print $this->_getIndent(); print "<" . $this->_namespace . "group size=\"$size\">\n"; print $this->_getIndent(1); print "<" . $this->_namespace . "name>" . $this->toParsedXml($test_name) . "_namespace . "name>\n"; } /** * Paints the end of a group test. * @param string $test_name Name of test that is ending. * @access public */ function paintGroupEnd($test_name) { print $this->_getIndent(); print "_namespace . "group>\n"; parent::paintGroupEnd($test_name); } /** * Paints the start of a test case. * @param string $test_name Name of test that is starting. * @access public */ function paintCaseStart($test_name) { parent::paintCaseStart($test_name); print $this->_getIndent(); print "<" . $this->_namespace . "case>\n"; print $this->_getIndent(1); print "<" . $this->_namespace . "name>" . $this->toParsedXml($test_name) . "_namespace . "name>\n"; } /** * Paints the end of a test case. * @param string $test_name Name of test that is ending. * @access public */ function paintCaseEnd($test_name) { print $this->_getIndent(); print "_namespace . "case>\n"; parent::paintCaseEnd($test_name); } /** * Paints the start of a test method. * @param string $test_name Name of test that is starting. * @access public */ function paintMethodStart($test_name) { parent::paintMethodStart($test_name); print $this->_getIndent(); print "<" . $this->_namespace . "test>\n"; print $this->_getIndent(1); print "<" . $this->_namespace . "name>" . $this->toParsedXml($test_name) . "_namespace . "name>\n"; } /** * Paints the end of a test method. * @param string $test_name Name of test that is ending. * @param integer $progress Number of test cases ending. * @access public */ function paintMethodEnd($test_name) { print $this->_getIndent(); print "_namespace . "test>\n"; parent::paintMethodEnd($test_name); } /** * Paints pass as XML. * @param string $message Message to encode. * @access public */ function paintPass($message) { parent::paintPass($message); print $this->_getIndent(1); print "<" . $this->_namespace . "pass>"; print $this->toParsedXml($message); print "_namespace . "pass>\n"; } /** * Paints failure as XML. * @param string $message Message to encode. * @access public */ function paintFail($message) { parent::paintFail($message); print $this->_getIndent(1); print "<" . $this->_namespace . "fail>"; print $this->toParsedXml($message); print "_namespace . "fail>\n"; } /** * Paints error as XML. * @param string $message Message to encode. * @access public */ function paintError($message) { parent::paintError($message); print $this->_getIndent(1); print "<" . $this->_namespace . "exception>"; print $this->toParsedXml($message); print "_namespace . "exception>\n"; } /** * Paints exception as XML. * @param Exception $exception Exception to encode. * @access public */ function paintException($exception) { parent::paintException($exception); print $this->_getIndent(1); print "<" . $this->_namespace . "exception>"; $message = 'Unexpected exception of type [' . get_class($exception) . '] with message ['. $exception->getMessage() . '] in ['. $exception->getFile() . ' line ' . $exception->getLine() . ']'; print $this->toParsedXml($message); print "_namespace . "exception>\n"; } /** * Paints the skipping message and tag. * @param string $message Text to display in skip tag. * @access public */ function paintSkip($message) { parent::paintSkip($message); print $this->_getIndent(1); print "<" . $this->_namespace . "skip>"; print $this->toParsedXml($message); print "_namespace . "skip>\n"; } /** * Paints a simple supplementary message. * @param string $message Text to display. * @access public */ function paintMessage($message) { parent::paintMessage($message); print $this->_getIndent(1); print "<" . $this->_namespace . "message>"; print $this->toParsedXml($message); print "_namespace . "message>\n"; } /** * Paints a formatted ASCII message such as a * variable dump. * @param string $message Text to display. * @access public */ function paintFormattedMessage($message) { parent::paintFormattedMessage($message); print $this->_getIndent(1); print "<" . $this->_namespace . "formatted>"; print ""; print "_namespace . "formatted>\n"; } /** * Serialises the event object. * @param string $type Event type as text. * @param mixed $payload Message or object. * @access public */ function paintSignal($type, &$payload) { parent::paintSignal($type, $payload); print $this->_getIndent(1); print "<" . $this->_namespace . "signal type=\"$type\">"; print ""; print "_namespace . "signal>\n"; } /** * Paints the test document header. * @param string $test_name First test top level * to start. * @access public * @abstract */ function paintHeader($test_name) { if (! SimpleReporter::inCli()) { header('Content-type: text/xml'); } print "_namespace) { print " xmlns:" . $this->_namespace . "=\"www.lastcraft.com/SimpleTest/Beta3/Report\""; } print "?>\n"; print "<" . $this->_namespace . "run>\n"; } /** * Paints the test document footer. * @param string $test_name The top level test. * @access public * @abstract */ function paintFooter($test_name) { print "_namespace . "run>\n"; } } /** * Accumulator for incoming tag. Holds the * incoming test structure information for * later dispatch to the reporter. * @package SimpleTest * @subpackage UnitTester */ class NestingXmlTag { var $_name; var $_attributes; /** * Sets the basic test information except * the name. * @param hash $attributes Name value pairs. * @access public */ function NestingXmlTag($attributes) { $this->_name = false; $this->_attributes = $attributes; } /** * Sets the test case/method name. * @param string $name Name of test. * @access public */ function setName($name) { $this->_name = $name; } /** * Accessor for name. * @return string Name of test. * @access public */ function getName() { return $this->_name; } /** * Accessor for attributes. * @return hash All attributes. * @access protected */ function _getAttributes() { return $this->_attributes; } } /** * Accumulator for incoming method tag. Holds the * incoming test structure information for * later dispatch to the reporter. * @package SimpleTest * @subpackage UnitTester */ class NestingMethodTag extends NestingXmlTag { /** * Sets the basic test information except * the name. * @param hash $attributes Name value pairs. * @access public */ function NestingMethodTag($attributes) { $this->NestingXmlTag($attributes); } /** * Signals the appropriate start event on the * listener. * @param SimpleReporter $listener Target for events. * @access public */ function paintStart(&$listener) { $listener->paintMethodStart($this->getName()); } /** * Signals the appropriate end event on the * listener. * @param SimpleReporter $listener Target for events. * @access public */ function paintEnd(&$listener) { $listener->paintMethodEnd($this->getName()); } } /** * Accumulator for incoming case tag. Holds the * incoming test structure information for * later dispatch to the reporter. * @package SimpleTest * @subpackage UnitTester */ class NestingCaseTag extends NestingXmlTag { /** * Sets the basic test information except * the name. * @param hash $attributes Name value pairs. * @access public */ function NestingCaseTag($attributes) { $this->NestingXmlTag($attributes); } /** * Signals the appropriate start event on the * listener. * @param SimpleReporter $listener Target for events. * @access public */ function paintStart(&$listener) { $listener->paintCaseStart($this->getName()); } /** * Signals the appropriate end event on the * listener. * @param SimpleReporter $listener Target for events. * @access public */ function paintEnd(&$listener) { $listener->paintCaseEnd($this->getName()); } } /** * Accumulator for incoming group tag. Holds the * incoming test structure information for * later dispatch to the reporter. * @package SimpleTest * @subpackage UnitTester */ class NestingGroupTag extends NestingXmlTag { /** * Sets the basic test information except * the name. * @param hash $attributes Name value pairs. * @access public */ function NestingGroupTag($attributes) { $this->NestingXmlTag($attributes); } /** * Signals the appropriate start event on the * listener. * @param SimpleReporter $listener Target for events. * @access public */ function paintStart(&$listener) { $listener->paintGroupStart($this->getName(), $this->getSize()); } /** * Signals the appropriate end event on the * listener. * @param SimpleReporter $listener Target for events. * @access public */ function paintEnd(&$listener) { $listener->paintGroupEnd($this->getName()); } /** * The size in the attributes. * @return integer Value of size attribute or zero. * @access public */ function getSize() { $attributes = $this->_getAttributes(); if (isset($attributes['SIZE'])) { return (integer)$attributes['SIZE']; } return 0; } } /** * Parser for importing the output of the XmlReporter. * Dispatches that output to another reporter. * @package SimpleTest * @subpackage UnitTester */ class SimpleTestXmlParser { var $_listener; var $_expat; var $_tag_stack; var $_in_content_tag; var $_content; var $_attributes; /** * Loads a listener with the SimpleReporter * interface. * @param SimpleReporter $listener Listener of tag events. * @access public */ function SimpleTestXmlParser(&$listener) { $this->_listener = &$listener; $this->_expat = &$this->_createParser(); $this->_tag_stack = array(); $this->_in_content_tag = false; $this->_content = ''; $this->_attributes = array(); } /** * Parses a block of XML sending the results to * the listener. * @param string $chunk Block of text to read. * @return boolean True if valid XML. * @access public */ function parse($chunk) { if (! xml_parse($this->_expat, $chunk)) { trigger_error('XML parse error with ' . xml_error_string(xml_get_error_code($this->_expat))); return false; } return true; } /** * Sets up expat as the XML parser. * @return resource Expat handle. * @access protected */ function &_createParser() { $expat = xml_parser_create(); xml_set_object($expat, $this); xml_set_element_handler($expat, '_startElement', '_endElement'); xml_set_character_data_handler($expat, '_addContent'); xml_set_default_handler($expat, '_default'); return $expat; } /** * Opens a new test nesting level. * @return NestedXmlTag The group, case or method tag * to start. * @access private */ function _pushNestingTag($nested) { array_unshift($this->_tag_stack, $nested); } /** * Accessor for current test structure tag. * @return NestedXmlTag The group, case or method tag * being parsed. * @access private */ function &_getCurrentNestingTag() { return $this->_tag_stack[0]; } /** * Ends a nesting tag. * @return NestedXmlTag The group, case or method tag * just finished. * @access private */ function _popNestingTag() { return array_shift($this->_tag_stack); } /** * Test if tag is a leaf node with only text content. * @param string $tag XML tag name. * @return @boolean True if leaf, false if nesting. * @private */ function _isLeaf($tag) { return in_array($tag, array( 'NAME', 'PASS', 'FAIL', 'EXCEPTION', 'SKIP', 'MESSAGE', 'FORMATTED', 'SIGNAL')); } /** * Handler for start of event element. * @param resource $expat Parser handle. * @param string $tag Element name. * @param hash $attributes Name value pairs. * Attributes without content * are marked as true. * @access protected */ function _startElement($expat, $tag, $attributes) { $this->_attributes = $attributes; if ($tag == 'GROUP') { $this->_pushNestingTag(new NestingGroupTag($attributes)); } elseif ($tag == 'CASE') { $this->_pushNestingTag(new NestingCaseTag($attributes)); } elseif ($tag == 'TEST') { $this->_pushNestingTag(new NestingMethodTag($attributes)); } elseif ($this->_isLeaf($tag)) { $this->_in_content_tag = true; $this->_content = ''; } } /** * End of element event. * @param resource $expat Parser handle. * @param string $tag Element name. * @access protected */ function _endElement($expat, $tag) { $this->_in_content_tag = false; if (in_array($tag, array('GROUP', 'CASE', 'TEST'))) { $nesting_tag = $this->_popNestingTag(); $nesting_tag->paintEnd($this->_listener); } elseif ($tag == 'NAME') { $nesting_tag = &$this->_getCurrentNestingTag(); $nesting_tag->setName($this->_content); $nesting_tag->paintStart($this->_listener); } elseif ($tag == 'PASS') { $this->_listener->paintPass($this->_content); } elseif ($tag == 'FAIL') { $this->_listener->paintFail($this->_content); } elseif ($tag == 'EXCEPTION') { $this->_listener->paintError($this->_content); } elseif ($tag == 'SKIP') { $this->_listener->paintSkip($this->_content); } elseif ($tag == 'SIGNAL') { $this->_listener->paintSignal( $this->_attributes['TYPE'], unserialize($this->_content)); } elseif ($tag == 'MESSAGE') { $this->_listener->paintMessage($this->_content); } elseif ($tag == 'FORMATTED') { $this->_listener->paintFormattedMessage($this->_content); } } /** * Content between start and end elements. * @param resource $expat Parser handle. * @param string $text Usually output messages. * @access protected */ function _addContent($expat, $text) { if ($this->_in_content_tag) { $this->_content .= $text; } return true; } /** * XML and Doctype handler. Discards all such content. * @param resource $expat Parser handle. * @param string $default Text of default content. * @access protected */ function _default($expat, $default) { } } ?> postfixadmin-2.3.7/tests/simpletest/exceptions.php0000664000175000017620000001243111157271050022504 0ustar davidpalepurpleSimpleInvokerDecorator($invoker); } /** * Invokes a test method whilst trapping expected * exceptions. Any left over unthrown exceptions * are then reported as failures. * @param string $method Test method to call. */ function invoke($method) { $trap = SimpleTest::getContext()->get('SimpleExceptionTrap'); $trap->clear(); try { parent::invoke($method); } catch (Exception $exception) { if (! $trap->isExpected($this->getTestCase(), $exception)) { $this->getTestCase()->exception($exception); } $trap->clear(); $this->_invoker->getTestCase()->tearDown(); } if ($message = $trap->getOutstanding()) { $this->getTestCase()->fail($message); } } } /** * Tests exceptions either by type or the exact * exception. This could be improved to accept * a pattern expectation to test the error * message, but that will have to come later. * @package SimpleTest * @subpackage UnitTester */ class ExceptionExpectation extends SimpleExpectation { private $expected; /** * Sets up the conditions to test against. * If the expected value is a string, then * it will act as a test of the class name. * An exception as the comparison will * trigger an identical match. Writing this * down now makes it look doubly dumb. I hope * come up with a better scheme later. * @param mixed $expected A class name or an actual * exception to compare with. * @param string $message Message to display. */ function __construct($expected, $message = '%s') { $this->expected = $expected; parent::__construct($message); } /** * Carry out the test. * @param Exception $compare Value to check. * @return boolean True if matched. */ function test($compare) { if (is_string($this->expected)) { return ($compare instanceof $this->expected); } if (get_class($compare) != get_class($this->expected)) { return false; } return $compare->getMessage() == $this->expected->getMessage(); } /** * Create the message to display describing the test. * @param Exception $compare Exception to match. * @return string Final message. */ function testMessage($compare) { if (is_string($this->expected)) { return "Exception [" . $this->describeException($compare) . "] should be type [" . $this->expected . "]"; } return "Exception [" . $this->describeException($compare) . "] should match [" . $this->describeException($this->expected) . "]"; } /** * Summary of an Exception object. * @param Exception $compare Exception to describe. * @return string Text description. */ protected function describeException($exception) { return get_class($exception) . ": " . $exception->getMessage(); } } /** * Stores expected exceptions for when they * get thrown. Saves the irritating try...catch * block. * @package SimpleTest * @subpackage UnitTester */ class SimpleExceptionTrap { private $expected; private $message; /** * Clears down the queue ready for action. */ function __construct() { $this->clear(); } /** * Sets up an expectation of an exception. * This has the effect of intercepting an * exception that matches. * @param SimpleExpectation $expected Expected exception to match. * @param string $message Message to display. * @access public */ function expectException($expected = false, $message = '%s') { if ($expected === false) { $expected = new AnythingExpectation(); } if (! SimpleExpectation::isExpectation($expected)) { $expected = new ExceptionExpectation($expected); } $this->expected = $expected; $this->message = $message; } /** * Compares the expected exception with any * in the queue. Issues a pass or fail and * returns the state of the test. * @param SimpleTestCase $test Test case to send messages to. * @param Exception $exception Exception to compare. * @return boolean False on no match. */ function isExpected($test, $exception) { if ($this->expected) { return $test->assert($this->expected, $exception, $this->message); } return false; } /** * Tests for any left over exception. * @return string/false The failure message or false if none. */ function getOutstanding() { return sprintf($this->message, 'Failed to trap exception'); } /** * Discards the contents of the error queue. */ function clear() { $this->expected = false; $this->message = false; } } ?>postfixadmin-2.3.7/tests/simpletest/BACKLOG0000664000175000017620000000120711157271050020576 0ustar davidpalepurpleBACKLOG This is backed up stuff that defines the 1.0.1 release. $Id: BACKLOG,v 1.10 2006/11/20 23:44:36 lastcraft Exp $ Unit tester ----------- Reporter -------- Mock objects ------------ Fix new type hinting bug in PHP 5.0.2 and above (1). Parser ------ Add U flag to regexes to allow unicode (3). Browser ------- Add a file() loading command (4). Change getUrls() to return more information (2). Web tester ---------- Documentation ------------- Extension docs (1). Integrate SpikeSource docs (4). Write Eclipse plug-in guide (4). Add page for projects that use or extend SimpleTest (2). Build ----- Integrate German documentation (2). postfixadmin-2.3.7/tests/simpletest/frames.php0000664000175000017620000005031711157271050021605 0ustar davidpalepurple_frameset = &$page; $this->_frames = array(); $this->_focus = false; $this->_names = array(); } /** * Adds a parsed page to the frameset. * @param SimplePage $page Frame page. * @param string $name Name of frame in frameset. * @access public */ function addFrame(&$page, $name = false) { $this->_frames[] = &$page; if ($name) { $this->_names[$name] = count($this->_frames) - 1; } } /** * Replaces existing frame with another. If the * frame is nested, then the call is passed down * one level. * @param array $path Path of frame in frameset. * @param SimplePage $page Frame source. * @access public */ function setFrame($path, &$page) { $name = array_shift($path); if (isset($this->_names[$name])) { $index = $this->_names[$name]; } else { $index = $name - 1; } if (count($path) == 0) { $this->_frames[$index] = &$page; return; } $this->_frames[$index]->setFrame($path, $page); } /** * Accessor for current frame focus. Will be * false if no frame has focus. Will have the nested * frame focus if any. * @return array Labels or indexes of nested frames. * @access public */ function getFrameFocus() { if ($this->_focus === false) { return array(); } return array_merge( array($this->_getPublicNameFromIndex($this->_focus)), $this->_frames[$this->_focus]->getFrameFocus()); } /** * Turns an internal array index into the frames list * into a public name, or if none, then a one offset * index. * @param integer $subject Internal index. * @return integer/string Public name. * @access private */ function _getPublicNameFromIndex($subject) { foreach ($this->_names as $name => $index) { if ($subject == $index) { return $name; } } return $subject + 1; } /** * Sets the focus by index. The integer index starts from 1. * If already focused and the target frame also has frames, * then the nested frame will be focused. * @param integer $choice Chosen frame. * @return boolean True if frame exists. * @access public */ function setFrameFocusByIndex($choice) { if (is_integer($this->_focus)) { if ($this->_frames[$this->_focus]->hasFrames()) { return $this->_frames[$this->_focus]->setFrameFocusByIndex($choice); } } if (($choice < 1) || ($choice > count($this->_frames))) { return false; } $this->_focus = $choice - 1; return true; } /** * Sets the focus by name. If already focused and the * target frame also has frames, then the nested frame * will be focused. * @param string $name Chosen frame. * @return boolean True if frame exists. * @access public */ function setFrameFocus($name) { if (is_integer($this->_focus)) { if ($this->_frames[$this->_focus]->hasFrames()) { return $this->_frames[$this->_focus]->setFrameFocus($name); } } if (in_array($name, array_keys($this->_names))) { $this->_focus = $this->_names[$name]; return true; } return false; } /** * Clears the frame focus. * @access public */ function clearFrameFocus() { $this->_focus = false; $this->_clearNestedFramesFocus(); } /** * Clears the frame focus for any nested frames. * @access private */ function _clearNestedFramesFocus() { for ($i = 0; $i < count($this->_frames); $i++) { $this->_frames[$i]->clearFrameFocus(); } } /** * Test for the presence of a frameset. * @return boolean Always true. * @access public */ function hasFrames() { return true; } /** * Accessor for frames information. * @return array/string Recursive hash of frame URL strings. * The key is either a numerical * index or the name attribute. * @access public */ function getFrames() { $report = array(); for ($i = 0; $i < count($this->_frames); $i++) { $report[$this->_getPublicNameFromIndex($i)] = $this->_frames[$i]->getFrames(); } return $report; } /** * Accessor for raw text of either all the pages or * the frame in focus. * @return string Raw unparsed content. * @access public */ function getRaw() { if (is_integer($this->_focus)) { return $this->_frames[$this->_focus]->getRaw(); } $raw = ''; for ($i = 0; $i < count($this->_frames); $i++) { $raw .= $this->_frames[$i]->getRaw(); } return $raw; } /** * Accessor for plain text of either all the pages or * the frame in focus. * @return string Plain text content. * @access public */ function getText() { if (is_integer($this->_focus)) { return $this->_frames[$this->_focus]->getText(); } $raw = ''; for ($i = 0; $i < count($this->_frames); $i++) { $raw .= ' ' . $this->_frames[$i]->getText(); } return trim($raw); } /** * Accessor for last error. * @return string Error from last response. * @access public */ function getTransportError() { if (is_integer($this->_focus)) { return $this->_frames[$this->_focus]->getTransportError(); } return $this->_frameset->getTransportError(); } /** * Request method used to fetch this frame. * @return string GET, POST or HEAD. * @access public */ function getMethod() { if (is_integer($this->_focus)) { return $this->_frames[$this->_focus]->getMethod(); } return $this->_frameset->getMethod(); } /** * Original resource name. * @return SimpleUrl Current url. * @access public */ function getUrl() { if (is_integer($this->_focus)) { $url = $this->_frames[$this->_focus]->getUrl(); $url->setTarget($this->_getPublicNameFromIndex($this->_focus)); } else { $url = $this->_frameset->getUrl(); } return $url; } /** * Original request data. * @return mixed Sent content. * @access public */ function getRequestData() { if (is_integer($this->_focus)) { return $this->_frames[$this->_focus]->getRequestData(); } return $this->_frameset->getRequestData(); } /** * Accessor for current MIME type. * @return string MIME type as string; e.g. 'text/html' * @access public */ function getMimeType() { if (is_integer($this->_focus)) { return $this->_frames[$this->_focus]->getMimeType(); } return $this->_frameset->getMimeType(); } /** * Accessor for last response code. * @return integer Last HTTP response code received. * @access public */ function getResponseCode() { if (is_integer($this->_focus)) { return $this->_frames[$this->_focus]->getResponseCode(); } return $this->_frameset->getResponseCode(); } /** * Accessor for last Authentication type. Only valid * straight after a challenge (401). * @return string Description of challenge type. * @access public */ function getAuthentication() { if (is_integer($this->_focus)) { return $this->_frames[$this->_focus]->getAuthentication(); } return $this->_frameset->getAuthentication(); } /** * Accessor for last Authentication realm. Only valid * straight after a challenge (401). * @return string Name of security realm. * @access public */ function getRealm() { if (is_integer($this->_focus)) { return $this->_frames[$this->_focus]->getRealm(); } return $this->_frameset->getRealm(); } /** * Accessor for outgoing header information. * @return string Header block. * @access public */ function getRequest() { if (is_integer($this->_focus)) { return $this->_frames[$this->_focus]->getRequest(); } return $this->_frameset->getRequest(); } /** * Accessor for raw header information. * @return string Header block. * @access public */ function getHeaders() { if (is_integer($this->_focus)) { return $this->_frames[$this->_focus]->getHeaders(); } return $this->_frameset->getHeaders(); } /** * Accessor for parsed title. * @return string Title or false if no title is present. * @access public */ function getTitle() { return $this->_frameset->getTitle(); } /** * Accessor for a list of all fixed links. * @return array List of urls with scheme of * http or https and hostname. * @access public */ function getAbsoluteUrls() { if (is_integer($this->_focus)) { return $this->_frames[$this->_focus]->getAbsoluteUrls(); } $urls = array(); foreach ($this->_frames as $frame) { $urls = array_merge($urls, $frame->getAbsoluteUrls()); } return array_values(array_unique($urls)); } /** * Accessor for a list of all relative links. * @return array List of urls without hostname. * @access public */ function getRelativeUrls() { if (is_integer($this->_focus)) { return $this->_frames[$this->_focus]->getRelativeUrls(); } $urls = array(); foreach ($this->_frames as $frame) { $urls = array_merge($urls, $frame->getRelativeUrls()); } return array_values(array_unique($urls)); } /** * Accessor for URLs by the link label. Label will match * regardess of whitespace issues and case. * @param string $label Text of link. * @return array List of links with that label. * @access public */ function getUrlsByLabel($label) { if (is_integer($this->_focus)) { return $this->_tagUrlsWithFrame( $this->_frames[$this->_focus]->getUrlsByLabel($label), $this->_focus); } $urls = array(); foreach ($this->_frames as $index => $frame) { $urls = array_merge( $urls, $this->_tagUrlsWithFrame( $frame->getUrlsByLabel($label), $index)); } return $urls; } /** * Accessor for a URL by the id attribute. If in a frameset * then the first link found with that ID attribute is * returned only. Focus on a frame if you want one from * a specific part of the frameset. * @param string $id Id attribute of link. * @return string URL with that id. * @access public */ function getUrlById($id) { foreach ($this->_frames as $index => $frame) { if ($url = $frame->getUrlById($id)) { if (! $url->gettarget()) { $url->setTarget($this->_getPublicNameFromIndex($index)); } return $url; } } return false; } /** * Attaches the intended frame index to a list of URLs. * @param array $urls List of SimpleUrls. * @param string $frame Name of frame or index. * @return array List of tagged URLs. * @access private */ function _tagUrlsWithFrame($urls, $frame) { $tagged = array(); foreach ($urls as $url) { if (! $url->getTarget()) { $url->setTarget($this->_getPublicNameFromIndex($frame)); } $tagged[] = $url; } return $tagged; } /** * Finds a held form by button label. Will only * search correctly built forms. * @param SimpleSelector $selector Button finder. * @return SimpleForm Form object containing * the button. * @access public */ function &getFormBySubmit($selector) { $form = &$this->_findForm('getFormBySubmit', $selector); return $form; } /** * Finds a held form by image using a selector. * Will only search correctly built forms. The first * form found either within the focused frame, or * across frames, will be the one returned. * @param SimpleSelector $selector Image finder. * @return SimpleForm Form object containing * the image. * @access public */ function &getFormByImage($selector) { $form = &$this->_findForm('getFormByImage', $selector); return $form; } /** * Finds a held form by the form ID. A way of * identifying a specific form when we have control * of the HTML code. The first form found * either within the focused frame, or across frames, * will be the one returned. * @param string $id Form label. * @return SimpleForm Form object containing the matching ID. * @access public */ function &getFormById($id) { $form = &$this->_findForm('getFormById', $id); return $form; } /** * General form finder. Will search all the frames or * just the one in focus. * @param string $method Method to use to find in a page. * @param string $attribute Label, name or ID. * @return SimpleForm Form object containing the matching ID. * @access private */ function &_findForm($method, $attribute) { if (is_integer($this->_focus)) { $form = &$this->_findFormInFrame( $this->_frames[$this->_focus], $this->_focus, $method, $attribute); return $form; } for ($i = 0; $i < count($this->_frames); $i++) { $form = &$this->_findFormInFrame( $this->_frames[$i], $i, $method, $attribute); if ($form) { return $form; } } $null = null; return $null; } /** * Finds a form in a page using a form finding method. Will * also tag the form with the frame name it belongs in. * @param SimplePage $page Page content of frame. * @param integer $index Internal frame representation. * @param string $method Method to use to find in a page. * @param string $attribute Label, name or ID. * @return SimpleForm Form object containing the matching ID. * @access private */ function &_findFormInFrame(&$page, $index, $method, $attribute) { $form = &$this->_frames[$index]->$method($attribute); if (isset($form)) { $form->setDefaultTarget($this->_getPublicNameFromIndex($index)); } return $form; } /** * Sets a field on each form in which the field is * available. * @param SimpleSelector $selector Field finder. * @param string $value Value to set field to. * @return boolean True if value is valid. * @access public */ function setField($selector, $value) { if (is_integer($this->_focus)) { $this->_frames[$this->_focus]->setField($selector, $value); } else { for ($i = 0; $i < count($this->_frames); $i++) { $this->_frames[$i]->setField($selector, $value); } } } /** * Accessor for a form element value within a page. * @param SimpleSelector $selector Field finder. * @return string/boolean A string if the field is * present, false if unchecked * and null if missing. * @access public */ function getField($selector) { for ($i = 0; $i < count($this->_frames); $i++) { $value = $this->_frames[$i]->getField($selector); if (isset($value)) { return $value; } } return null; } } ?>postfixadmin-2.3.7/tests/simpletest/shell_tester.php0000664000175000017620000002673511157271050023034 0ustar davidpalepurple_output = false; } /** * Actually runs the command. Does not trap the * error stream output as this need PHP 4.3+. * @param string $command The actual command line * to run. * @return integer Exit code. * @access public */ function execute($command) { $this->_output = false; exec($command, $this->_output, $ret); return $ret; } /** * Accessor for the last output. * @return string Output as text. * @access public */ function getOutput() { return implode("\n", $this->_output); } /** * Accessor for the last output. * @return array Output as array of lines. * @access public */ function getOutputAsList() { return $this->_output; } } /** * Test case for testing of command line scripts and * utilities. Usually scripts that are external to the * PHP code, but support it in some way. * @package SimpleTest * @subpackage UnitTester */ class ShellTestCase extends SimpleTestCase { var $_current_shell; var $_last_status; var $_last_command; /** * Creates an empty test case. Should be subclassed * with test methods for a functional test case. * @param string $label Name of test case. Will use * the class name if none specified. * @access public */ function ShellTestCase($label = false) { $this->SimpleTestCase($label); $this->_current_shell = &$this->_createShell(); $this->_last_status = false; $this->_last_command = ''; } /** * Executes a command and buffers the results. * @param string $command Command to run. * @return boolean True if zero exit code. * @access public */ function execute($command) { $shell = &$this->_getShell(); $this->_last_status = $shell->execute($command); $this->_last_command = $command; return ($this->_last_status === 0); } /** * Dumps the output of the last command. * @access public */ function dumpOutput() { $this->dump($this->getOutput()); } /** * Accessor for the last output. * @return string Output as text. * @access public */ function getOutput() { $shell = &$this->_getShell(); return $shell->getOutput(); } /** * Accessor for the last output. * @return array Output as array of lines. * @access public */ function getOutputAsList() { $shell = &$this->_getShell(); return $shell->getOutputAsList(); } /** * Called from within the test methods to register * passes and failures. * @param boolean $result Pass on true. * @param string $message Message to display describing * the test state. * @return boolean True on pass * @access public */ function assertTrue($result, $message = false) { return $this->assert(new TrueExpectation(), $result, $message); } /** * Will be true on false and vice versa. False * is the PHP definition of false, so that null, * empty strings, zero and an empty array all count * as false. * @param boolean $result Pass on false. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertFalse($result, $message = '%s') { return $this->assert(new FalseExpectation(), $result, $message); } /** * Will trigger a pass if the two parameters have * the same value only. Otherwise a fail. This * is for testing hand extracted text, etc. * @param mixed $first Value to compare. * @param mixed $second Value to compare. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertEqual($first, $second, $message = "%s") { return $this->assert( new EqualExpectation($first), $second, $message); } /** * Will trigger a pass if the two parameters have * a different value. Otherwise a fail. This * is for testing hand extracted text, etc. * @param mixed $first Value to compare. * @param mixed $second Value to compare. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertNotEqual($first, $second, $message = "%s") { return $this->assert( new NotEqualExpectation($first), $second, $message); } /** * Tests the last status code from the shell. * @param integer $status Expected status of last * command. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertExitCode($status, $message = "%s") { $message = sprintf($message, "Expected status code of [$status] from [" . $this->_last_command . "], but got [" . $this->_last_status . "]"); return $this->assertTrue($status === $this->_last_status, $message); } /** * Attempt to exactly match the combined STDERR and * STDOUT output. * @param string $expected Expected output. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertOutput($expected, $message = "%s") { $shell = &$this->_getShell(); return $this->assert( new EqualExpectation($expected), $shell->getOutput(), $message); } /** * Scans the output for a Perl regex. If found * anywhere it passes, else it fails. * @param string $pattern Regex to search for. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertOutputPattern($pattern, $message = "%s") { $shell = &$this->_getShell(); return $this->assert( new PatternExpectation($pattern), $shell->getOutput(), $message); } /** * If a Perl regex is found anywhere in the current * output then a failure is generated, else a pass. * @param string $pattern Regex to search for. * @param $message Message to display. * @return boolean True if pass. * @access public */ function assertNoOutputPattern($pattern, $message = "%s") { $shell = &$this->_getShell(); return $this->assert( new NoPatternExpectation($pattern), $shell->getOutput(), $message); } /** * File existence check. * @param string $path Full filename and path. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertFileExists($path, $message = "%s") { $message = sprintf($message, "File [$path] should exist"); return $this->assertTrue(file_exists($path), $message); } /** * File non-existence check. * @param string $path Full filename and path. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertFileNotExists($path, $message = "%s") { $message = sprintf($message, "File [$path] should not exist"); return $this->assertFalse(file_exists($path), $message); } /** * Scans a file for a Perl regex. If found * anywhere it passes, else it fails. * @param string $pattern Regex to search for. * @param string $path Full filename and path. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertFilePattern($pattern, $path, $message = "%s") { $shell = &$this->_getShell(); return $this->assert( new PatternExpectation($pattern), implode('', file($path)), $message); } /** * If a Perl regex is found anywhere in the named * file then a failure is generated, else a pass. * @param string $pattern Regex to search for. * @param string $path Full filename and path. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertNoFilePattern($pattern, $path, $message = "%s") { $shell = &$this->_getShell(); return $this->assert( new NoPatternExpectation($pattern), implode('', file($path)), $message); } /** * Accessor for current shell. Used for testing the * the tester itself. * @return Shell Current shell. * @access protected */ function &_getShell() { return $this->_current_shell; } /** * Factory for the shell to run the command on. * @return Shell New shell object. * @access protected */ function &_createShell() { $shell = &new SimpleShell(); return $shell; } } ?> postfixadmin-2.3.7/tests/simpletest/simpletest.php0000664000175000017620000003253611157271050022524 0ustar davidpalepurple= 0) { require_once(dirname(__FILE__) . '/reflection_php5.php'); } else { require_once(dirname(__FILE__) . '/reflection_php4.php'); } /**#@-*/ /** * Registry and test context. Includes a few * global options that I'm slowly getting rid of. * @package SimpleTest * @subpackage UnitTester */ class SimpleTest { /** * Reads the SimpleTest version from the release file. * @return string Version string. * @static * @access public */ function getVersion() { $content = file(dirname(__FILE__) . '/VERSION'); return trim($content[0]); } /** * Sets the name of a test case to ignore, usually * because the class is an abstract case that should * not be run. Once PHP4 is dropped this will disappear * as a public method and "abstract" will rule. * @param string $class Add a class to ignore. * @static * @access public */ function ignore($class) { $registry = &SimpleTest::_getRegistry(); $registry['IgnoreList'][strtolower($class)] = true; } /** * Scans the now complete ignore list, and adds * all parent classes to the list. If a class * is not a runnable test case, then it's parents * wouldn't be either. This is syntactic sugar * to cut down on ommissions of ignore()'s or * missing abstract declarations. This cannot * be done whilst loading classes wiithout forcing * a particular order on the class declarations and * the ignore() calls. It's just nice to have the ignore() * calls at the top of the file before the actual declarations. * @param array $classes Class names of interest. * @static * @access public */ function ignoreParentsIfIgnored($classes) { $registry = &SimpleTest::_getRegistry(); foreach ($classes as $class) { if (SimpleTest::isIgnored($class)) { $reflection = new SimpleReflection($class); if ($parent = $reflection->getParent()) { SimpleTest::ignore($parent); } } } } /** * Test to see if a test case is in the ignore * list. Quite obviously the ignore list should * be a separate object and will be one day. * This method is internal to SimpleTest. Don't * use it. * @param string $class Class name to test. * @return boolean True if should not be run. * @access public * @static */ function isIgnored($class) { $registry = &SimpleTest::_getRegistry(); return isset($registry['IgnoreList'][strtolower($class)]); } /** * @deprecated */ function setMockBaseClass($mock_base) { $registry = &SimpleTest::_getRegistry(); $registry['MockBaseClass'] = $mock_base; } /** * @deprecated */ function getMockBaseClass() { $registry = &SimpleTest::_getRegistry(); return $registry['MockBaseClass']; } /** * Sets proxy to use on all requests for when * testing from behind a firewall. Set host * to false to disable. This will take effect * if there are no other proxy settings. * @param string $proxy Proxy host as URL. * @param string $username Proxy username for authentication. * @param string $password Proxy password for authentication. * @access public */ function useProxy($proxy, $username = false, $password = false) { $registry = &SimpleTest::_getRegistry(); $registry['DefaultProxy'] = $proxy; $registry['DefaultProxyUsername'] = $username; $registry['DefaultProxyPassword'] = $password; } /** * Accessor for default proxy host. * @return string Proxy URL. * @access public */ function getDefaultProxy() { $registry = &SimpleTest::_getRegistry(); return $registry['DefaultProxy']; } /** * Accessor for default proxy username. * @return string Proxy username for authentication. * @access public */ function getDefaultProxyUsername() { $registry = &SimpleTest::_getRegistry(); return $registry['DefaultProxyUsername']; } /** * Accessor for default proxy password. * @return string Proxy password for authentication. * @access public */ function getDefaultProxyPassword() { $registry = &SimpleTest::_getRegistry(); return $registry['DefaultProxyPassword']; } /** * Accessor for global registry of options. * @return hash All stored values. * @access private * @static */ function &_getRegistry() { static $registry = false; if (! $registry) { $registry = SimpleTest::_getDefaults(); } return $registry; } /** * Accessor for the context of the current * test run. * @return SimpleTestContext Current test run. * @access public * @static */ function &getContext() { static $context = false; if (! $context) { $context = new SimpleTestContext(); } return $context; } /** * Constant default values. * @return hash All registry defaults. * @access private * @static */ function _getDefaults() { return array( 'StubBaseClass' => 'SimpleStub', 'MockBaseClass' => 'SimpleMock', 'IgnoreList' => array(), 'DefaultProxy' => false, 'DefaultProxyUsername' => false, 'DefaultProxyPassword' => false); } } /** * Container for all components for a specific * test run. Makes things like error queues * available to PHP event handlers, and also * gets around some nasty reference issues in * the mocks. * @package SimpleTest */ class SimpleTestContext { var $_test; var $_reporter; var $_resources; /** * Clears down the current context. * @access public */ function clear() { $this->_resources = array(); } /** * Sets the current test case instance. This * global instance can be used by the mock objects * to send message to the test cases. * @param SimpleTestCase $test Test case to register. * @access public */ function setTest(&$test) { $this->clear(); $this->_test = &$test; } /** * Accessor for currently running test case. * @return SimpleTestCase Current test. * @access public */ function &getTest() { return $this->_test; } /** * Sets the current reporter. This * global instance can be used by the mock objects * to send messages. * @param SimpleReporter $reporter Reporter to register. * @access public */ function setReporter(&$reporter) { $this->clear(); $this->_reporter = &$reporter; } /** * Accessor for current reporter. * @return SimpleReporter Current reporter. * @access public */ function &getReporter() { return $this->_reporter; } /** * Accessor for the Singleton resource. * @return object Global resource. * @access public * @static */ function &get($resource) { if (! isset($this->_resources[$resource])) { $this->_resources[$resource] = &new $resource(); } return $this->_resources[$resource]; } } /** * Interrogates the stack trace to recover the * failure point. * @package SimpleTest * @subpackage UnitTester */ class SimpleStackTrace { var $_prefixes; /** * Stashes the list of target prefixes. * @param array $prefixes List of method prefixes * to search for. */ function SimpleStackTrace($prefixes) { $this->_prefixes = $prefixes; } /** * Extracts the last method name that was not within * Simpletest itself. Captures a stack trace if none given. * @param array $stack List of stack frames. * @return string Snippet of test report with line * number and file. * @access public */ function traceMethod($stack = false) { $stack = $stack ? $stack : $this->_captureTrace(); foreach ($stack as $frame) { if ($this->_frameLiesWithinSimpleTestFolder($frame)) { continue; } if ($this->_frameMatchesPrefix($frame)) { return ' at [' . $frame['file'] . ' line ' . $frame['line'] . ']'; } } return ''; } /** * Test to see if error is generated by SimpleTest itself. * @param array $frame PHP stack frame. * @return boolean True if a SimpleTest file. * @access private */ function _frameLiesWithinSimpleTestFolder($frame) { if (isset($frame['file'])) { $path = substr(SIMPLE_TEST, 0, -1); if (strpos($frame['file'], $path) === 0) { if (dirname($frame['file']) == $path) { return true; } } } return false; } /** * Tries to determine if the method call is an assert, etc. * @param array $frame PHP stack frame. * @return boolean True if matches a target. * @access private */ function _frameMatchesPrefix($frame) { foreach ($this->_prefixes as $prefix) { if (strncmp($frame['function'], $prefix, strlen($prefix)) == 0) { return true; } } return false; } /** * Grabs a current stack trace. * @return array Fulle trace. * @access private */ function _captureTrace() { if (function_exists('debug_backtrace')) { return array_reverse(debug_backtrace()); } return array(); } } /** * @package SimpleTest * @subpackage UnitTester * @deprecated */ class SimpleTestOptions extends SimpleTest { /** * @deprecated */ function getVersion() { return Simpletest::getVersion(); } /** * @deprecated */ function ignore($class) { return Simpletest::ignore($class); } /** * @deprecated */ function isIgnored($class) { return Simpletest::isIgnored($class); } /** * @deprecated */ function setMockBaseClass($mock_base) { return Simpletest::setMockBaseClass($mock_base); } /** * @deprecated */ function getMockBaseClass() { return Simpletest::getMockBaseClass(); } /** * @deprecated */ function useProxy($proxy, $username = false, $password = false) { return Simpletest::useProxy($proxy, $username, $password); } /** * @deprecated */ function getDefaultProxy() { return Simpletest::getDefaultProxy(); } /** * @deprecated */ function getDefaultProxyUsername() { return Simpletest::getDefaultProxyUsername(); } /** * @deprecated */ function getDefaultProxyPassword() { return Simpletest::getDefaultProxyPassword(); } } ?> postfixadmin-2.3.7/tests/simpletest/HELP_MY_TESTS_DONT_WORK_ANYMORE0000664000175000017620000003075111157271050024541 0ustar davidpalepurpleSimple Test interface changes ============================= Because the SimpleTest tool set is still evolving it is likely that tests written with earlier versions will fail with the newest ones. The most dramatic changes are in the alpha releases. Here is a list of possible problems and their fixes... Method setWildcard() removed in mocks ------------------------------------- Even setWildcard() has been removed in 1.0.1beta now. If you want to test explicitely for a '*' string, then simply pass in new IdenticalExpectation('*') instead. No method _getTest() on mocks ----------------------------- This has finally been removed. It was a pretty esoteric flex point anyway. It was there to allow the mocks to work with other test tools, but no one does this. No method assertError(), assertNoErrors(), swallowErrors() ---------------------------------------------------------- These have been deprecated in 1.0.1beta in favour of expectError() and expectException(). assertNoErrors() is redundant if you use expectError() as failures are now reported immediately. No method TestCase::signal() ---------------------------- This has been deprecated in favour of triggering an error or throwing an exception. Deprecated as of 1.0.1beta. No method TestCase::sendMessage() --------------------------------- This has been deprecated as of 1.0.1beta. Failure to connect now emits failures ------------------------------------- It used to be that you would have to use the getTransferError() call on the web tester to see if there was a socket level error in a fetch. This check is now always carried out by the WebTestCase unless the fetch is prefaced with WebTestCase::ignoreErrors(). The ignore directive only lasts for test case fetching action such as get() and click(). No method SimpleTestOptions::ignore() ------------------------------------- This is deprecated in version 1.0.1beta and has been moved to SimpleTest::ignore() as that is more readable. In addition, parent classes are also ignored automatically. If you are using PHP5 you can skip this directive simply by marking your test case as abstract. No method assertCopy() ---------------------- This is deprecated in 1.0.1 in favour of assertClone(). The assertClone() method is slightly different in that the objects must be identical, but without being a reference. It is thus not a strict inversion of assertReference(). Constructor wildcard override has no effect in mocks ---------------------------------------------------- As of 1.0.1beta this is now set with setWildcard() instead of in the constructor. No methods setStubBaseClass()/getStubBaseClass() ------------------------------------------------ As mocks are now used instead of stubs, these methods stopped working and are now removed as of the 1.0.1beta release. The mock objects may be freely used instead. No method addPartialMockCode() ------------------------------ The ability to insert arbitrary partial mock code has been removed. This was a low value feature causing needless complications. It was removed in the 1.0.1beta release. No method setMockBaseClass() ---------------------------- The ability to change the mock base class has been scheduled for removal and is deprecated since the 1.0.1beta version. This was a rarely used feature except as a workaround for PHP5 limitations. As these limitations are being resolved it's hoped that the bundled mocks can be used directly. No class Stub ------------- Server stubs are deprecated from 1.0.1 as the mocks now have exactly the same interface. Just use mock objects instead. No class SimpleTestOptions -------------------------- This was replced by the shorter SimpleTest in 1.0.1beta1 and is since deprecated. No file simple_test.php ----------------------- This was renamed test_case.php in 1.0.1beta to more accurately reflect it's purpose. This file should never be directly included in test suites though, as it's part of the underlying mechanics and has a tendency to be refactored. No class WantedPatternExpectation --------------------------------- This was deprecated in 1.0.1alpha in favour of the simpler name PatternExpectation. No class NoUnwantedPatternExpectation ------------------------------------- This was deprecated in 1.0.1alpha in favour of the simpler name NoPatternExpectation. No method assertNoUnwantedPattern() ----------------------------------- This has been renamed to assertNoPattern() in 1.0.1alpha and the old form is deprecated. No method assertWantedPattern() ------------------------------- This has been renamed to assertPattern() in 1.0.1alpha and the old form is deprecated. No method assertExpectation() ----------------------------- This was renamed as assert() in 1.0.1alpha and the old form has been deprecated. No class WildcardExpectation ---------------------------- This was a mostly internal class for the mock objects. It was renamed AnythingExpectation to bring it closer to JMock and NMock in version 1.0.1alpha. Missing UnitTestCase::assertErrorPattern() ------------------------------------------ This method is deprecated for version 1.0.1 onwards. This method has been subsumed by assertError() that can now take an expectation. Simply pass a PatternExpectation into assertError() to simulate the old behaviour. No HTML when matching page elements ----------------------------------- This behaviour has been switched to using plain text as if it were seen by the user of the browser. This means that HTML tags are suppressed, entities are converted and whitespace is normalised. This should make it easier to match items in forms. Also images are replaced with their "alt" text so that they can be matched as well. No method SimpleRunner::_getTestCase() -------------------------------------- This was made public as getTestCase() in 1.0RC2. No method restartSession() -------------------------- This was renamed to restart() in the WebTestCase, SimpleBrowser and the underlying SimpleUserAgent in 1.0RC2. Because it was undocumented anyway, no attempt was made at backward compatibility. My custom test case ignored by tally() -------------------------------------- The _assertTrue method has had it's signature changed due to a bug in the PHP 5.0.1 release. You must now use getTest() from within that method to get the test case. Mock compatibility with other unit testers is now deprecated as of 1.0.1alpha as PEAR::PHPUnit2 should soon have mock support of it's own. Broken code extending SimpleRunner ---------------------------------- This was replaced with SimpleScorer so that I could use the runner name in another class. This happened in RC1 development and there is no easy backward compatibility fix. The solution is simply to extend SimpleScorer instead. Missing method getBaseCookieValue() ----------------------------------- This was renamed getCurrentCookieValue() in RC1. Missing files from the SimpleTest suite --------------------------------------- Versions of SimpleTest prior to Beta6 required a SIMPLE_TEST constant to point at the SimpleTest folder location before any of the toolset was loaded. This is no longer documented as it is now unnecessary for later versions. If you are using an earlier version you may need this constant. Consult the documentation that was bundled with the release that you are using or upgrade to Beta6 or later. No method SimpleBrowser::getCurrentUrl() -------------------------------------- This is replaced with the more versatile showRequest() for debugging. It only existed in this context for version Beta5. Later versions will have SimpleBrowser::getHistory() for tracking paths through pages. It is renamed as getUrl() since 1.0RC1. No method Stub::setStubBaseClass() ---------------------------------- This method has finally been removed in 1.0RC1. Use SimpleTestOptions::setStubBaseClass() instead. No class CommandLineReporter ---------------------------- This was renamed to TextReporter in Beta3 and the deprecated version was removed in 1.0RC1. No method requireReturn() ------------------------- This was deprecated in Beta3 and is now removed. No method expectCookie() ------------------------ This method was abruptly removed in Beta4 so as to simplify the internals until another mechanism can replace it. As a workaround it is necessary to assert that the cookie has changed by setting it before the page fetch and then assert the desired value. No method clickSubmitByFormId() ------------------------------- This method had an incorrect name as no button was involved. It was renamed to submitByFormId() in Beta4 and the old version deprecated. Now removed. No method paintStart() or paintEnd() ------------------------------------ You should only get this error if you have subclassed the lower level reporting and test runner machinery. These methods have been broken down into events for test methods, events for test cases and events for group tests. The new methods are... paintStart() --> paintMethodStart(), paintCaseStart(), paintGroupStart() paintEnd() --> paintMethodEnd(), paintCaseEnd(), paintGroupEnd() This change was made in Beta3, ironically to make it easier to subclass the inner machinery. Simply duplicating the code you had in the previous methods should provide a temporary fix. No class TestDisplay -------------------- This has been folded into SimpleReporter in Beta3 and is now deprecated. It was removed in RC1. No method WebTestCase::fetch() ------------------------------ This was renamed get() in Alpha8. It is removed in Beta3. No method submit() ------------------ This has been renamed clickSubmit() in Beta1. The old method was removed in Beta2. No method clearHistory() ------------------------ This method is deprecated in Beta2 and removed in RC1. No method getCallCount() ------------------------ This method has been deprecated since Beta1 and has now been removed. There are now more ways to set expectations on counts and so this method should be unecessery. Removed in RC1. Cannot find file * ------------------ The following public name changes have occoured... simple_html_test.php --> reporter.php simple_mock.php --> mock_objects.php simple_unit.php --> unit_tester.php simple_web.php --> web_tester.php The old names were deprecated in Alpha8 and removed in Beta1. No method attachObserver() -------------------------- Prior to the Alpha8 release the old internal observer pattern was gutted and replaced with a visitor. This is to trade flexibility of test case expansion against the ease of writing user interfaces. Code such as... $test = &new MyTestCase(); $test->attachObserver(new TestHtmlDisplay()); $test->run(); ...should be rewritten as... $test = &new MyTestCase(); $test->run(new HtmlReporter()); If you previously attached multiple observers then the workaround is to run the tests twice, once with each, until they can be combined. For one observer the old method is simulated in Alpha 8, but is removed in Beta1. No class TestHtmlDisplay ------------------------ This class has been renamed to HtmlReporter in Alpha8. It is supported, but deprecated in Beta1 and removed in Beta2. If you have subclassed the display for your own design, then you will have to extend this class (HtmlReporter) instead. If you have accessed the event queue by overriding the notify() method then I am afraid you are in big trouble :(. The reporter is now carried around the test suite by the runner classes and the methods called directly. In the unlikely event that this is a problem and you don't want to upgrade the test tool then simplest is to write your own runner class and invoke the tests with... $test->accept(new MyRunner(new MyReporter())); ...rather than the run method. This should be easier to extend anyway and gives much more control. Even this method is overhauled in Beta3 where the runner class can be set within the test case. Really the best thing to do is to upgrade to this version as whatever you were trying to achieve before should now be very much easier. Missing set options method -------------------------- All test suite options are now in one class called SimpleTestOptions. This means that options are set differently... GroupTest::ignore() --> SimpleTestOptions::ignore() Mock::setMockBaseClass() --> SimpleTestOptions::setMockBaseClass() These changed in Alpha8 and the old versions are now removed in RC1. No method setExpected*() ------------------------ The mock expectations changed their names in Alpha4 and the old names ceased to be supported in Alpha8. The changes are... setExpectedArguments() --> expectArguments() setExpectedArgumentsSequence() --> expectArgumentsAt() setExpectedCallCount() --> expectCallCount() setMaximumCallCount() --> expectMaximumCallCount() The parameters remained the same. postfixadmin-2.3.7/tests/simpletest/ui/0000775000175000017620000000000012301477471020235 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/ui/css/0000775000175000017620000000000012301477471021025 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/ui/css/webunit.css0000664000175000017620000000250111157271050023203 0ustar davidpalepurplehtml { font-face: Verdana, Arial, Helvetica, sans-serif; font-weight: bold; color: black; } .pass { color: green; } .fail { color: red; } .activetab { position: relative; background: white; border-color: black; border-style: solid; border-weight: 1; border-top-color: white; border-style: solid; border-weight: 1; } .inactivetab{ position: relative; background: silver; border-color: black; border-style: solid; border-weight: 1; } span.inactivetab a:link , span.activetab a:link { text-decoration: none; color: black; } pre { background-color: lightgray; } #wait { background: #B7B8DD; position: absolute; visibility: hidden; text-align: center; border-color: blue; border-style: solid; border-weight: 2; } #webunit { position: absolute; visibility: hidden; background: silver; border-color: black; border-style: solid; border-weight: 2; } #visible_tab { position: relative; visibility: hidden; overflow: auto; background: white; width: 100%; height: 100%; border-color: black; border-style: solid; border-weight: 1; } #visible_tab a:link { text-decoration: none; color: inherit; } #msg { position: absolute; visibility: hidden; overflow: auto; background: white; border-color: black; border-style: solid; border-weight: 1; } #fail, #tree { position: absolute; visibility: hidden; } postfixadmin-2.3.7/tests/simpletest/ui/array_reporter/0000775000175000017620000000000012301477471023275 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/ui/array_reporter/sample_test.php0000664000175000017620000000050311157271050026315 0ustar davidpalepurpleassertTrue(true); } function testFalseIsTrue() { $this->assertFalse(true); } } ?>postfixadmin-2.3.7/tests/simpletest/ui/array_reporter/test.php0000664000175000017620000000341211157271050024756 0ustar davidpalepurpleaddTestFile(dirname(__FILE__) . '/sample_test.php'); $result = $test->run(new ArrayReporter()); $this->assertEqual(count($result), 2); $this->assertEqual(count($result[0]), 4); $this->assertPattern("/".substr(time(), 9)."/", $result[0]['time']); $this->assertEqual($result[0]['status'], "Passed"); $this->assertPattern("/test\.php->SampleTestForArrayReporter->testTrueIsTrue/", $result[0]['test']); $this->assertPattern("/ at \[.*array_reporter\/sample_test\.php line 7\]/", $result[0]['message']); $this->assertEqual(count($result[1]), 4); $this->assertPattern("/".substr(time(), 9)."/", $result[1]['time']); $this->assertEqual($result[1]['status'], "Failed"); $this->assertPattern("/test\.php->SampleTestForArrayReporter->testFalseIsTrue/", $result[1]['test']); $this->assertPattern("/Expected false, got \[Boolean: true\] at \[.*array_reporter\/sample_test\.php line 11\]/", $result[1]['message']); } } $test = &new GroupTest('Tests for the "array reporter"'); $test->addTestClass('TestOfArrayReporter'); if (SimpleReporter::inCli()) { $result = $test->run(new TextReporter()); return ($result ? 0 : 1); } $test->run(new HtmlReporter()); ?>postfixadmin-2.3.7/tests/simpletest/ui/js/0000775000175000017620000000000012301477471020651 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/ui/js/tests/0000775000175000017620000000000012301477471022013 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/ui/js/tests/TestOfWebunit.js.html0000664000175000017620000000204011157271050026043 0ustar davidpalepurple JsUnit Tests of webunit.js

    JsUnit Tests of webunit.js

    This page contains tests for the webunit.js file functions.

    postfixadmin-2.3.7/tests/simpletest/ui/js/x.js0000664000175000017620000003457111157271050021461 0ustar davidpalepurple// x.js // X v3.14.1, Cross-Browser DHTML Library from Cross-Browser.com // Copyright (c) 2002,2003 Michael Foster (mike@cross-browser.com) // This library is distributed under the terms of the LGPL (gnu.org) // Variables: var xVersion='3.14.1',xOp7=false,xOp5or6=false,xIE4Up=false,xNN4=false,xUA=navigator.userAgent.toLowerCase(); if(window.opera){ xOp7=(xUA.indexOf('opera 7')!=-1 || xUA.indexOf('opera/7')!=-1); if (!xOp7) xOp5or6=(xUA.indexOf('opera 5')!=-1 || xUA.indexOf('opera/5')!=-1 || xUA.indexOf('opera 6')!=-1 || xUA.indexOf('opera/6')!=-1); } else if(document.layers) {xNN4=true;} else {xIE4Up=document.all && xUA.indexOf('msie')!=-1 && parseInt(navigator.appVersion)>=4;} // Object: function xGetElementById(e) { if(typeof(e)!='string') return e; if(document.getElementById) e=document.getElementById(e); else if(document.all) e=document.all[e]; else if(document.layers) e=xLayer(e); else e=null; return e; } function xParent(e,bNode){ if (!(e=xGetElementById(e))) return null; var p=null; if (!bNode && xDef(e.offsetParent)) p=e.offsetParent; else if (xDef(e.parentNode)) p=e.parentNode; else if (xDef(e.parentElement)) p=e.parentElement; else if (xDef(e.parentLayer)){if (e.parentLayer!=window) p=e.parentLayer;} return p; } function xDef() { for(var i=0; iwindow.innerHeight) w-=16; } return w; } function xClientHeight() { var h=0; if(xOp5or6) h=window.innerHeight; else if(!window.opera && document.documentElement && document.documentElement.clientHeight) // v3.12 h=document.documentElement.clientHeight; else if(document.body && document.body.clientHeight) h=document.body.clientHeight; else if(xDef(window.innerWidth,window.innerHeight,document.width)) { h=window.innerHeight; if(document.width>window.innerWidth) h-=16; } return h; } // Animation: function xSlideTo(e,x,y,uTime) { if (!(e=xGetElementById(e))) return; if (!e.timeout) e.timeout = 25; e.xTarget = x; e.yTarget = y; e.slideTime = uTime; e.stop = false; e.yA = e.yTarget - xTop(e); e.xA = e.xTarget - xLeft(e); // A = distance e.B = Math.PI / (2 * e.slideTime); // B = period e.yD = xTop(e); e.xD = xLeft(e); // D = initial position var d = new Date(); e.C = d.getTime(); if (!e.moving) xSlide(e); } function xSlide(e) { if (!(e=xGetElementById(e))) return; var now, s, t, newY, newX; now = new Date(); t = now.getTime() - e.C; if (e.stop) { e.moving = false; } else if (t < e.slideTime) { setTimeout("xSlide('"+e.id+"')", e.timeout); s = Math.sin(e.B * t); newX = Math.round(e.xA * s + e.xD); newY = Math.round(e.yA * s + e.yD); xMoveTo(e, newX, newY); e.moving = true; } else { xMoveTo(e, e.xTarget, e.yTarget); e.moving = false; } } // Event: function xAddEventListener(e,eventType,eventListener,useCapture) { if(!(e=xGetElementById(e))) return; eventType=eventType.toLowerCase(); if((!xIE4Up && !xOp7) && e==window) { if(eventType=='resize') { window.xPCW=xClientWidth(); window.xPCH=xClientHeight(); window.xREL=eventListener; xResizeEvent(); return; } if(eventType=='scroll') { window.xPSL=xScrollLeft(); window.xPST=xScrollTop(); window.xSEL=eventListener; xScrollEvent(); return; } } var eh='e.on'+eventType+'=eventListener'; if(e.addEventListener) e.addEventListener(eventType,eventListener,useCapture); else if(e.attachEvent) e.attachEvent('on'+eventType,eventListener); else if(e.captureEvents) { if(useCapture||(eventType.indexOf('mousemove')!=-1)) { e.captureEvents(eval('Event.'+eventType.toUpperCase())); } eval(eh); } else eval(eh); } function xRemoveEventListener(e,eventType,eventListener,useCapture) { if(!(e=xGetElementById(e))) return; eventType=eventType.toLowerCase(); if((!xIE4Up && !xOp7) && e==window) { if(eventType=='resize') { window.xREL=null; return; } if(eventType=='scroll') { window.xSEL=null; return; } } var eh='e.on'+eventType+'=null'; if(e.removeEventListener) e.removeEventListener(eventType,eventListener,useCapture); else if(e.detachEvent) e.detachEvent('on'+eventType,eventListener); else if(e.releaseEvents) { if(useCapture||(eventType.indexOf('mousemove')!=-1)) { e.releaseEvents(eval('Event.'+eventType.toUpperCase())); } eval(eh); } else eval(eh); } function xEvent(evt) { // cross-browser event object prototype this.type = ''; this.target = null; this.pageX = 0; this.pageY = 0; this.offsetX = 0; this.offsetY = 0; this.keyCode = 0; var e = evt ? evt : window.event; if(!e) return; if(e.type) this.type = e.type; if(e.target) this.target = e.target; else if(e.srcElement) this.target = e.srcElement; else if(xNN4) this.target = xLayerFromPoint(e.pageX, e.pageY); if(xOp5or6) { this.pageX = e.clientX; this.pageY = e.clientY; } else if(xDef(e.pageX,e.pageY)) { this.pageX = e.pageX; this.pageY = e.pageY; } // v3.14 else if(xDef(e.clientX,e.clientY)) { this.pageX = e.clientX + xScrollLeft(); this.pageY = e.clientY + xScrollTop(); } if(xDef(e.offsetX,e.offsetY)) { this.offsetX = e.offsetX; this.offsetY = e.offsetY; } else if(xDef(e.layerX,e.layerY)) { this.offsetX = e.layerX; this.offsetY = e.layerY; } else { this.offsetX = this.pageX - xPageX(this.target); this.offsetY = this.pageY - xPageY(this.target); } if (e.keyCode) { this.keyCode = e.keyCode; } // for moz/fb, if keyCode==0 use which else if (xDef(e.which)) { this.keyCode = e.which; } } function xResizeEvent() { // window resize event simulation if (window.xREL) setTimeout('xResizeEvent()', 250); var cw = xClientWidth(), ch = xClientHeight(); if (window.xPCW != cw || window.xPCH != ch) { window.xPCW = cw; window.xPCH = ch; if (window.xREL) window.xREL(); } } function xScrollEvent() { // window scroll event simulation if (window.xSEL) setTimeout('xScrollEvent()', 250); var sl = xScrollLeft(), st = xScrollTop(); if (window.xPSL != sl || window.xPST != st) { window.xPSL = sl; window.xPST = st; if (window.xSEL) window.xSEL(); } } // end x.js postfixadmin-2.3.7/tests/simpletest/ui/js/webunit.js0000664000175000017620000001202111157271050022651 0ustar davidpalepurple// jsreporter.js // Script to support JsReporter class // Relies heavily on the X library in x.js // X v3.14.1, Cross-Browser DHTML Library from Cross-Browser.com // Copyright (c) 2004 Jason E. Sweat (jsweat_php@yahoo.com) // // SimpleTest - http://simpletest.sf.net/ // Copyright (c) 2003,2004 Marcus Baker (marcus@lastcraft.com) // $Id: webunit.js,v 1.10 2004/02/14 18:24:13 jsweat Exp $ // Variables: min_x=500; min_y=400; groups = new Array(); cases = new Array(); methods = new Array(); current_group=0; current_case=0; current_method=0; Hash = { Set : function(foo,bar) {this[foo] = bar;}, Get : function(foo) {return this[foo];} } // Functions: function wait_start() { var wait_x; var wait_y; wait_x = xWidth('wait'); wait_y = xHeight('wait'); xMoveTo('wait', (xClientWidth()-wait_x)/2, (xClientHeight()-wait_y)/2); xShow('wait'); } function layout() { xResizeTo('webunit', max(xClientWidth()-30,min_x), max(xClientHeight()-20,min_y)); xMoveTo('webunit', 5, 5); xResizeTo('tabs', xWidth('webunit')-10, xHeight('webunit')/3); xLeft('tabs', 5); xShow('webunit'); xShow('tabs'); activate_tab('fail'); xShow('visible_tab'); xZIndex('visible_tab', 2) xResizeTo('msg', xWidth('webunit')-17, xHeight('webunit')/3-20); xLeft('msg', 2); xTop('msg',2*xHeight('webunit')/3); xShow('msg'); } function set_div_content(div, content) { xGetElementById(div).innerHTML = content; } function copy_div_content(divsrc, divtrgt) { xGetElementById(divtrgt).innerHTML = xGetElementById(divsrc).innerHTML; } function activate_tab(tab) { if (tab == 'fail') { copy_div_content('fail', 'visible_tab'); xGetElementById('failtab').className = 'activetab'; xZIndex('failtab', 3) xGetElementById('treetab').className = 'inactivetab'; xZIndex('treetab', 1) } if (tab == 'tree') { copy_div_content('tree', 'visible_tab'); xGetElementById('failtab').className = 'inactivetab'; xZIndex('failtab', 1) xGetElementById('treetab').className = 'activetab'; xZIndex('treetab', 3) } } function add_group(group_name) { var add; add = { Set : function(foo,bar) {this[foo] = bar;}, Get : function(foo) {return this[foo];} } add.Set('desc', group_name); add.Set('pass', true); groups[groups.length] = add; current_group = groups.length - 1; cases[current_group] = new Array(); methods[current_group] = new Array(); } function add_case(case_name) { var curgroup; var add; add = { Set : function(foo,bar) {this[foo] = bar;}, Get : function(foo) {return this[foo];} } add.Set('desc', case_name); add.Set('pass', true); curgroup = cases[current_group]; cases[current_group][curgroup.length] = add; current_case = curgroup.length - 1; methods[current_group][current_case] = new Array(); } function add_method(method_name) { var curcase; var add; add = { Set : function(foo,bar) {this[foo] = bar;}, Get : function(foo) {return this[foo];} } add.Set('desc', method_name); add.Set('pass', true); add.Set('msg',''); curcase = methods[current_group][current_case]; methods[current_group][current_case][curcase.length] = add; current_method = curcase.length - 1; } function add_fail(msg) { var oldmsg; add_log(msg); groups[current_group].Set('pass', false); cases[current_group][current_case].Set('pass', false); methods[current_group][current_case][current_method].Set('pass', false); oldmsg = methods[current_group][current_case][current_method].Get('msg'); methods[current_group][current_case][current_method].Set('msg', oldmsg+msg); } function add_log(msg) { var faildiv; faildiv = xGetElementById('fail'); faildiv.innerHTML = faildiv.innerHTML + msg; } function set_msg(gid, cid, mid) { var passfail; var msg=methods[gid][cid][mid].Get('msg'); if ('' == msg) { passfail = (methods[gid][cid][mid].Get('pass')) ? 'pass' : 'fail'; msg = 'No output for ' + groups[gid].Get('desc') + '->' + cases[gid][cid].Get('desc') + '->' + methods[gid][cid][mid].Get('desc') + '
    '; } xGetElementById('msg').innerHTML = msg; } function make_tree() { var content; var passfail; content = '
      '; for (x in groups) { passfail = (groups[x].Get('pass')) ? 'pass' : 'fail'; content += '
    • '+groups[x].Get('desc')+'
        '; for (y in cases[x]) { passfail = (cases[x][y].Get('pass')) ? 'pass' : 'fail'; content += '
      • '+cases[x][y].Get('desc')+'
      • '; } content += '
    • '; } content += '
    '; xGetElementById('tree').innerHTML = content; if (xGetElementById('treetab').className == 'activetab') { activate_tab('tree'); } else { activate_tab('fail'); } } function make_output(data) { } function make_fail_msg(id, msg) { } function max(n1, n2) { if (n1 > n2) { return n1; } else { return n2; } } postfixadmin-2.3.7/tests/simpletest/ui/img/0000775000175000017620000000000012301477471021011 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/ui/img/wait.gif0000664000175000017620000000262211157271050022437 0ustar davidpalepurpleGIF89a?>~!=} >~#=|%={&[QھD_acegikmoqsuwy{ 4СD.D @" 8iȱLBIrK! ,@N@pH,Ȥl:LtZVR Vr~}F;_ԣD~gTbKd]oA! ,@pH,Ȥrl:ШtJZXk! ,2@pH,Ȥrl:ШtJZXk! ,I@pH,Ȥrl:ШtJZXk! ,`@pH,Ȥrl:ШtJZXk! ,w@pH,Ȥrl:ШtJZXk! ,@pH,Ȥrl:ШtJZXk! ,@pH,Ȥrl:ШtJZXk! , @pH,Ȥrl: ! ,@pH,Ȥrl:ШtJZXk! ,."@pH,Ȥrl:ШtJZجvzx ! ,I@pH,Ȥrl:ШtJZXk! ,`@pH,Ȥrl:ШtJZXk! ,w@pH,Ȥrl:ШtJZXk! ,@pH,Ȥrl:ШtJZXk! ,Պzb0ljj5fv X0"QX(D<}@ #!!"%$&&''+>>Ɵɱ<ϸ=םb- ,;postfixadmin-2.3.7/tests/simpletest/ui/webunit_reporter.php0000664000175000017620000002267711157271050024354 0ustar davidpalepurple %s

     Running %s 

    Please wait...

     

    visible tab content
        Fail     Tree  
    Click on a failed test case method in the tree tab to view output here.
    '.$this->outputScript("xHide('wait');"); $colour = ($this->getFailCount() + $this->getExceptionCount() > 0 ? "red" : "green"); $content = "

    $test_name

    \n"; $content .= "
    "; $content .= $this->getTestCaseProgress() . "/" . $this->getTestCaseCount(); $content .= " test cases complete:\n"; $content .= "" . $this->getPassCount() . " passes, "; $content .= "" . $this->getFailCount() . " fails and "; $content .= "" . $this->getExceptionCount() . " exceptions."; $content .= "
    \n"; echo $this->outputScript('foo = "'.$this->toJsString($content).'";'."\nset_div_content('run', foo);"); echo "\n\n\n"; } /** * Paints formatted text such as dumped variables. * @param string $message Text to show. * @access public */ function paintFormattedMessage($message) { echo "add_log(\"".$this->toJsString("
    $message
    ", true)."\");\n"; } /** * Paints the start of a group test. Will also paint * the page header and footer if this is the * first test. Will stash the size if the first * start. * @param string $test_name Name of test that is starting. * @param integer $size Number of test cases starting. * @access public */ function paintGroupStart($test_name, $size) { Parent::paintGroupStart($test_name, $size); echo "add_group('$test_name');\n"; } /** * Paints the start of a test case. Will also paint * the page header and footer if this is the * first test. Will stash the size if the first * start. * @param string $test_name Name of test that is starting. * @access public */ function paintCaseStart($test_name) { Parent::paintCaseStart($test_name); echo "add_case('$test_name');\n"; } /** * Paints the start of a test method. * @param string $test_name Name of test that is starting. * @access public */ function paintMethodStart($test_name) { Parent::paintMethodStart($test_name); echo "add_method('$test_name');\n"; } /** * Paints the end of a test method. * @param string $test_name Name of test that is ending. * @access public */ function paintMethodEnd($test_name) { Parent::paintMethodEnd($test_name); } /** * Paints the test failure with a breadcrumbs * trail of the nesting test suites below the * top level test. * @param string $message Failure message displayed in * the context of the other tests. * @access public */ function paintFail($message) { parent::paintFail($message); $msg = "Fail: "; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); $msg .= implode("->", $breadcrumb); $msg .= "->" . htmlentities($message) . "
    "; echo "add_fail('$msg');\n"; } /** * Paints a PHP error or exception. * @param string $message Message is ignored. * @access public * @abstract */ function paintException($message) { parent::paintException($message); $msg = "Exception: "; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); $msg .= implode("->", $breadcrumb); $msg .= "->" . htmlentities($message) . "
    "; echo "add_fail('$msg');\n"; } /** * Returns the script passed in wrapped in script tags. * * @param string $script the script to output * @return string the script wrapped with script tags */ function outputScript($script) { return "\n"; } /** * Transform a string into a format acceptable to JavaScript * @param string $str the string to transform * @return string */ function toJsString($str, $preserveCr=false) { $cr = ($preserveCr) ? '\\n' : ''; return str_replace( array('"' ,"\n") ,array('\"' ,"$cr\"\n\t+\"") ,$str ); } } ?>postfixadmin-2.3.7/tests/simpletest/ui/array_reporter.php0000664000175000017620000000330611157271050024001 0ustar davidpalepurpleSimpleReporter(); $this->_results = array(); } function paintPass($message) { parent::paintPass($message); $breadcrumb = $this->getTestList(); array_shift($breadcrumb); $test = implode("->", $breadcrumb); $result["time"] = time(); $result["status"] = "Passed"; $result["test"] = $test; $result["message"] = $message; $this->_results[] = $result; } function paintFail($message) { parent::paintFail($message); $breadcrumb = $this->getTestList(); array_shift($breadcrumb); $test = implode("->", $breadcrumb); $result["time"] = time(); $result["status"] = "Failed"; $result["test"] = $test; $result["message"] = $message; $this->_results[] = $result; } function getStatus() { return $this->_results; } } ?>postfixadmin-2.3.7/tests/simpletest/ui/colortext_reporter.php0000664000175000017620000000400611157271050024704 0ustar davidpalepurple * @package SimpleTest * @subpackage UnitTester */ class ColorTextReporter extends TextReporter { var $_failColor = 41; var $_passColor = 42; /** * Handle initialization * * @param {@link TextReporter} */ function ColorTextReporter() { parent::TextReporter(); } /** * Capture the attempt to display the final test results and insert the * ANSI-color codes in place. * * @param string * @see TextReporter * @access public */ function paintFooter($test_name) { ob_start(); parent::paintFooter($test_name); $output = trim(ob_get_clean()); if ($output) { if (($this->getFailCount() + $this->getExceptionCount()) == 0) { $color = $this->_passColor; } else { $color = $this->_failColor; } $this->_setColor($color); echo $output; $this->_resetColor(); } } /** * Sets the terminal to an ANSI-standard $color * * @param int * @access protected */ function _setColor($color) { printf("%s[%sm\n", chr(27), $color); } /** * Resets the color back to normal. * * @access protected */ function _resetColor() { $this->_setColor(0); } } postfixadmin-2.3.7/tests/simpletest/reflection_php5.php0000664000175000017620000002456311157271050023422 0ustar davidpalepurple_interface = $interface; } /** * Checks that a class has been declared. Versions * before PHP5.0.2 need a check that it's not really * an interface. * @return boolean True if defined. * @access public */ function classExists() { if (! class_exists($this->_interface)) { return false; } $reflection = new ReflectionClass($this->_interface); return ! $reflection->isInterface(); } /** * Needed to kill the autoload feature in PHP5 * for classes created dynamically. * @return boolean True if defined. * @access public */ function classExistsSansAutoload() { return class_exists($this->_interface, false); } /** * Checks that a class or interface has been * declared. * @return boolean True if defined. * @access public */ function classOrInterfaceExists() { return $this->_classOrInterfaceExistsWithAutoload($this->_interface, true); } /** * Needed to kill the autoload feature in PHP5 * for classes created dynamically. * @return boolean True if defined. * @access public */ function classOrInterfaceExistsSansAutoload() { return $this->_classOrInterfaceExistsWithAutoload($this->_interface, false); } /** * Needed to select the autoload feature in PHP5 * for classes created dynamically. * @param string $interface Class or interface name. * @param boolean $autoload True totriggerautoload. * @return boolean True if interface defined. * @access private */ function _classOrInterfaceExistsWithAutoload($interface, $autoload) { if (function_exists('interface_exists')) { if (interface_exists($this->_interface, $autoload)) { return true; } } return class_exists($this->_interface, $autoload); } /** * Gets the list of methods on a class or * interface. Needs to recursively look at all of * the interfaces included. * @returns array List of method names. * @access public */ function getMethods() { return array_unique(get_class_methods($this->_interface)); } /** * Gets the list of interfaces from a class. If the * class name is actually an interface then just that * interface is returned. * @returns array List of interfaces. * @access public */ function getInterfaces() { $reflection = new ReflectionClass($this->_interface); if ($reflection->isInterface()) { return array($this->_interface); } return $this->_onlyParents($reflection->getInterfaces()); } /** * Gets the list of methods for the implemented * interfaces only. * @returns array List of enforced method signatures. * @access public */ function getInterfaceMethods() { $methods = array(); foreach ($this->getInterfaces() as $interface) { $methods = array_merge($methods, get_class_methods($interface)); } return array_unique($methods); } /** * Checks to see if the method signature has to be tightly * specified. * @param string $method Method name. * @returns boolean True if enforced. * @access private */ function _isInterfaceMethod($method) { return in_array($method, $this->getInterfaceMethods()); } /** * Finds the parent class name. * @returns string Parent class name. * @access public */ function getParent() { $reflection = new ReflectionClass($this->_interface); $parent = $reflection->getParentClass(); if ($parent) { return $parent->getName(); } return false; } /** * Determines if the class is abstract. * @returns boolean True if abstract. * @access public */ function isAbstract() { $reflection = new ReflectionClass($this->_interface); return $reflection->isAbstract(); } /** * Determines if the class is an interface. * @returns boolean True if interface. * @access public */ function isInterface() { $reflection = new ReflectionClass($this->_interface); return $reflection->isInterface(); } /** * Whittles a list of interfaces down to only the top * level parents. * @param array $interfaces Reflection API interfaces * to reduce. * @returns array List of parent interface names. * @access private */ function _onlyParents($interfaces) { $parents = array(); $blacklist = array(); foreach ($interfaces as $interface) { foreach($interfaces as $possible_parent) { if ($interface->getName() == $possible_parent->getName()) { continue; } if ($interface->isSubClassOf($possible_parent)) { $blacklist[$possible_parent->getName()] = true; } } if (!isset($blacklist[$interface->getName()])) { $parents[] = $interface->getName(); } } return $parents; } /** * Gets the source code matching the declaration * of a method. * @param string $name Method name. * @return string Method signature up to last * bracket. * @access public */ function getSignature($name) { if ($name == '__set') { return 'function __set($key, $value)'; } if ($name == '__call') { return 'function __call($method, $arguments)'; } if (version_compare(phpversion(), '5.1.0', '>=')) { if (in_array($name, array('__get', '__isset', $name == '__unset'))) { return "function {$name}(\$key)"; } } if (! is_callable(array($this->_interface, $name))) { return "function $name()"; } if ($this->_isInterfaceMethod($name)) { return $this->_getFullSignature($name); } return "function $name()"; } /** * For a signature specified in an interface, full * details must be replicated to be a valid implementation. * @param string $name Method name. * @return string Method signature up to last * bracket. * @access private */ function _getFullSignature($name) { $interface = new ReflectionClass($this->_interface); $method = $interface->getMethod($name); $reference = $method->returnsReference() ? '&' : ''; return "function $reference$name(" . implode(', ', $this->_getParameterSignatures($method)) . ")"; } /** * Gets the source code for each parameter. * @param ReflectionMethod $method Method object from * reflection API * @return array List of strings, each * a snippet of code. * @access private */ function _getParameterSignatures($method) { $signatures = array(); foreach ($method->getParameters() as $parameter) { $type = $parameter->getClass(); $signatures[] = (! is_null($type) ? $type->getName() . ' ' : '') . ($parameter->isPassedByReference() ? '&' : '') . '$' . $this->_suppressSpurious($parameter->getName()) . ($this->_isOptional($parameter) ? ' = null' : ''); } return $signatures; } /** * The SPL library has problems with the * Reflection library. In particular, you can * get extra characters in parameter names :(. * @param string $name Parameter name. * @return string Cleaner name. * @access private */ function _suppressSpurious($name) { return str_replace(array('[', ']', ' '), '', $name); } /** * Test of a reflection parameter being optional * that works with early versions of PHP5. * @param reflectionParameter $parameter Is this optional. * @return boolean True if optional. * @access private */ function _isOptional($parameter) { if (method_exists($parameter, 'isOptional')) { return $parameter->isOptional(); } return false; } } ?> postfixadmin-2.3.7/tests/simpletest/TODO0000664000175000017620000000072211157271050020302 0ustar davidpalepurpleTODO This is immediate stuff only for this iteration (1.0.1beta2) of 15 hours. $Id: TODO,v 1.508 2007/01/16 23:35:21 lastcraft Exp $ Unit tester ----------- Fix errors_test.php in PHP 5.2+ (2). Reporter -------- Dumper should be passed in testMessage() call to expectation (3). Mock objects ------------ Mocks should inherit mocked class (9/4). Parser ------ Browser ------- Web tester ---------- Documentation ------------- Update roadmap (1). Build ----- postfixadmin-2.3.7/tests/simpletest/page.php0000664000175000017620000007730111157271050021246 0ustar davidpalepurple 'SimpleAnchorTag', 'title' => 'SimpleTitleTag', 'button' => 'SimpleButtonTag', 'textarea' => 'SimpleTextAreaTag', 'option' => 'SimpleOptionTag', 'label' => 'SimpleLabelTag', 'form' => 'SimpleFormTag', 'frame' => 'SimpleFrameTag'); $attributes = $this->_keysToLowerCase($attributes); if (array_key_exists($name, $map)) { $tag_class = $map[$name]; return new $tag_class($attributes); } elseif ($name == 'select') { return $this->_createSelectionTag($attributes); } elseif ($name == 'input') { return $this->_createInputTag($attributes); } return new SimpleTag($name, $attributes); } /** * Factory for selection fields. * @param hash $attributes Element attributes. * @return SimpleTag Tag object. * @access protected */ function _createSelectionTag($attributes) { if (isset($attributes['multiple'])) { return new MultipleSelectionTag($attributes); } return new SimpleSelectionTag($attributes); } /** * Factory for input tags. * @param hash $attributes Element attributes. * @return SimpleTag Tag object. * @access protected */ function _createInputTag($attributes) { if (! isset($attributes['type'])) { return new SimpleTextTag($attributes); } $type = strtolower(trim($attributes['type'])); $map = array( 'submit' => 'SimpleSubmitTag', 'image' => 'SimpleImageSubmitTag', 'checkbox' => 'SimpleCheckboxTag', 'radio' => 'SimpleRadioButtonTag', 'text' => 'SimpleTextTag', 'hidden' => 'SimpleTextTag', 'password' => 'SimpleTextTag', 'file' => 'SimpleUploadTag'); if (array_key_exists($type, $map)) { $tag_class = $map[$type]; return new $tag_class($attributes); } return false; } /** * Make the keys lower case for case insensitive look-ups. * @param hash $map Hash to convert. * @return hash Unchanged values, but keys lower case. * @access private */ function _keysToLowerCase($map) { $lower = array(); foreach ($map as $key => $value) { $lower[strtolower($key)] = $value; } return $lower; } } /** * SAX event handler. Maintains a list of * open tags and dispatches them as they close. * @package SimpleTest * @subpackage WebTester */ class SimplePageBuilder extends SimpleSaxListener { var $_tags; var $_page; var $_private_content_tag; /** * Sets the builder up empty. * @access public */ function SimplePageBuilder() { $this->SimpleSaxListener(); } /** * Frees up any references so as to allow the PHP garbage * collection from unset() to work. * @access public */ function free() { unset($this->_tags); unset($this->_page); unset($this->_private_content_tags); } /** * Reads the raw content and send events * into the page to be built. * @param $response SimpleHttpResponse Fetched response. * @return SimplePage Newly parsed page. * @access public */ function &parse($response) { $this->_tags = array(); $this->_page = &$this->_createPage($response); $parser = &$this->_createParser($this); $parser->parse($response->getContent()); $this->_page->acceptPageEnd(); return $this->_page; } /** * Creates an empty page. * @return SimplePage New unparsed page. * @access protected */ function &_createPage($response) { $page = &new SimplePage($response); return $page; } /** * Creates the parser used with the builder. * @param $listener SimpleSaxListener Target of parser. * @return SimpleSaxParser Parser to generate * events for the builder. * @access protected */ function &_createParser(&$listener) { $parser = &new SimpleHtmlSaxParser($listener); return $parser; } /** * Start of element event. Opens a new tag. * @param string $name Element name. * @param hash $attributes Attributes without content * are marked as true. * @return boolean False on parse error. * @access public */ function startElement($name, $attributes) { $factory = &new SimpleTagBuilder(); $tag = $factory->createTag($name, $attributes); if (! $tag) { return true; } if ($tag->getTagName() == 'label') { $this->_page->acceptLabelStart($tag); $this->_openTag($tag); return true; } if ($tag->getTagName() == 'form') { $this->_page->acceptFormStart($tag); return true; } if ($tag->getTagName() == 'frameset') { $this->_page->acceptFramesetStart($tag); return true; } if ($tag->getTagName() == 'frame') { $this->_page->acceptFrame($tag); return true; } if ($tag->isPrivateContent() && ! isset($this->_private_content_tag)) { $this->_private_content_tag = &$tag; } if ($tag->expectEndTag()) { $this->_openTag($tag); return true; } $this->_page->acceptTag($tag); return true; } /** * End of element event. * @param string $name Element name. * @return boolean False on parse error. * @access public */ function endElement($name) { if ($name == 'label') { $this->_page->acceptLabelEnd(); return true; } if ($name == 'form') { $this->_page->acceptFormEnd(); return true; } if ($name == 'frameset') { $this->_page->acceptFramesetEnd(); return true; } if ($this->_hasNamedTagOnOpenTagStack($name)) { $tag = array_pop($this->_tags[$name]); if ($tag->isPrivateContent() && $this->_private_content_tag->getTagName() == $name) { unset($this->_private_content_tag); } $this->_addContentTagToOpenTags($tag); $this->_page->acceptTag($tag); return true; } return true; } /** * Test to see if there are any open tags awaiting * closure that match the tag name. * @param string $name Element name. * @return boolean True if any are still open. * @access private */ function _hasNamedTagOnOpenTagStack($name) { return isset($this->_tags[$name]) && (count($this->_tags[$name]) > 0); } /** * Unparsed, but relevant data. The data is added * to every open tag. * @param string $text May include unparsed tags. * @return boolean False on parse error. * @access public */ function addContent($text) { if (isset($this->_private_content_tag)) { $this->_private_content_tag->addContent($text); } else { $this->_addContentToAllOpenTags($text); } return true; } /** * Any content fills all currently open tags unless it * is part of an option tag. * @param string $text May include unparsed tags. * @access private */ function _addContentToAllOpenTags($text) { foreach (array_keys($this->_tags) as $name) { for ($i = 0, $count = count($this->_tags[$name]); $i < $count; $i++) { $this->_tags[$name][$i]->addContent($text); } } } /** * Parsed data in tag form. The parsed tag is added * to every open tag. Used for adding options to select * fields only. * @param SimpleTag $tag Option tags only. * @access private */ function _addContentTagToOpenTags(&$tag) { if ($tag->getTagName() != 'option') { return; } foreach (array_keys($this->_tags) as $name) { for ($i = 0, $count = count($this->_tags[$name]); $i < $count; $i++) { $this->_tags[$name][$i]->addTag($tag); } } } /** * Opens a tag for receiving content. Multiple tags * will be receiving input at the same time. * @param SimpleTag $tag New content tag. * @access private */ function _openTag(&$tag) { $name = $tag->getTagName(); if (! in_array($name, array_keys($this->_tags))) { $this->_tags[$name] = array(); } $this->_tags[$name][] = &$tag; } } /** * A wrapper for a web page. * @package SimpleTest * @subpackage WebTester */ class SimplePage { var $_links; var $_title; var $_last_widget; var $_label; var $_left_over_labels; var $_open_forms; var $_complete_forms; var $_frameset; var $_frames; var $_frameset_nesting_level; var $_transport_error; var $_raw; var $_text; var $_sent; var $_headers; var $_method; var $_url; var $_request_data; /** * Parses a page ready to access it's contents. * @param SimpleHttpResponse $response Result of HTTP fetch. * @access public */ function SimplePage($response = false) { $this->_links = array(); $this->_title = false; $this->_left_over_labels = array(); $this->_open_forms = array(); $this->_complete_forms = array(); $this->_frameset = false; $this->_frames = array(); $this->_frameset_nesting_level = 0; $this->_text = false; if ($response) { $this->_extractResponse($response); } else { $this->_noResponse(); } } /** * Extracts all of the response information. * @param SimpleHttpResponse $response Response being parsed. * @access private */ function _extractResponse($response) { $this->_transport_error = $response->getError(); $this->_raw = $response->getContent(); $this->_sent = $response->getSent(); $this->_headers = $response->getHeaders(); $this->_method = $response->getMethod(); $this->_url = $response->getUrl(); $this->_request_data = $response->getRequestData(); } /** * Sets up a missing response. * @access private */ function _noResponse() { $this->_transport_error = 'No page fetched yet'; $this->_raw = false; $this->_sent = false; $this->_headers = false; $this->_method = 'GET'; $this->_url = false; $this->_request_data = false; } /** * Original request as bytes sent down the wire. * @return mixed Sent content. * @access public */ function getRequest() { return $this->_sent; } /** * Accessor for raw text of page. * @return string Raw unparsed content. * @access public */ function getRaw() { return $this->_raw; } /** * Accessor for plain text of page as a text browser * would see it. * @return string Plain text of page. * @access public */ function getText() { if (! $this->_text) { $this->_text = SimpleHtmlSaxParser::normalise($this->_raw); } return $this->_text; } /** * Accessor for raw headers of page. * @return string Header block as text. * @access public */ function getHeaders() { if ($this->_headers) { return $this->_headers->getRaw(); } return false; } /** * Original request method. * @return string GET, POST or HEAD. * @access public */ function getMethod() { return $this->_method; } /** * Original resource name. * @return SimpleUrl Current url. * @access public */ function getUrl() { return $this->_url; } /** * Original request data. * @return mixed Sent content. * @access public */ function getRequestData() { return $this->_request_data; } /** * Accessor for last error. * @return string Error from last response. * @access public */ function getTransportError() { return $this->_transport_error; } /** * Accessor for current MIME type. * @return string MIME type as string; e.g. 'text/html' * @access public */ function getMimeType() { if ($this->_headers) { return $this->_headers->getMimeType(); } return false; } /** * Accessor for HTTP response code. * @return integer HTTP response code received. * @access public */ function getResponseCode() { if ($this->_headers) { return $this->_headers->getResponseCode(); } return false; } /** * Accessor for last Authentication type. Only valid * straight after a challenge (401). * @return string Description of challenge type. * @access public */ function getAuthentication() { if ($this->_headers) { return $this->_headers->getAuthentication(); } return false; } /** * Accessor for last Authentication realm. Only valid * straight after a challenge (401). * @return string Name of security realm. * @access public */ function getRealm() { if ($this->_headers) { return $this->_headers->getRealm(); } return false; } /** * Accessor for current frame focus. Will be * false as no frames. * @return array Always empty. * @access public */ function getFrameFocus() { return array(); } /** * Sets the focus by index. The integer index starts from 1. * @param integer $choice Chosen frame. * @return boolean Always false. * @access public */ function setFrameFocusByIndex($choice) { return false; } /** * Sets the focus by name. Always fails for a leaf page. * @param string $name Chosen frame. * @return boolean False as no frames. * @access public */ function setFrameFocus($name) { return false; } /** * Clears the frame focus. Does nothing for a leaf page. * @access public */ function clearFrameFocus() { } /** * Adds a tag to the page. * @param SimpleTag $tag Tag to accept. * @access public */ function acceptTag(&$tag) { if ($tag->getTagName() == "a") { $this->_addLink($tag); } elseif ($tag->getTagName() == "title") { $this->_setTitle($tag); } elseif ($this->_isFormElement($tag->getTagName())) { for ($i = 0; $i < count($this->_open_forms); $i++) { $this->_open_forms[$i]->addWidget($tag); } $this->_last_widget = &$tag; } } /** * Opens a label for a described widget. * @param SimpleFormTag $tag Tag to accept. * @access public */ function acceptLabelStart(&$tag) { $this->_label = &$tag; unset($this->_last_widget); } /** * Closes the most recently opened label. * @access public */ function acceptLabelEnd() { if (isset($this->_label)) { if (isset($this->_last_widget)) { $this->_last_widget->setLabel($this->_label->getText()); unset($this->_last_widget); } else { $this->_left_over_labels[] = SimpleTestCompatibility::copy($this->_label); } unset($this->_label); } } /** * Tests to see if a tag is a possible form * element. * @param string $name HTML element name. * @return boolean True if form element. * @access private */ function _isFormElement($name) { return in_array($name, array('input', 'button', 'textarea', 'select')); } /** * Opens a form. New widgets go here. * @param SimpleFormTag $tag Tag to accept. * @access public */ function acceptFormStart(&$tag) { $this->_open_forms[] = &new SimpleForm($tag, $this->getUrl()); } /** * Closes the most recently opened form. * @access public */ function acceptFormEnd() { if (count($this->_open_forms)) { $this->_complete_forms[] = array_pop($this->_open_forms); } } /** * Opens a frameset. A frameset may contain nested * frameset tags. * @param SimpleFramesetTag $tag Tag to accept. * @access public */ function acceptFramesetStart(&$tag) { if (! $this->_isLoadingFrames()) { $this->_frameset = &$tag; } $this->_frameset_nesting_level++; } /** * Closes the most recently opened frameset. * @access public */ function acceptFramesetEnd() { if ($this->_isLoadingFrames()) { $this->_frameset_nesting_level--; } } /** * Takes a single frame tag and stashes it in * the current frame set. * @param SimpleFrameTag $tag Tag to accept. * @access public */ function acceptFrame(&$tag) { if ($this->_isLoadingFrames()) { if ($tag->getAttribute('src')) { $this->_frames[] = &$tag; } } } /** * Test to see if in the middle of reading * a frameset. * @return boolean True if inframeset. * @access private */ function _isLoadingFrames() { if (! $this->_frameset) { return false; } return ($this->_frameset_nesting_level > 0); } /** * Test to see if link is an absolute one. * @param string $url Url to test. * @return boolean True if absolute. * @access protected */ function _linkIsAbsolute($url) { $parsed = new SimpleUrl($url); return (boolean)($parsed->getScheme() && $parsed->getHost()); } /** * Adds a link to the page. * @param SimpleAnchorTag $tag Link to accept. * @access protected */ function _addLink($tag) { $this->_links[] = $tag; } /** * Marker for end of complete page. Any work in * progress can now be closed. * @access public */ function acceptPageEnd() { while (count($this->_open_forms)) { $this->_complete_forms[] = array_pop($this->_open_forms); } foreach ($this->_left_over_labels as $label) { for ($i = 0, $count = count($this->_complete_forms); $i < $count; $i++) { $this->_complete_forms[$i]->attachLabelBySelector( new SimpleById($label->getFor()), $label->getText()); } } } /** * Test for the presence of a frameset. * @return boolean True if frameset. * @access public */ function hasFrames() { return (boolean)$this->_frameset; } /** * Accessor for frame name and source URL for every frame that * will need to be loaded. Immediate children only. * @return boolean/array False if no frameset or * otherwise a hash of frame URLs. * The key is either a numerical * base one index or the name attribute. * @access public */ function getFrameset() { if (! $this->_frameset) { return false; } $urls = array(); for ($i = 0; $i < count($this->_frames); $i++) { $name = $this->_frames[$i]->getAttribute('name'); $url = new SimpleUrl($this->_frames[$i]->getAttribute('src')); $urls[$name ? $name : $i + 1] = $url->makeAbsolute($this->getUrl()); } return $urls; } /** * Fetches a list of loaded frames. * @return array/string Just the URL for a single page. * @access public */ function getFrames() { $url = $this->getUrl(); return $url->asString(); } /** * Accessor for a list of all fixed links. * @return array List of urls with scheme of * http or https and hostname. * @access public */ function getAbsoluteUrls() { $all = array(); foreach ($this->_links as $link) { if ($this->_linkIsAbsolute($link->getHref())) { $all[] = $link->getHref(); } } return $all; } /** * Accessor for a list of all relative links. * @return array List of urls without hostname. * @access public */ function getRelativeUrls() { $all = array(); foreach ($this->_links as $link) { if (! $this->_linkIsAbsolute($link->getHref())) { $all[] = $link->getHref(); } } return $all; } /** * Accessor for URLs by the link label. Label will match * regardess of whitespace issues and case. * @param string $label Text of link. * @return array List of links with that label. * @access public */ function getUrlsByLabel($label) { $matches = array(); foreach ($this->_links as $link) { if ($link->getText() == $label) { $matches[] = $this->_getUrlFromLink($link); } } return $matches; } /** * Accessor for a URL by the id attribute. * @param string $id Id attribute of link. * @return SimpleUrl URL with that id of false if none. * @access public */ function getUrlById($id) { foreach ($this->_links as $link) { if ($link->getAttribute('id') === (string)$id) { return $this->_getUrlFromLink($link); } } return false; } /** * Converts a link into a target URL. * @param SimpleAnchor $link Parsed link. * @return SimpleUrl URL with frame target if any. * @access private */ function _getUrlFromLink($link) { $url = $this->_makeAbsolute($link->getHref()); if ($link->getAttribute('target')) { $url->setTarget($link->getAttribute('target')); } return $url; } /** * Expands expandomatic URLs into fully qualified * URLs. * @param SimpleUrl $url Relative URL. * @return SimpleUrl Absolute URL. * @access protected */ function _makeAbsolute($url) { if (! is_object($url)) { $url = new SimpleUrl($url); } return $url->makeAbsolute($this->getUrl()); } /** * Sets the title tag contents. * @param SimpleTitleTag $tag Title of page. * @access protected */ function _setTitle(&$tag) { $this->_title = &$tag; } /** * Accessor for parsed title. * @return string Title or false if no title is present. * @access public */ function getTitle() { if ($this->_title) { return $this->_title->getText(); } return false; } /** * Finds a held form by button label. Will only * search correctly built forms. * @param SimpleSelector $selector Button finder. * @return SimpleForm Form object containing * the button. * @access public */ function &getFormBySubmit($selector) { for ($i = 0; $i < count($this->_complete_forms); $i++) { if ($this->_complete_forms[$i]->hasSubmit($selector)) { return $this->_complete_forms[$i]; } } $null = null; return $null; } /** * Finds a held form by image using a selector. * Will only search correctly built forms. * @param SimpleSelector $selector Image finder. * @return SimpleForm Form object containing * the image. * @access public */ function &getFormByImage($selector) { for ($i = 0; $i < count($this->_complete_forms); $i++) { if ($this->_complete_forms[$i]->hasImage($selector)) { return $this->_complete_forms[$i]; } } $null = null; return $null; } /** * Finds a held form by the form ID. A way of * identifying a specific form when we have control * of the HTML code. * @param string $id Form label. * @return SimpleForm Form object containing the matching ID. * @access public */ function &getFormById($id) { for ($i = 0; $i < count($this->_complete_forms); $i++) { if ($this->_complete_forms[$i]->getId() == $id) { return $this->_complete_forms[$i]; } } $null = null; return $null; } /** * Sets a field on each form in which the field is * available. * @param SimpleSelector $selector Field finder. * @param string $value Value to set field to. * @return boolean True if value is valid. * @access public */ function setField($selector, $value) { $is_set = false; for ($i = 0; $i < count($this->_complete_forms); $i++) { if ($this->_complete_forms[$i]->setField($selector, $value)) { $is_set = true; } } return $is_set; } /** * Accessor for a form element value within a page. * @param SimpleSelector $selector Field finder. * @return string/boolean A string if the field is * present, false if unchecked * and null if missing. * @access public */ function getField($selector) { for ($i = 0; $i < count($this->_complete_forms); $i++) { $value = $this->_complete_forms[$i]->getValue($selector); if (isset($value)) { return $value; } } return null; } } ?> postfixadmin-2.3.7/tests/simpletest/socket.php0000664000175000017620000001564411157271050021624 0ustar davidpalepurple_clearError(); } /** * Test for an outstanding error. * @return boolean True if there is an error. * @access public */ function isError() { return ($this->_error != ''); } /** * Accessor for an outstanding error. * @return string Empty string if no error otherwise * the error message. * @access public */ function getError() { return $this->_error; } /** * Sets the internal error. * @param string Error message to stash. * @access protected */ function _setError($error) { $this->_error = $error; } /** * Resets the error state to no error. * @access protected */ function _clearError() { $this->_setError(''); } } /** * Wrapper for TCP/IP socket. * @package SimpleTest * @subpackage WebTester */ class SimpleSocket extends SimpleStickyError { var $_handle; var $_is_open = false; var $_sent = ''; var $lock_size; /** * Opens a socket for reading and writing. * @param string $host Hostname to send request to. * @param integer $port Port on remote machine to open. * @param integer $timeout Connection timeout in seconds. * @param integer $block_size Size of chunk to read. * @access public */ function SimpleSocket($host, $port, $timeout, $block_size = 255) { $this->SimpleStickyError(); if (! ($this->_handle = $this->_openSocket($host, $port, $error_number, $error, $timeout))) { $this->_setError("Cannot open [$host:$port] with [$error] within [$timeout] seconds"); return; } $this->_is_open = true; $this->_block_size = $block_size; SimpleTestCompatibility::setTimeout($this->_handle, $timeout); } /** * Writes some data to the socket and saves alocal copy. * @param string $message String to send to socket. * @return boolean True if successful. * @access public */ function write($message) { if ($this->isError() || ! $this->isOpen()) { return false; } $count = fwrite($this->_handle, $message); if (! $count) { if ($count === false) { $this->_setError('Cannot write to socket'); $this->close(); } return false; } fflush($this->_handle); $this->_sent .= $message; return true; } /** * Reads data from the socket. The error suppresion * is a workaround for PHP4 always throwing a warning * with a secure socket. * @return integer/boolean Incoming bytes. False * on error. * @access public */ function read() { if ($this->isError() || ! $this->isOpen()) { return false; } $raw = @fread($this->_handle, $this->_block_size); if ($raw === false) { $this->_setError('Cannot read from socket'); $this->close(); } return $raw; } /** * Accessor for socket open state. * @return boolean True if open. * @access public */ function isOpen() { return $this->_is_open; } /** * Closes the socket preventing further reads. * Cannot be reopened once closed. * @return boolean True if successful. * @access public */ function close() { $this->_is_open = false; return fclose($this->_handle); } /** * Accessor for content so far. * @return string Bytes sent only. * @access public */ function getSent() { return $this->_sent; } /** * Actually opens the low level socket. * @param string $host Host to connect to. * @param integer $port Port on host. * @param integer $error_number Recipient of error code. * @param string $error Recipoent of error message. * @param integer $timeout Maximum time to wait for connection. * @access protected */ function _openSocket($host, $port, &$error_number, &$error, $timeout) { return @fsockopen($host, $port, $error_number, $error, $timeout); } } /** * Wrapper for TCP/IP socket over TLS. * @package SimpleTest * @subpackage WebTester */ class SimpleSecureSocket extends SimpleSocket { /** * Opens a secure socket for reading and writing. * @param string $host Hostname to send request to. * @param integer $port Port on remote machine to open. * @param integer $timeout Connection timeout in seconds. * @access public */ function SimpleSecureSocket($host, $port, $timeout) { $this->SimpleSocket($host, $port, $timeout); } /** * Actually opens the low level socket. * @param string $host Host to connect to. * @param integer $port Port on host. * @param integer $error_number Recipient of error code. * @param string $error Recipient of error message. * @param integer $timeout Maximum time to wait for connection. * @access protected */ function _openSocket($host, $port, &$error_number, &$error, $timeout) { return parent::_openSocket("tls://$host", $port, $error_number, $error, $timeout); } } ?>postfixadmin-2.3.7/tests/simpletest/packages/0000775000175000017620000000000012301477470021375 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/packages/make_phpdoc_docs.sh0000775000175000017620000000340011157271050025205 0ustar davidpalepurple#!/bin/bash #DEST_DIR=../docs/pkg if [ ! -d ../tutorials ] then mkdir ../tutorials fi if [ ! -d ../tutorials/SimpleTest ] then mkdir ../tutorials/SimpleTest fi DEST_DIR=../tutorials/SimpleTest rm ${DEST_DIR}/*.pkg cp ../docs/pkg/SimpleTest.pkg.ini ${DEST_DIR} #Xalan -o ${DEST_DIR}/QuickStart.pkg ../docs/source/en/simple_test.xml phpdoc_docs.xslt Xalan -o ${DEST_DIR}/SimpleTest.pkg ../docs/source/en/overview.xml phpdoc_docs.xslt Xalan -o ${DEST_DIR}/UnitTestCase.pkg ../docs/source/en/unit_test_documentation.xml phpdoc_docs.xslt Xalan -o ${DEST_DIR}/GroupTests.pkg ../docs/source/en/group_test_documentation.xml phpdoc_docs.xslt Xalan -o ${DEST_DIR}/MockObjects.pkg ../docs/source/en/mock_objects_documentation.xml phpdoc_docs.xslt Xalan -o ${DEST_DIR}/PartialMock.pkg ../docs/source/en/partial_mocks_documentation.xml phpdoc_docs.xslt Xalan -o ${DEST_DIR}/Reporting.pkg ../docs/source/en/reporter_documentation.xml phpdoc_docs.xslt Xalan -o ${DEST_DIR}/Expectations.pkg ../docs/source/en/expectation_documentation.xml phpdoc_docs.xslt Xalan -o ${DEST_DIR}/WebTester.pkg ../docs/source/en/web_tester_documentation.xml phpdoc_docs.xslt Xalan -o ${DEST_DIR}/FormTesting.pkg ../docs/source/en/form_testing_documentation.xml phpdoc_docs.xslt Xalan -o ${DEST_DIR}/Authentication.pkg ../docs/source/en/authentication_documentation.xml phpdoc_docs.xslt Xalan -o ${DEST_DIR}/Browser.pkg ../docs/source/en/browser_documentation.xml phpdoc_docs.xslt # some cleanup work cd $DEST_DIR # remove XML declaration for f in $(ls *.pkg --color=none) do grep -v -e '^ tmp.pkg mv tmp.pkg $f done # fix overview title cat SimpleTest.pkg | sed -e 's/Overview/Simple Test PHP Unit Test Framework/g;s/<\([A-Za-z0-9]*\)\/>/<\1><\/\1>/g' > tmp.pkg mv tmp.pkg SimpleTest.pkg postfixadmin-2.3.7/tests/simpletest/packages/make_bundled_docs.sh0000775000175000017620000000542311157271050025354 0ustar davidpalepurple#!/bin/sh xsltproc bundled_docs.xslt ../docs/source/en/simple_test.xml > ../docs/en/index.html xsltproc bundled_docs.xslt ../docs/source/en/overview.xml > ../docs/en/overview.html xsltproc bundled_docs.xslt ../docs/source/en/unit_test_documentation.xml > ../docs/en/unit_test_documentation.html xsltproc bundled_docs.xslt ../docs/source/en/group_test_documentation.xml > ../docs/en/group_test_documentation.html xsltproc bundled_docs.xslt ../docs/source/en/mock_objects_documentation.xml > ../docs/en/mock_objects_documentation.html xsltproc bundled_docs.xslt ../docs/source/en/partial_mocks_documentation.xml > ../docs/en/partial_mocks_documentation.html xsltproc bundled_docs.xslt ../docs/source/en/reporter_documentation.xml > ../docs/en/reporter_documentation.html xsltproc bundled_docs.xslt ../docs/source/en/expectation_documentation.xml > ../docs/en/expectation_documentation.html xsltproc bundled_docs.xslt ../docs/source/en/web_tester_documentation.xml > ../docs/en/web_tester_documentation.html xsltproc bundled_docs.xslt ../docs/source/en/form_testing_documentation.xml > ../docs/en/form_testing_documentation.html xsltproc bundled_docs.xslt ../docs/source/en/authentication_documentation.xml > ../docs/en/authentication_documentation.html xsltproc bundled_docs.xslt ../docs/source/en/browser_documentation.xml > ../docs/en/browser_documentation.html xsltproc bundled_docs.xslt ../docs/source/fr/simple_test.xml > ../docs/fr/index.html xsltproc bundled_docs.xslt ../docs/source/fr/overview.xml > ../docs/fr/overview.html xsltproc bundled_docs.xslt ../docs/source/fr/unit_test_documentation.xml > ../docs/fr/unit_test_documentation.html xsltproc bundled_docs.xslt ../docs/source/fr/group_test_documentation.xml > ../docs/fr/group_test_documentation.html xsltproc bundled_docs.xslt ../docs/source/fr/server_stubs_documentation.xml > ../docs/fr/server_stubs_documentation.html xsltproc bundled_docs.xslt ../docs/source/fr/mock_objects_documentation.xml > ../docs/fr/mock_objects_documentation.html xsltproc bundled_docs.xslt ../docs/source/fr/partial_mocks_documentation.xml > ../docs/fr/partial_mocks_documentation.html xsltproc bundled_docs.xslt ../docs/source/fr/reporter_documentation.xml > ../docs/fr/reporter_documentation.html xsltproc bundled_docs.xslt ../docs/source/fr/expectation_documentation.xml > ../docs/fr/expectation_documentation.html xsltproc bundled_docs.xslt ../docs/source/fr/web_tester_documentation.xml > ../docs/fr/web_tester_documentation.html xsltproc bundled_docs.xslt ../docs/source/fr/form_testing_documentation.xml > ../docs/fr/form_testing_documentation.html xsltproc bundled_docs.xslt ../docs/source/fr/authentication_documentation.xml > ../docs/fr/authentication_documentation.html xsltproc bundled_docs.xslt ../docs/source/fr/browser_documentation.xml > ../docs/fr/browser_documentation.html postfixadmin-2.3.7/tests/simpletest/packages/site_map.xml0000664000175000017620000000354611157271050023722 0ustar davidpalepurple postfixadmin-2.3.7/tests/simpletest/packages/simpletest.ini0000775000175000017620000000756611157271050024302 0ustar davidpalepurple;; phpDocumentor parse configuration file ;; ;; This file is designed to cut down on repetitive typing on the command-line or web interface ;; You can copy this file to create a number of configuration files that can be used with the ;; command-line switch -c, as in phpdoc -c default.ini or phpdoc -c myini.ini. The web ;; interface will automatically generate a list of .ini files that can be used. ;; ;; default.ini is used to generate the online manual at http://www.phpdoc.org/docs ;; ;; ALL .ini files must be in the user subdirectory of phpDocumentor with an extension of .ini ;; ;; Copyright 2002, Greg Beaver ;; ;; WARNING: do not change the name of any command-line parameters, phpDocumentor will ignore them [Parse Data] ;; title of all the documentation ;; legal values: any string title = SimpleTest API Documentation ;; parse files that start with a . like .bash_profile ;; legal values: true, false hidden = false ;; show elements marked @access private in documentation by setting this to on ;; legal values: on, off parseprivate = off ;; parse with javadoc-like description (first sentence is always the short description) ;; legal values: on, off javadocdesc = off ;; add any custom @tags separated by commas here ;; legal values: any legal tagname separated by commas. ;customtags = mytag1,mytag2 ;; This is only used by the XML:DocBook/peardoc2 converter defaultcategoryname = Documentation ;; what is the main package? ;; legal values: alphanumeric string plus - and _ defaultpackagename = SimpleTest ;; output any parsing information? set to on for cron jobs ;; legal values: on ;quiet = on ;; parse a PEAR-style repository. Do not turn this on if your project does ;; not have a parent directory named "pear" ;; legal values: on/off ;pear = on ;; where should the documentation be written? ;; legal values: a legal path target = /home/groups/s/si/simpletest/htdocs/api ;; limit output to the specified packages, even if others are parsed ;; legal values: package names separated by commas ;packageoutput = package1,package2 ;; comma-separated list of files to parse ;; legal values: paths separated by commas ;filename = /path/to/file1,/path/to/file2,fileincurrentdirectory ;; comma-separated list of directories to parse ;; legal values: directory paths separated by commas ;directory = /path1,/path2,.,..,subdirectory ;directory = /home/jeichorn/cvs/pear directory = /home/groups/s/si/simpletest/simpletest_doc_target ;; template base directory (the equivalent directory of /phpDocumentor) ;templatebase = /path/to/my/templates ;; comma-separated list of files, directories or wildcards ? and * (any wildcard) to ignore ;; legal values: any wildcard strings separated by commas ;ignore = /path/to/ignore*,*list.php,myfile.php,subdirectory/ ;ignore = templates_c/,*HTML/default/*,spec/ ignore = docs/,packages/,test/ ;; comma-separated list of Converters to use in outputformat:Convertername:templatedirectory format ;; legal values: HTML:frames:default,HTML:frames:l0l33t,HTML:frames:phpdoc.de,HTML:frames:phphtmllib, ;; HTML:frames:earthli, ;; HTML:frames:DOM/default,HTML:frames:DOM/l0l33t,HTML:frames:DOM/phpdoc.de, ;; HTML:frames:DOM/phphtmllib,HTML:frames:DOM/earthli ;; HTML:Smarty:default,HTML:Smarty:PHP,HTML:Smarty:HandS ;; PDF:default:default,CHM:default:default,XML:DocBook/peardoc2:default ;output=HTML:frames:earthli,HTML:frames:default,HTML:frames:l0l33t,HTML:frames:phpdoc.de,HTML:frames:phphtmllib,HTML:frames:DOM/default,HTML:frames:DOM/l0l33t,HTML:frames:DOM/phpdoc.de,HTML:frames:DOM/earthli,HTML:frames:DOM/phphtmllib,HTML:frames:phpedit,HTML:Smarty:default,HTML:Smarty:PHP,HTML:Smarty:HandS,CHM:default:default,PDF:default:default output=HTML:frames:DOM/earthlisf ;; turn this option on if you want highlighted source code for every file ;; legal values: on/off sourcecode = off postfixadmin-2.3.7/tests/simpletest/packages/make_lastcraft_docs.sh0000775000175000017620000000014111157271050025712 0ustar davidpalepurple#!/bin/bash php transform_all_lastcraft.php lastcraft.xslt ../docs/source/en/ ../docs/lastcraft/ postfixadmin-2.3.7/tests/simpletest/packages/package.xml0000664000175000017620000015010011157271050023501 0ustar davidpalepurple SimpleTest Unit testing, mock objects and web testing framework for PHP. The heart of SimpleTest is a testing framework built around test case classes. These are written as extensions of base test case classes, each extended with methods that actually contain test code. Top level test scripts then invoke the run() methods on every one of these test cases in order. Each test method is written to invoke various assertions that the developer expects to be true such as assertEqual(). If the expectation is correct, then a successful result is dispatched to the observing test reporter, but any failure triggers an alert and a description of the mismatch. These tools are designed for the developer. Tests are written in the PHP language itself more or less as the application itself is built. The advantage of using PHP itself as the testing language is that there are no new languages to learn, testing can start straight away, and the developer can test any part of the code. Basically, all parts that can be accessed by the application code can also be accessed by the test code if they are in the same language. lastcraft Marcus Baker marcus@lastcraft.com lead jsweat Jason Sweat jsweat_php@yahoo.com helper hfuecks Harry Fuecks hfuecks@phppatterns.com helper 0.9.4 2004-02-20 The Open Group Test Suite License beta This is the final version of the PHP unit and web testing tool before the stable release 1.0 version. It features many improvements to the HTML form parsing and exposure of the underlying web browser. There are also numerous minor improvements and bug fixes. 0.9.4 2004-02-20 The Open Group Test Suite License beta This is the final version of the PHP unit and web testing tool before the stable release 1.0 version. It features many improvements to the HTML form parsing and exposure of the underlying web browser. There are also numerous minor improvements and bug fixes. postfixadmin-2.3.7/tests/simpletest/packages/pear_package_create.php0000775000175000017620000001306511157271050026035 0ustar davidpalepurple#!/usr/local/bin/php -q 'lastcraft','role'=>'lead','name'=>'Marcus Baker', 'email'=>'marcus@lastcraft.com'), array ('handle'=>'jsweat','role'=>'helper','name'=>'Jason Sweat', 'email'=>'jsweat_php@yahoo.com'), array ('handle'=>'hfuecks','role'=>'helper','name'=>'Harry Fuecks', 'email'=>'hfuecks@phppatterns.com'), ); /*---------------------------------------------------------------------------*/ /** * Code starts here */ require_once('PEAR/PackageFileManager.php'); $PPFM = new PEAR_PackageFileManager; if (version_compare(phpversion(), '4.3.0', '<') || php_sapi_name() == 'cgi') { define('STDOUT', fopen('php://stdout', 'w')); define('STDERR', fopen('php://stderr', 'w')); register_shutdown_function( create_function('', 'fclose(STDOUT); fclose(STDERR); return true;')); } /** * A giant array to configure the PackageFileManager. For the "roles" see * http://pear.php.net/manual/en/developers.packagedef.php */ $options = array( 'baseinstalldir' => 'simpletest', 'version' => $version, 'packagedirectory' => $packagedir, 'outputdirectory' => $packagedir, 'pathtopackagefile' => $packagedir, 'state' => $state, 'summary' => $shortDesc, 'description' => $longDesc, 'filelistgenerator' => 'file', 'notes' => $releaseNotes, 'package' => 'SimpleTest', 'license' => 'The Open Group Test Suite License', 'dir_roles' => array( 'docs' => 'doc', 'test' => 'test', 'extensions' => 'php', //'tutorials' => 'doc', //'tutorials/SimpleTest' => 'doc', //'ui' => 'php', //'ui/css' => 'data', //'ui/img' => 'data', //'ui/js' => 'data', //'ui/js/tests' => 'test', ), 'exceptions' => array( 'HELP_MY_TESTS_DONT_WORK_ANYMORE' => 'doc', 'LICENSE' => 'doc', 'README' => 'doc', 'TODO' => 'doc', 'VERSION' => 'doc', ), 'ignore' => array( "$packagedir/packages", "$packagedir/ui", ), ); $status = $PPFM->setOptions($options); if (PEAR::isError($status)) { fwrite (STDERR,$status->getMessage()); exit; } foreach ( $maintainers as $maintainer ) { $PPFM->addMaintainer( $maintainer['handle'], $maintainer['role'], $maintainer['name'], $maintainer['email'] ); } // Adds a dependency of PHP 4.2.3+ $status = $PPFM->addDependency('php', '4.2.3', 'ge', 'php'); if (PEAR::isError($status)) { fwrite (STDERR,$status->getMessage()); exit; } // hack (apparently) $PPFM->addRole('tpl', 'php'); $PPFM->addRole('png', 'php'); $PPFM->addRole('gif', 'php'); $PPFM->addRole('jpg', 'php'); $PPFM->addRole('css', 'php'); $PPFM->addRole('js', 'php'); $PPFM->addRole('ini', 'php'); $PPFM->addRole('inc', 'php'); $PPFM->addRole('afm', 'php'); $PPFM->addRole('pkg', 'doc'); $PPFM->addRole('cls', 'doc'); $PPFM->addRole('proc', 'doc'); $PPFM->addRole('sh', 'script'); ob_start(); $status = $PPFM->writePackageFile(false); $output = ob_get_contents(); ob_end_clean(); // Hacks to handle PPFM output $start = strpos ($output,"getMessage()); } ?>postfixadmin-2.3.7/tests/simpletest/packages/generate_package.php0000664000175000017620000001026711157271050025353 0ustar davidpalepurplesetOptions(array( 'baseinstalldir' => 'simpletest', 'version' => '1.0.0', 'license' => 'The Open Group Test Suite License', 'packagedirectory' => '/var/www/html/tmp/simpletest', 'state' => 'stable', 'package' => 'simpletest', 'simpleoutput' => true, 'summary' => $shortDesc, 'description' => $longDesc, 'filelistgenerator' => 'file', // generate from cvs, use file for directory 'notes' => 'See the CHANGELOG for full list of changes', 'dir_roles' => array( 'extensions' => 'php', 'test' => 'test', ), 'ignore' => array( 'packages/', 'tutorials/', 'ui/', 'docs/', '*CVS*', 'TODO', ), 'roles' => array( 'php' => 'php', 'html' => 'php', '*' => 'php', ), 'exceptions' => array( 'VERSION' => 'doc', 'HELP_MY_TESTS_DONT_WORK_ANYMORE' => 'doc', 'LICENSE' => 'doc', 'README' => 'doc', ), ) ); if (is_a($e, 'PEAR_Error')) { echo $e->getMessage(); die(); } $e = $packagexml->addMaintainer('lastcraft', 'lead', 'Marcus Baker', 'marcus@lastcraft.com'); if (is_a($e, 'PEAR_Error')) { echo $e->getMessage(); exit; } $e = $packagexml->addMaintainer('tswicegood', 'developer', 'Travis Swicegood', 'tswicegood@users.sourceforge.net'); if (is_a($e, 'PEAR_Error')) { echo $e->getMessage(); exit; } $e = $packagexml->addMaintainer('jsweat', 'helper', 'Jason Sweat', 'jsweat_php@yahoo.com'); if (is_a($e, 'PEAR_Error')) { echo $e->getMessage(); exit; } $e = $packagexml->addMaintainer('pp11', 'helper', 'Perrick Penet', 'perrick@noparking.net'); if (is_a($e, 'PEAR_Error')) { echo $e->getMessage(); exit; } $e = $packagexml->addMaintainer('shpikat', 'helper', 'Constantine Shpikat', 'shpikat@users.sourceforge.net'); if (is_a($e, 'PEAR_Error')) { echo $e->getMessage(); exit; } $e = $packagexml->addMaintainer('demianturner', 'helper', 'Demian Turner', 'demian@phpkitchen.com'); if (is_a($e, 'PEAR_Error')) { echo $e->getMessage(); exit; } // note use of {@link debugPackageFile()} - this is VERY important if (isset($_GET['make']) || (isset($_SERVER['argv'][2]) && $_SERVER['argv'][2] == 'make')) { $e = $packagexml->writePackageFile(); } else { $e = $packagexml->debugPackageFile(); } if (is_a($e, 'PEAR_Error')) { echo $e->getMessage(); die(); } ?>postfixadmin-2.3.7/tests/simpletest/packages/onpk/0000775000175000017620000000000012301477470022344 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/packages/onpk/map_onpk.xml0000664000175000017620000000340711157271050024670 0ustar davidpalepurple postfixadmin-2.3.7/tests/simpletest/packages/onpk/transform_all_onpk.php0000664000175000017620000000146311157271050026745 0ustar davidpalepurple"; } else { echo "erreur pour ".$destination." : ".xslt_error($xh)."
    "; } xslt_free($xsltProcessor); } closedir($dir); ?>postfixadmin-2.3.7/tests/simpletest/packages/onpk/onpk.xslt0000664000175000017620000001513111157271050024222 0ustar davidpalepurple <xsl:value-of select="//long_title"/>

    Cette page...
    Pour aller plus loin...
    			
    				
    			
    		

    .php
  • postfixadmin-2.3.7/tests/simpletest/packages/transform_all_lastcraft.php0000664000175000017620000000101211157271050027000 0ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/packages/README0000664000175000017620000000114311157271050022246 0ustar davidpalepurpleHOW TO MAKE A PACKAGE 1. First make sure PEAR_PackageFileManager is installed; (version 1.2.0 was used) $ pear install PEAR_PackageFileManager 2. Edit the simpletest/packages/pear_package_create.php file (see comments for what needs changing). 3. Run the simpletest/packages/pear_package_create.php script, piping the output to the file you want to create e.g.; $ ./pear_package_create.php > package.xml 4. Copy the package.xml to the root of Simpletest. 5. From the root of Simpletest type; $ pear package package.xml This creates the package zip 6. Install with; $ pear install SimpleTest-x.x.x.tgzpostfixadmin-2.3.7/tests/simpletest/packages/make_bundled_docs_with_xalan.sh0000775000175000017620000000534111157271050027571 0ustar davidpalepurple#!/bin/sh Xalan -o ../docs/en/index.html ../docs/source/en/simple_test.xml bundled_docs.xslt Xalan -o ../docs/en/overview.html ../docs/source/en/overview.xml bundled_docs.xslt Xalan -o ../docs/en/unit_test_documentation.html ../docs/source/en/unit_test_documentation.xml bundled_docs.xslt Xalan -o ../docs/en/group_test_documentation.html ../docs/source/en/group_test_documentation.xml bundled_docs.xslt Xalan -o ../docs/en/mock_objects_documentation.html ../docs/source/en/mock_objects_documentation.xml bundled_docs.xslt Xalan -o ../docs/en/partial_mocks_documentation.html ../docs/source/en/partial_mocks_documentation.xml bundled_docs.xslt Xalan -o ../docs/en/reporter_documentation.html ../docs/source/en/reporter_documentation.xml bundled_docs.xslt Xalan -o ../docs/en/expectation_documentation.html ../docs/source/en/expectation_documentation.xml bundled_docs.xslt Xalan -o ../docs/en/web_tester_documentation.html ../docs/source/en/web_tester_documentation.xml bundled_docs.xslt Xalan -o ../docs/en/form_testing_documentation.html ../docs/source/en/form_testing_documentation.xml bundled_docs.xslt Xalan -o ../docs/en/authentication_documentation.html ../docs/source/en/authentication_documentation.xml bundled_docs.xslt Xalan -o ../docs/en/browser_documentation.html ../docs/source/en/browser_documentation.xml bundled_docs.xslt Xalan -o ../docs/fr/index.html ../docs/source/fr/simple_test.xml bundled_docs.xslt Xalan -o ../docs/fr/overview.html ../docs/source/fr/overview.xml bundled_docs.xslt Xalan -o ../docs/fr/unit_test_documentation.html ../docs/source/fr/unit_test_documentation.xml bundled_docs.xslt Xalan -o ../docs/fr/group_test_documentation.html ../docs/source/fr/group_test_documentation.xml bundled_docs.xslt Xalan -o ../docs/fr/server_stubs_documentation.html ../docs/source/fr/server_stubs_documentation.xml bundled_docs.xslt Xalan -o ../docs/fr/mock_objects_documentation.html ../docs/source/fr/mock_objects_documentation.xml bundled_docs.xslt Xalan -o ../docs/fr/partial_mocks_documentation.html ../docs/source/fr/partial_mocks_documentation.xml bundled_docs.xslt Xalan -o ../docs/fr/reporter_documentation.html ../docs/source/fr/reporter_documentation.xml bundled_docs.xslt Xalan -o ../docs/fr/expectation_documentation.html ../docs/source/fr/expectation_documentation.xml bundled_docs.xslt Xalan -o ../docs/fr/web_tester_documentation.html ../docs/source/fr/web_tester_documentation.xml bundled_docs.xslt Xalan -o ../docs/fr/form_testing_documentation.html ../docs/source/fr/form_testing_documentation.xml bundled_docs.xslt Xalan -o ../docs/fr/authentication_documentation.html ../docs/source/fr/authentication_documentation.xml bundled_docs.xslt Xalan -o ../docs/fr/browser_documentation.html ../docs/source/fr/browser_documentation.xml bundled_docs.xslt postfixadmin-2.3.7/tests/simpletest/packages/phpdoc_docs.xslt0000664000175000017620000001033411157271050024571 0ustar davidpalepurple
    <![CDATA[ ]]> {@id } <xsl:value-of select="@title"/> <xsl:value-of select="h2"/> .html }
    postfixadmin-2.3.7/tests/simpletest/packages/bundled_map.xml0000664000175000017620000000150111157271050024360 0ustar davidpalepurple postfixadmin-2.3.7/tests/simpletest/packages/build_tarball.sh0000775000175000017620000001233711157271050024534 0ustar davidpalepurple#!/bin/sh # Builds project release. # cd ../.. NAME=simpletest_`cat simpletest/VERSION`.tar.gz FILES=(simpletest/compatibility.php \ simpletest/collector.php \ simpletest/dumper.php \ simpletest/errors.php \ simpletest/exceptions.php \ simpletest/expectation.php \ simpletest/socket.php \ simpletest/encoding.php \ simpletest/url.php \ simpletest/cookies.php \ simpletest/http.php \ simpletest/authentication.php \ simpletest/user_agent.php \ simpletest/browser.php \ simpletest/parser.php \ simpletest/tag.php \ simpletest/selector.php \ simpletest/form.php \ simpletest/frames.php \ simpletest/page.php \ simpletest/reflection_php4.php \ simpletest/reflection_php5.php \ simpletest/invoker.php \ simpletest/scorer.php \ simpletest/reporter.php \ simpletest/mock_objects.php \ simpletest/simpletest.php \ simpletest/test_case.php \ simpletest/unit_tester.php \ simpletest/web_tester.php \ simpletest/shell_tester.php \ simpletest/xml.php \ simpletest/detached.php \ simpletest/remote.php \ simpletest/extensions/pear_test_case.php \ simpletest/extensions/phpunit_test_case.php \ simpletest/README \ simpletest/VERSION \ simpletest/LICENSE \ simpletest/HELP_MY_TESTS_DONT_WORK_ANYMORE \ simpletest/test/all_tests.php \ simpletest/test/unit_tests.php \ simpletest/test/test_groups.php \ simpletest/test/acceptance_test.php \ simpletest/test/collector_test.php \ simpletest/test/simpletest_test.php \ simpletest/test/errors_test.php \ simpletest/test/exceptions_test.php \ simpletest/test/compatibility_test.php \ simpletest/test/dumper_test.php \ simpletest/test/expectation_test.php \ simpletest/test/adapter_test.php \ simpletest/test/socket_test.php \ simpletest/test/url_test.php \ simpletest/test/cookies_test.php \ simpletest/test/encoding_test.php \ simpletest/test/http_test.php \ simpletest/test/authentication_test.php \ simpletest/test/user_agent_test.php \ simpletest/test/browser_test.php \ simpletest/test/parser_test.php \ simpletest/test/tag_test.php \ simpletest/test/form_test.php \ simpletest/test/frames_test.php \ simpletest/test/page_test.php \ simpletest/test/reflection_php4_test.php \ simpletest/test/reflection_php5_test.php \ simpletest/test/mock_objects_test.php \ simpletest/test/interfaces_test.php \ simpletest/test/visual_test.php \ simpletest/test/shell_test.php \ simpletest/test/web_tester_test.php \ simpletest/test/unit_tester_test.php \ simpletest/test/shell_tester_test.php \ simpletest/test/xml_test.php \ simpletest/test/live_test.php \ simpletest/test/parse_error_test.php \ simpletest/test/detached_test.php \ simpletest/test/remote_test.php \ simpletest/test/test_with_parse_error.php \ simpletest/test/support/collector/collectable.1 \ simpletest/test/support/collector/collectable.2 \ simpletest/test/support/upload_sample.txt \ simpletest/test/support/supplementary_upload_sample.txt \ simpletest/test/support/latin1_sample \ simpletest/test/support/spl_examples.php \ simpletest/docs/en/docs.css \ simpletest/docs/en/index.html \ simpletest/docs/en/overview.html \ simpletest/docs/en/unit_test_documentation.html \ simpletest/docs/en/group_test_documentation.html \ simpletest/docs/en/mock_objects_documentation.html \ simpletest/docs/en/partial_mocks_documentation.html \ simpletest/docs/en/reporter_documentation.html \ simpletest/docs/en/expectation_documentation.html \ simpletest/docs/en/web_tester_documentation.html \ simpletest/docs/en/form_testing_documentation.html \ simpletest/docs/en/authentication_documentation.html \ simpletest/docs/en/browser_documentation.html \ simpletest/docs/fr/docs.css \ simpletest/docs/fr/index.html \ simpletest/docs/fr/overview.html \ simpletest/docs/fr/unit_test_documentation.html \ simpletest/docs/fr/group_test_documentation.html \ simpletest/docs/fr/server_stubs_documentation.html \ simpletest/docs/fr/mock_objects_documentation.html \ simpletest/docs/fr/partial_mocks_documentation.html \ simpletest/docs/fr/reporter_documentation.html \ simpletest/docs/fr/expectation_documentation.html \ simpletest/docs/fr/web_tester_documentation.html \ simpletest/docs/fr/form_testing_documentation.html \ simpletest/docs/fr/authentication_documentation.html \ simpletest/docs/fr/browser_documentation.html) tar -zcf $NAME ${FILES[*]} postfixadmin-2.3.7/tests/simpletest/packages/bundled_docs.xslt0000664000175000017620000002056511157271050024740 0ustar davidpalepurple <xsl:value-of select="//long_title"/>
    |
    ( pages)

    This page...
    References and related information...
                
                    
                
            
                
                    
                
            
                
                    
                
            
                
            

    .html
  • postfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/0000775000175000017620000000000012301477470024354 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/test/0000775000175000017620000000000012301477470025333 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/test/package_test.php0000664000175000017620000000750111157271050030473 0ustar davidpalepurplecontent(); $this->assertPattern('/
    /', $content);
    		$this->assertNoPattern('/<\!\[CDATA\[/', $content);
    		$this->assertPattern('/

    /', $content); } function testOfContentWithoutSections() { $file = dirname(__FILE__).'/package/content_without_section.xml'; $source = simplexml_load_file($file, "SimpleTestXMLElement"); $content = $source->content(); $this->assertPattern('/

    /', $content); } function testOfSingleLink() { $file = dirname(__FILE__).'/package/here_download.xml'; $source = simplexml_load_file($file, "SimpleTestXMLElement"); $map = dirname(__FILE__).'/package/map.xml'; $links = $source->links($map); $this->assertEqual(count($links), 3); $links_download = '

    '; $this->assertEqual($links['download'], $links_download); } function testOfMultipleLinks() { $file = dirname(__FILE__).'/package/here_support.xml'; $source = simplexml_load_file($file, "SimpleTestXMLElement"); $map = dirname(__FILE__).'/package/map.xml'; $links = $source->links($map); $this->assertEqual(count($links), 3); $links_support = ''; $this->assertEqual($links['support'], $links_support); } function testOfHierarchicalLinks() { $file = dirname(__FILE__).'/package/here_overview.xml'; $source = simplexml_load_file($file, "SimpleTestXMLElement"); $map = dirname(__FILE__).'/package/map.xml'; $links = $source->links($map); $this->assertEqual(count($links), 3); $links_start_testing = ''; $this->assertEqual($links['start_testing'], $links_start_testing); } function testOfRootLinksWithHierarchy() { $file = dirname(__FILE__).'/package/here_simpletest.xml'; $source = simplexml_load_file($file, "SimpleTestXMLElement"); $map = dirname(__FILE__).'/package/map.xml'; $links = $source->links($map); $this->assertEqual(count($links), 3); $links_start_testing = ''; $this->assertEqual($links['start_testing'], $links_start_testing); } function testOfLinksWithNonRootParent() { $file = dirname(__FILE__).'/package/here_unit-tester.xml'; $source = simplexml_load_file($file, "SimpleTestXMLElement"); $map = dirname(__FILE__).'/package/map.xml'; $links = $source->links($map); $this->assertEqual(count($links), 3); $links_start_testing = ''; $this->assertEqual($links['start_testing'], $links_start_testing); } } $test = &new TestOfContentTransformationFromXMLToHTML(); $test->run(new HtmlReporter()); ?>postfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/test/package/0000775000175000017620000000000012301477470026726 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/test/package/here_unit-tester.xml0000664000175000017620000000552211157271050032734 0ustar davidpalepurple Overview and feature list for the SimpleTest PHP unit tester and web tester

    A test case looks like this... MyTestCase extends UnitTestCase { function testLogWroteMessage() { $log = &new Log('my.log'); $log->message('Hello'); $this->assertTrue(file_exists('my.log')); } } ?> ]]>

    Quick summary of the SimpleTest tool for PHP. List of features, both current ones and those planned. There are plenty of unit testing resources on the web. Documentation for SimpleTest. How to write PHP test cases is a fairly advanced tutorial. SimpleTest API from phpdoc. software development tools, php programming, programming php, software development tools, Tools for extreme programming, free php scripts, links of testing tools, php testing resources, mock objects, junit, jwebunit, htmlunit, itc, php testing links, unit test advice and documentation, extreme programming in php Marcus Baker Primary Developer{@link mailto:marcus@lastcraft.com marcus@lastcraft.com} Harry Fuecks Packager{@link mailto:harryf@users.sourceforge.net harryf@users.sourceforge.net} Jason Sweat Documentation{@link mailto:jsweat_php@yahoo.com jsweat_php@yahoo.com}
    postfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/test/package/here_simpletest.xml0000664000175000017620000000552111157271050032641 0ustar davidpalepurple Overview and feature list for the SimpleTest PHP unit tester and web tester

    A test case looks like this... MyTestCase extends UnitTestCase { function testLogWroteMessage() { $log = &new Log('my.log'); $log->message('Hello'); $this->assertTrue(file_exists('my.log')); } } ?> ]]>

    Quick summary of the SimpleTest tool for PHP. List of features, both current ones and those planned. There are plenty of unit testing resources on the web. Documentation for SimpleTest. How to write PHP test cases is a fairly advanced tutorial. SimpleTest API from phpdoc. software development tools, php programming, programming php, software development tools, Tools for extreme programming, free php scripts, links of testing tools, php testing resources, mock objects, junit, jwebunit, htmlunit, itc, php testing links, unit test advice and documentation, extreme programming in php Marcus Baker Primary Developer{@link mailto:marcus@lastcraft.com marcus@lastcraft.com} Harry Fuecks Packager{@link mailto:harryf@users.sourceforge.net harryf@users.sourceforge.net} Jason Sweat Documentation{@link mailto:jsweat_php@yahoo.com jsweat_php@yahoo.com}
    postfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/test/package/here_download.xml0000664000175000017620000000551711157271050032264 0ustar davidpalepurple Overview and feature list for the SimpleTest PHP unit tester and web tester

    A test case looks like this... MyTestCase extends UnitTestCase { function testLogWroteMessage() { $log = &new Log('my.log'); $log->message('Hello'); $this->assertTrue(file_exists('my.log')); } } ?> ]]>

    Quick summary of the SimpleTest tool for PHP. List of features, both current ones and those planned. There are plenty of unit testing resources on the web. Documentation for SimpleTest. How to write PHP test cases is a fairly advanced tutorial. SimpleTest API from phpdoc. software development tools, php programming, programming php, software development tools, Tools for extreme programming, free php scripts, links of testing tools, php testing resources, mock objects, junit, jwebunit, htmlunit, itc, php testing links, unit test advice and documentation, extreme programming in php Marcus Baker Primary Developer{@link mailto:marcus@lastcraft.com marcus@lastcraft.com} Harry Fuecks Packager{@link mailto:harryf@users.sourceforge.net harryf@users.sourceforge.net} Jason Sweat Documentation{@link mailto:jsweat_php@yahoo.com jsweat_php@yahoo.com}
    ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootpostfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/test/package/one_section_with_php_code.xmlpostfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/test/package/one_section_with_php_code.x0000664000175000017620000000565311157271050034323 0ustar davidpalepurple Overview and feature list for the SimpleTest PHP unit tester and web tester

    A test case looks like this... MyTestCase extends UnitTestCase { function testLogWroteMessage() { $log = &new Log('my.log'); $log->message('Hello'); $this->assertTrue(file_exists('my.log')); } } ?> ]]>

    Quick summary of the SimpleTest tool for PHP. List of features, both current ones and those planned. There are plenty of unit testing resources on the web. Documentation for SimpleTest. How to write PHP test cases is a fairly advanced tutorial. SimpleTest API from phpdoc. software development tools, php programming, programming php, software development tools, Tools for extreme programming, free php scripts, links of testing tools, php testing resources, mock objects, junit, jwebunit, htmlunit, itc, php testing links, unit test advice and documentation, extreme programming in php Marcus Baker Primary Developer{@link mailto:marcus@lastcraft.com marcus@lastcraft.com} Harry Fuecks Packager{@link mailto:harryf@users.sourceforge.net harryf@users.sourceforge.net} Jason Sweat Documentation{@link mailto:jsweat_php@yahoo.com jsweat_php@yahoo.com}
    postfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/test/package/map.xml0000664000175000017620000000211211157271050030213 0ustar davidpalepurple postfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/test/package/here_overview.xml0000664000175000017620000000551711157271050032323 0ustar davidpalepurple Overview and feature list for the SimpleTest PHP unit tester and web tester

    A test case looks like this... MyTestCase extends UnitTestCase { function testLogWroteMessage() { $log = &new Log('my.log'); $log->message('Hello'); $this->assertTrue(file_exists('my.log')); } } ?> ]]>

    Quick summary of the SimpleTest tool for PHP. List of features, both current ones and those planned. There are plenty of unit testing resources on the web. Documentation for SimpleTest. How to write PHP test cases is a fairly advanced tutorial. SimpleTest API from phpdoc. software development tools, php programming, programming php, software development tools, Tools for extreme programming, free php scripts, links of testing tools, php testing resources, mock objects, junit, jwebunit, htmlunit, itc, php testing links, unit test advice and documentation, extreme programming in php Marcus Baker Primary Developer{@link mailto:marcus@lastcraft.com marcus@lastcraft.com} Harry Fuecks Packager{@link mailto:harryf@users.sourceforge.net harryf@users.sourceforge.net} Jason Sweat Documentation{@link mailto:jsweat_php@yahoo.com jsweat_php@yahoo.com}
    postfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/test/package/content_without_section.xml0000664000175000017620000000551711157271050034433 0ustar davidpalepurple Overview and feature list for the SimpleTest PHP unit tester and web tester

    A test case looks like this... MyTestCase extends UnitTestCase { function testLogWroteMessage() { $log = &new Log('my.log'); $log->message('Hello'); $this->assertTrue(file_exists('my.log')); } } ?> ]]>

    Quick summary of the SimpleTest tool for PHP. List of features, both current ones and those planned. There are plenty of unit testing resources on the web. Documentation for SimpleTest. How to write PHP test cases is a fairly advanced tutorial. SimpleTest API from phpdoc. software development tools, php programming, programming php, software development tools, Tools for extreme programming, free php scripts, links of testing tools, php testing resources, mock objects, junit, jwebunit, htmlunit, itc, php testing links, unit test advice and documentation, extreme programming in php Marcus Baker Primary Developer{@link mailto:marcus@lastcraft.com marcus@lastcraft.com} Harry Fuecks Packager{@link mailto:harryf@users.sourceforge.net harryf@users.sourceforge.net} Jason Sweat Documentation{@link mailto:jsweat_php@yahoo.com jsweat_php@yahoo.com}
    postfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/test/package/here_support.xml0000664000175000017620000000551611157271050032170 0ustar davidpalepurple Overview and feature list for the SimpleTest PHP unit tester and web tester

    A test case looks like this... MyTestCase extends UnitTestCase { function testLogWroteMessage() { $log = &new Log('my.log'); $log->message('Hello'); $this->assertTrue(file_exists('my.log')); } } ?> ]]>

    Quick summary of the SimpleTest tool for PHP. List of features, both current ones and those planned. There are plenty of unit testing resources on the web. Documentation for SimpleTest. How to write PHP test cases is a fairly advanced tutorial. SimpleTest API from phpdoc. software development tools, php programming, programming php, software development tools, Tools for extreme programming, free php scripts, links of testing tools, php testing resources, mock objects, junit, jwebunit, htmlunit, itc, php testing links, unit test advice and documentation, extreme programming in php Marcus Baker Primary Developer{@link mailto:marcus@lastcraft.com marcus@lastcraft.com} Harry Fuecks Packager{@link mailto:harryf@users.sourceforge.net harryf@users.sourceforge.net} Jason Sweat Documentation{@link mailto:jsweat_php@yahoo.com jsweat_php@yahoo.com}
    postfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/test/package/here_start_testing.xml0000664000175000017620000000551711157271050033347 0ustar davidpalepurple Overview and feature list for the SimpleTest PHP unit tester and web tester

    A test case looks like this... MyTestCase extends UnitTestCase { function testLogWroteMessage() { $log = &new Log('my.log'); $log->message('Hello'); $this->assertTrue(file_exists('my.log')); } } ?> ]]>

    Quick summary of the SimpleTest tool for PHP. List of features, both current ones and those planned. There are plenty of unit testing resources on the web. Documentation for SimpleTest. How to write PHP test cases is a fairly advanced tutorial. SimpleTest API from phpdoc. software development tools, php programming, programming php, software development tools, Tools for extreme programming, free php scripts, links of testing tools, php testing resources, mock objects, junit, jwebunit, htmlunit, itc, php testing links, unit test advice and documentation, extreme programming in php Marcus Baker Primary Developer{@link mailto:marcus@lastcraft.com marcus@lastcraft.com} Harry Fuecks Packager{@link mailto:harryf@users.sourceforge.net harryf@users.sourceforge.net} Jason Sweat Documentation{@link mailto:jsweat_php@yahoo.com jsweat_php@yahoo.com}
    postfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/template.html0000664000175000017620000000310211157271050027043 0ustar davidpalepurple TITLE
    LINKS_DOWNLOAD
    LINKS_START_TESTING
    LINKS_SUPPORT

    TITLE

    CONTENT
    postfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/map.xml0000664000175000017620000001241211157271050025645 0ustar davidpalepurple postfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/package.php0000664000175000017620000001552311157271050026460 0ustar davidpalepurplexpath('//page'); return $titles[0]->attributes()->title; } function transform_code($code) { $code = str_replace('', '', $code); $code = str_replace('<', '<', $code); $code = str_replace('>', '>', $code); $code = str_replace('<strong>', '', $code); $code = str_replace('</strong>', '', $code); return $code; } function content() { $content = ""; $sections = $this->xpath('//section'); if (count($sections) > 0) { $content = $this->content_with_sections(); } else { $content = $this->content_without_sections(); } return $content; } function content_without_sections() { $content_without_sections = ""; $contents = $this->xpath('//content'); foreach ($contents as $content) { $content_element = $content->asXML(); $elements_divided = preg_split('/|<\/php>/', $content_element); if (count($elements_divided) > 1) { $content_element = ''; foreach ($elements_divided as $element_divided) { if (strpos($element_divided, ''.$this->transform_code($element_divided).'
    '; } $content_element .= $element_divided; } } $content_without_sections .= $content_element; } return $content_without_sections; } function content_with_sections() { $content = ""; $sections = $this->xpath('//section'); foreach ($sections as $section) { $content .= "

    ".(string)$section->attributes()->title."

    "; foreach ($section as $element) { $content_element = $element->asXML(); $elements_divided = preg_split('/|<\/php>/', $content_element); if (count($elements_divided) > 1) { $content_element = ''; foreach ($elements_divided as $element_divided) { if (strpos($element_divided, ''.$this->transform_code($element_divided).''; } $content_element .= $element_divided; } } $content .= $content_element; } } return $content; } function here() { $pages = $this->xpath('//page'); return $pages[0]->attributes()->here; } function parent($map) { $here = $this->here(); $pages = $map->xpath('//page[normalize-space(@here)="'.$here.'"]/parent::*'); return $pages[0]->attributes()->here; } function destination($path_to_map) { $destination = ''; $here = $this->here(); $map = simplexml_load_file($path_to_map); $pages = $map->xpath('//page'); $i = 0; foreach ($pages as $page) { $i++; if ((string)$page->attributes()->here == $here) { $destination = (string)$page->attributes()->file; break; } } return $destination; } function url($file) { $segments = explode("/", $file); return array_pop($segments); } function links_from_xpath($xpath, $map) { $link = ""; $here = $this->here(); $pages = $map->xpath($xpath); foreach ($pages as $page) { $link .= '
  • '; $link .= $page->attributes()->title.'
  • '; } return $link; } function links_parent_siblings_after($map) { $here = $this->parent($map); $query = '//page[normalize-space(@here)="'.$here.'"]/following-sibling::*'; return $this->links_from_xpath($query, $map); } function links_parent($map) { $here = $this->parent($map); $query = '//page[normalize-space(@here)="'.$here.'"]'; return $this->links_from_xpath($query, $map); } function links_parent_siblings_before($map) { $here = $this->parent($map); $query = '//page[normalize-space(@here)="'.$here.'"]/preceding-sibling::*'; return $this->links_from_xpath($query, $map); } function links_parent_ancestors($map) { $here = $this->parent($map); return $this->links_ancestors_from($here, $map); } function links_self_ancestors($map) { $here = $this->here(); return $this->links_ancestors_from($here, $map); } function links_ancestors_from($here, $map) { $link = ""; $pages = $map->xpath('//page[normalize-space(@here)="'.$here.'"]/ancestor::*'); foreach ($pages as $page) { $here = (string)$page->attributes()->here; if ($this->level_from_root($here, $map) >= 2) { $link .= '
  • '; $link .= $page->attributes()->title.'
  • '; } } return $link; } function links_siblings_before($map) { $here = $this->here(); $query = '//page[normalize-space(@here)="'.$here.'"]/preceding-sibling::*'; return $this->links_from_xpath($query, $map); } function links_self($map) { $here = $this->here(); $query = '//page[normalize-space(@here)="'.$here.'"]'; return $this->links_from_xpath($query, $map); } function links_siblings_after($map) { $here = $this->here(); $query = '//page[normalize-space(@here)="'.$here.'"]/following-sibling::*'; return $this->links_from_xpath($query, $map); } function links_children($map) { $here = $this->here(); $query = '//page[normalize-space(@here)="'.$here.'"]/child::*'; return $this->links_from_xpath($query, $map); } function links($path_to_map) { $links['download'] = ""; $links['start_testing'] = ""; $links['support'] = ""; $map = simplexml_load_file($path_to_map); $link = '
      '; $here = $this->here(); $level = $this->level_from_root($here, $map); if ($level == 2) { $link .= $this->links_self($map); $link .= $this->links_children($map); } if ($level == 3) { $link .= $this->links_self_ancestors($map); $link .= $this->links_siblings_before($map); $link .= $this->links_self($map); $chilren = $this->links_children($map); if ($chilren) { $link = preg_replace('/(<\/li>)$/', '', $link).'
        '.$chilren.'
      '; } $link .= $this->links_siblings_after($map); } if ($level == 4) { $link .= $this->links_parent_ancestors($map); $link .= $this->links_parent_siblings_before($map); $link .= $this->links_parent($map); $link = preg_replace('/(<\/li>)$/', '', $link).'
        '; $link .= $this->links_siblings_before($map); $link .= $this->links_self($map); $chilren = $this->links_children($map); if ($chilren) { $link = preg_replace('/(<\/li>)$/', '', $link).'
          '.$chilren.'
        '; } $link .= $this->links_siblings_after($map); $link .= '
      '; $link .= $this->links_parent_siblings_after($map); } $link .= '
    '; if (strpos($link, 'download.html') !== false) { $links['download'] = $link; } elseif (strpos($link, 'start-testing.html') !== false) { $links['start_testing'] = $link; } elseif (strpos($link, 'support.html') !== false) { $links['support'] = $link; } return $links; } function level_from_root($here, $map) { $ancestors = $map->xpath('//page[normalize-space(@here)="'.$here.'"]/ancestor::*'); return count($ancestors); } } ?>postfixadmin-2.3.7/tests/simpletest/packages/simpletest.org/index.php0000664000175000017620000000240111157271050026163 0ustar davidpalepurpledestination("map.xml"); if (!empty($destination)) { $page = file_get_contents('template.html'); $page = str_replace('TITLE', $source->title(), $page); $page = str_replace('CONTENT', $source->content(), $page); $links = $source->links("map.xml"); foreach ($links as $category => $link) { $page = str_replace("LINKS_".strtoupper($category), $link, $page); } $destination_dir = dirname($destination_path.$destination); if (!is_dir($destination_dir)) { mkdir($destination_dir); } $ok = file_put_contents($destination_path.$destination, $page); if ($ok) { $result = "OK"; } else { $result = "KO"; } echo $destination_path.$destination." : ".$result."
    "; } } } closedir($dir); } ?>postfixadmin-2.3.7/tests/simpletest/packages/lastcraft.xslt0000664000175000017620000002525311157271050024275 0ustar davidpalepurple <xsl:value-of select="//long_title"/>

    ( pages)

    This page...
    Related...
                
                    
                
            
                
                    
                
            
                
            

    News:

    .php
  • postfixadmin-2.3.7/tests/simpletest/authentication.php0000664000175000017620000002021411157271050023340 0ustar davidpalepurple_type = $type; $this->_root = $url->getBasePath(); $this->_username = false; $this->_password = false; } /** * Adds another location to the realm. * @param SimpleUrl $url Somewhere in realm. * @access public */ function stretch($url) { $this->_root = $this->_getCommonPath($this->_root, $url->getPath()); } /** * Finds the common starting path. * @param string $first Path to compare. * @param string $second Path to compare. * @return string Common directories. * @access private */ function _getCommonPath($first, $second) { $first = explode('/', $first); $second = explode('/', $second); for ($i = 0; $i < min(count($first), count($second)); $i++) { if ($first[$i] != $second[$i]) { return implode('/', array_slice($first, 0, $i)) . '/'; } } return implode('/', $first) . '/'; } /** * Sets the identity to try within this realm. * @param string $username Username in authentication dialog. * @param string $username Password in authentication dialog. * @access public */ function setIdentity($username, $password) { $this->_username = $username; $this->_password = $password; } /** * Accessor for current identity. * @return string Last succesful username. * @access public */ function getUsername() { return $this->_username; } /** * Accessor for current identity. * @return string Last succesful password. * @access public */ function getPassword() { return $this->_password; } /** * Test to see if the URL is within the directory * tree of the realm. * @param SimpleUrl $url URL to test. * @return boolean True if subpath. * @access public */ function isWithin($url) { if ($this->_isIn($this->_root, $url->getBasePath())) { return true; } if ($this->_isIn($this->_root, $url->getBasePath() . $url->getPage() . '/')) { return true; } return false; } /** * Tests to see if one string is a substring of * another. * @param string $part Small bit. * @param string $whole Big bit. * @return boolean True if the small bit is * in the big bit. * @access private */ function _isIn($part, $whole) { return strpos($whole, $part) === 0; } } /** * Manages security realms. * @package SimpleTest * @subpackage WebTester */ class SimpleAuthenticator { var $_realms; /** * Clears the realms. * @access public */ function SimpleAuthenticator() { $this->restartSession(); } /** * Starts with no realms set up. * @access public */ function restartSession() { $this->_realms = array(); } /** * Adds a new realm centered the current URL. * Browsers vary wildly on their behaviour in this * regard. Mozilla ignores the realm and presents * only when challenged, wasting bandwidth. IE * just carries on presenting until a new challenge * occours. SimpleTest tries to follow the spirit of * the original standards committee and treats the * base URL as the root of a file tree shaped realm. * @param SimpleUrl $url Base of realm. * @param string $type Authentication type for this * realm. Only Basic authentication * is currently supported. * @param string $realm Name of realm. * @access public */ function addRealm($url, $type, $realm) { $this->_realms[$url->getHost()][$realm] = new SimpleRealm($type, $url); } /** * Sets the current identity to be presented * against that realm. * @param string $host Server hosting realm. * @param string $realm Name of realm. * @param string $username Username for realm. * @param string $password Password for realm. * @access public */ function setIdentityForRealm($host, $realm, $username, $password) { if (isset($this->_realms[$host][$realm])) { $this->_realms[$host][$realm]->setIdentity($username, $password); } } /** * Finds the name of the realm by comparing URLs. * @param SimpleUrl $url URL to test. * @return SimpleRealm Name of realm. * @access private */ function _findRealmFromUrl($url) { if (! isset($this->_realms[$url->getHost()])) { return false; } foreach ($this->_realms[$url->getHost()] as $name => $realm) { if ($realm->isWithin($url)) { return $realm; } } return false; } /** * Presents the appropriate headers for this location. * @param SimpleHttpRequest $request Request to modify. * @param SimpleUrl $url Base of realm. * @access public */ function addHeaders(&$request, $url) { if ($url->getUsername() && $url->getPassword()) { $username = $url->getUsername(); $password = $url->getPassword(); } elseif ($realm = $this->_findRealmFromUrl($url)) { $username = $realm->getUsername(); $password = $realm->getPassword(); } else { return; } $this->addBasicHeaders($request, $username, $password); } /** * Presents the appropriate headers for this * location for basic authentication. * @param SimpleHttpRequest $request Request to modify. * @param string $username Username for realm. * @param string $password Password for realm. * @access public * @static */ function addBasicHeaders(&$request, $username, $password) { if ($username && $password) { $request->addHeaderLine( 'Authorization: Basic ' . base64_encode("$username:$password")); } } } ?>postfixadmin-2.3.7/tests/simpletest/errors.php0000664000175000017620000001601311157271050021637 0ustar davidpalepurpleSimpleInvokerDecorator($invoker); } /** * Invokes a test method and dispatches any * untrapped errors. Called back from * the visiting runner. * @param string $method Test method to call. * @access public */ function invoke($method) { $context = &SimpleTest::getContext(); $queue = &$context->get('SimpleErrorQueue'); $queue->setTestCase($this->GetTestCase()); set_error_handler('SimpleTestErrorHandler'); parent::invoke($method); while (list($severity, $message, $file, $line) = $queue->extract()) { $severity = SimpleErrorQueue::getSeverityAsString($severity); $test = &$this->getTestCase(); $test->error($severity, $message, $file, $line); } restore_error_handler(); } } /** * Singleton error queue used to record trapped * errors. * @package SimpleTest * @subpackage UnitTester */ class SimpleErrorQueue { var $_queue; var $_expectation_queue; var $_test; /** * Starts with an empty queue. */ function SimpleErrorQueue() { $this->clear(); } /** * Sets the currently running test case. * @param SimpleTestCase $test Test case to send messages to. * @access public */ function setTestCase(&$test) { $this->_test = &$test; } /** * Adds an error to the front of the queue. * @param integer $severity PHP error code. * @param string $content Text of error. * @param string $filename File error occoured in. * @param integer $line Line number of error. * @access public */ function add($severity, $content, $filename, $line) { $content = str_replace('%', '%%', $content); if (count($this->_expectation_queue)) { $this->_testLatestError($severity, $content, $filename, $line); } else { array_push( $this->_queue, array($severity, $content, $filename, $line)); } } /** * Tests the error against the most recent expected * error. * @param integer $severity PHP error code. * @param string $content Text of error. * @param string $filename File error occoured in. * @param integer $line Line number of error. * @access private */ function _testLatestError($severity, $content, $filename, $line) { list($expected, $message) = array_shift($this->_expectation_queue); $severity = $this->getSeverityAsString($severity); $is_match = $this->_test->assert( $expected, $content, sprintf($message, "%s -> PHP error [$content] severity [$severity] in [$filename] line [$line]")); if (! $is_match) { $this->_test->error($severity, $content, $filename, $line); } } /** * Pulls the earliest error from the queue. * @return False if none, or a list of error * information. Elements are: severity * as the PHP error code, the error message, * the file with the error, the line number * and a list of PHP super global arrays. * @access public */ function extract() { if (count($this->_queue)) { return array_shift($this->_queue); } return false; } /** * Discards the contents of the error queue. * @access public */ function clear() { $this->_queue = array(); $this->_expectation_queue = array(); } /** * @deprecated */ function assertNoErrors($message) { return $this->_test->assert( new TrueExpectation(), count($this->_queue) == 0, sprintf($message, 'Should be no errors')); } /** * @deprecated */ function assertError($expected, $message) { if (count($this->_queue) == 0) { $this->_test->fail(sprintf($message, 'Expected error not found')); return false; } list($severity, $content, $file, $line) = $this->extract(); $severity = $this->getSeverityAsString($severity); return $this->_test->assert( $expected, $content, sprintf($message, "Expected PHP error [$content] severity [$severity] in [$file] line [$line]")); } /** * Sets up an expectation of an error. If this is * not fulfilled at the end of the test, a failure * will occour. If the error does happen, then this * will cancel it out and send a pass message. * @param SimpleExpectation $expected Expected error match. * @param string $message Message to display. * @access public */ function expectError($expected, $message) { array_push( $this->_expectation_queue, array($expected, $message)); } /** * Converts an error code into it's string * representation. * @param $severity PHP integer error code. * @return String version of error code. * @access public * @static */ function getSeverityAsString($severity) { static $map = array( E_STRICT => 'E_STRICT', E_ERROR => 'E_ERROR', E_WARNING => 'E_WARNING', E_PARSE => 'E_PARSE', E_NOTICE => 'E_NOTICE', E_CORE_ERROR => 'E_CORE_ERROR', E_CORE_WARNING => 'E_CORE_WARNING', E_COMPILE_ERROR => 'E_COMPILE_ERROR', E_COMPILE_WARNING => 'E_COMPILE_WARNING', E_USER_ERROR => 'E_USER_ERROR', E_USER_WARNING => 'E_USER_WARNING', E_USER_NOTICE => 'E_USER_NOTICE'); return $map[$severity]; } } /** * Error handler that simply stashes any errors into the global * error queue. Simulates the existing behaviour with respect to * logging errors, but this feature may be removed in future. * @param $severity PHP error code. * @param $message Text of error. * @param $filename File error occoured in. * @param $line Line number of error. * @param $super_globals Hash of PHP super global arrays. * @static * @access public */ function SimpleTestErrorHandler($severity, $message, $filename, $line, $super_globals) { $severity = $severity & error_reporting(); if ($severity) { restore_error_handler(); if (ini_get('log_errors')) { $label = SimpleErrorQueue::getSeverityAsString($severity); error_log("$label: $message in $filename on line $line"); } $context = &SimpleTest::getContext(); $queue = &$context->get('SimpleErrorQueue'); $queue->add($severity, $message, $filename, $line); set_error_handler('SimpleTestErrorHandler'); } else { if (version_compare(phpversion(), '5.2') >= 0) { return false; } } } ?>postfixadmin-2.3.7/tests/simpletest/browser.php0000664000175000017620000011627711157271050022023 0ustar davidpalepurple_sequence = array(); $this->_position = -1; } /** * Test for no entries yet. * @return boolean True if empty. * @access private */ function _isEmpty() { return ($this->_position == -1); } /** * Test for being at the beginning. * @return boolean True if first. * @access private */ function _atBeginning() { return ($this->_position == 0) && ! $this->_isEmpty(); } /** * Test for being at the last entry. * @return boolean True if last. * @access private */ function _atEnd() { return ($this->_position + 1 >= count($this->_sequence)) && ! $this->_isEmpty(); } /** * Adds a successfully fetched page to the history. * @param SimpleUrl $url URL of fetch. * @param SimpleEncoding $parameters Any post data with the fetch. * @access public */ function recordEntry($url, $parameters) { $this->_dropFuture(); array_push( $this->_sequence, array('url' => $url, 'parameters' => $parameters)); $this->_position++; } /** * Last fully qualified URL for current history * position. * @return SimpleUrl URL for this position. * @access public */ function getUrl() { if ($this->_isEmpty()) { return false; } return $this->_sequence[$this->_position]['url']; } /** * Parameters of last fetch from current history * position. * @return SimpleFormEncoding Post parameters. * @access public */ function getParameters() { if ($this->_isEmpty()) { return false; } return $this->_sequence[$this->_position]['parameters']; } /** * Step back one place in the history. Stops at * the first page. * @return boolean True if any previous entries. * @access public */ function back() { if ($this->_isEmpty() || $this->_atBeginning()) { return false; } $this->_position--; return true; } /** * Step forward one place. If already at the * latest entry then nothing will happen. * @return boolean True if any future entries. * @access public */ function forward() { if ($this->_isEmpty() || $this->_atEnd()) { return false; } $this->_position++; return true; } /** * Ditches all future entries beyond the current * point. * @access private */ function _dropFuture() { if ($this->_isEmpty()) { return; } while (! $this->_atEnd()) { array_pop($this->_sequence); } } } /** * Simulated web browser. This is an aggregate of * the user agent, the HTML parsing, request history * and the last header set. * @package SimpleTest * @subpackage WebTester */ class SimpleBrowser { var $_user_agent; var $_page; var $_history; var $_ignore_frames; var $_maximum_nested_frames; /** * Starts with a fresh browser with no * cookie or any other state information. The * exception is that a default proxy will be * set up if specified in the options. * @access public */ function SimpleBrowser() { $this->_user_agent = &$this->_createUserAgent(); $this->_user_agent->useProxy( SimpleTest::getDefaultProxy(), SimpleTest::getDefaultProxyUsername(), SimpleTest::getDefaultProxyPassword()); $this->_page = &new SimplePage(); $this->_history = &$this->_createHistory(); $this->_ignore_frames = false; $this->_maximum_nested_frames = DEFAULT_MAX_NESTED_FRAMES; } /** * Creates the underlying user agent. * @return SimpleFetcher Content fetcher. * @access protected */ function &_createUserAgent() { $user_agent = &new SimpleUserAgent(); return $user_agent; } /** * Creates a new empty history list. * @return SimpleBrowserHistory New list. * @access protected */ function &_createHistory() { $history = &new SimpleBrowserHistory(); return $history; } /** * Disables frames support. Frames will not be fetched * and the frameset page will be used instead. * @access public */ function ignoreFrames() { $this->_ignore_frames = true; } /** * Enables frames support. Frames will be fetched from * now on. * @access public */ function useFrames() { $this->_ignore_frames = false; } /** * Switches off cookie sending and recieving. * @access public */ function ignoreCookies() { $this->_user_agent->ignoreCookies(); } /** * Switches back on the cookie sending and recieving. * @access public */ function useCookies() { $this->_user_agent->useCookies(); } /** * Parses the raw content into a page. Will load further * frame pages unless frames are disabled. * @param SimpleHttpResponse $response Response from fetch. * @param integer $depth Nested frameset depth. * @return SimplePage Parsed HTML. * @access private */ function &_parse($response, $depth = 0) { $page = &$this->_buildPage($response); if ($this->_ignore_frames || ! $page->hasFrames() || ($depth > $this->_maximum_nested_frames)) { return $page; } $frameset = &new SimpleFrameset($page); foreach ($page->getFrameset() as $key => $url) { $frame = &$this->_fetch($url, new SimpleGetEncoding(), $depth + 1); $frameset->addFrame($frame, $key); } return $frameset; } /** * Assembles the parsing machinery and actually parses * a single page. Frees all of the builder memory and so * unjams the PHP memory management. * @param SimpleHttpResponse $response Response from fetch. * @return SimplePage Parsed top level page. * @access protected */ function &_buildPage($response) { $builder = &new SimplePageBuilder(); $page = &$builder->parse($response); $builder->free(); unset($builder); return $page; } /** * Fetches a page. Jointly recursive with the _parse() * method as it descends a frameset. * @param string/SimpleUrl $url Target to fetch. * @param SimpleEncoding $encoding GET/POST parameters. * @param integer $depth Nested frameset depth protection. * @return SimplePage Parsed page. * @access private */ function &_fetch($url, $encoding, $depth = 0) { $response = &$this->_user_agent->fetchResponse($url, $encoding); if ($response->isError()) { $page = &new SimplePage($response); } else { $page = &$this->_parse($response, $depth); } return $page; } /** * Fetches a page or a single frame if that is the current * focus. * @param SimpleUrl $url Target to fetch. * @param SimpleEncoding $parameters GET/POST parameters. * @return string Raw content of page. * @access private */ function _load($url, $parameters) { $frame = $url->getTarget(); if (! $frame || ! $this->_page->hasFrames() || (strtolower($frame) == '_top')) { return $this->_loadPage($url, $parameters); } return $this->_loadFrame(array($frame), $url, $parameters); } /** * Fetches a page and makes it the current page/frame. * @param string/SimpleUrl $url Target to fetch as string. * @param SimplePostEncoding $parameters POST parameters. * @return string Raw content of page. * @access private */ function _loadPage($url, $parameters) { $this->_page = &$this->_fetch($url, $parameters); $this->_history->recordEntry( $this->_page->getUrl(), $this->_page->getRequestData()); return $this->_page->getRaw(); } /** * Fetches a frame into the existing frameset replacing the * original. * @param array $frames List of names to drill down. * @param string/SimpleUrl $url Target to fetch as string. * @param SimpleFormEncoding $parameters POST parameters. * @return string Raw content of page. * @access private */ function _loadFrame($frames, $url, $parameters) { $page = &$this->_fetch($url, $parameters); $this->_page->setFrame($frames, $page); } /** * Removes expired and temporary cookies as if * the browser was closed and re-opened. * @param string/integer $date Time when session restarted. * If omitted then all persistent * cookies are kept. * @access public */ function restart($date = false) { $this->_user_agent->restart($date); } /** * Adds a header to every fetch. * @param string $header Header line to add to every * request until cleared. * @access public */ function addHeader($header) { $this->_user_agent->addHeader($header); } /** * Ages the cookies by the specified time. * @param integer $interval Amount in seconds. * @access public */ function ageCookies($interval) { $this->_user_agent->ageCookies($interval); } /** * Sets an additional cookie. If a cookie has * the same name and path it is replaced. * @param string $name Cookie key. * @param string $value Value of cookie. * @param string $host Host upon which the cookie is valid. * @param string $path Cookie path if not host wide. * @param string $expiry Expiry date. * @access public */ function setCookie($name, $value, $host = false, $path = '/', $expiry = false) { $this->_user_agent->setCookie($name, $value, $host, $path, $expiry); } /** * Reads the most specific cookie value from the * browser cookies. * @param string $host Host to search. * @param string $path Applicable path. * @param string $name Name of cookie to read. * @return string False if not present, else the * value as a string. * @access public */ function getCookieValue($host, $path, $name) { return $this->_user_agent->getCookieValue($host, $path, $name); } /** * Reads the current cookies for the current URL. * @param string $name Key of cookie to find. * @return string Null if there is no current URL, false * if the cookie is not set. * @access public */ function getCurrentCookieValue($name) { return $this->_user_agent->getBaseCookieValue($name, $this->_page->getUrl()); } /** * Sets the maximum number of redirects before * a page will be loaded anyway. * @param integer $max Most hops allowed. * @access public */ function setMaximumRedirects($max) { $this->_user_agent->setMaximumRedirects($max); } /** * Sets the maximum number of nesting of framed pages * within a framed page to prevent loops. * @param integer $max Highest depth allowed. * @access public */ function setMaximumNestedFrames($max) { $this->_maximum_nested_frames = $max; } /** * Sets the socket timeout for opening a connection. * @param integer $timeout Maximum time in seconds. * @access public */ function setConnectionTimeout($timeout) { $this->_user_agent->setConnectionTimeout($timeout); } /** * Sets proxy to use on all requests for when * testing from behind a firewall. Set URL * to false to disable. * @param string $proxy Proxy URL. * @param string $username Proxy username for authentication. * @param string $password Proxy password for authentication. * @access public */ function useProxy($proxy, $username = false, $password = false) { $this->_user_agent->useProxy($proxy, $username, $password); } /** * Fetches the page content with a HEAD request. * Will affect cookies, but will not change the base URL. * @param string/SimpleUrl $url Target to fetch as string. * @param hash/SimpleHeadEncoding $parameters Additional parameters for * HEAD request. * @return boolean True if successful. * @access public */ function head($url, $parameters = false) { if (! is_object($url)) { $url = new SimpleUrl($url); } if ($this->getUrl()) { $url = $url->makeAbsolute($this->getUrl()); } $response = &$this->_user_agent->fetchResponse($url, new SimpleHeadEncoding($parameters)); return ! $response->isError(); } /** * Fetches the page content with a simple GET request. * @param string/SimpleUrl $url Target to fetch. * @param hash/SimpleFormEncoding $parameters Additional parameters for * GET request. * @return string Content of page or false. * @access public */ function get($url, $parameters = false) { if (! is_object($url)) { $url = new SimpleUrl($url); } if ($this->getUrl()) { $url = $url->makeAbsolute($this->getUrl()); } return $this->_load($url, new SimpleGetEncoding($parameters)); } /** * Fetches the page content with a POST request. * @param string/SimpleUrl $url Target to fetch as string. * @param hash/SimpleFormEncoding $parameters POST parameters. * @return string Content of page. * @access public */ function post($url, $parameters = false) { if (! is_object($url)) { $url = new SimpleUrl($url); } if ($this->getUrl()) { $url = $url->makeAbsolute($this->getUrl()); } return $this->_load($url, new SimplePostEncoding($parameters)); } /** * Equivalent to hitting the retry button on the * browser. Will attempt to repeat the page fetch. If * there is no history to repeat it will give false. * @return string/boolean Content if fetch succeeded * else false. * @access public */ function retry() { $frames = $this->_page->getFrameFocus(); if (count($frames) > 0) { $this->_loadFrame( $frames, $this->_page->getUrl(), $this->_page->getRequestData()); return $this->_page->getRaw(); } if ($url = $this->_history->getUrl()) { $this->_page = &$this->_fetch($url, $this->_history->getParameters()); return $this->_page->getRaw(); } return false; } /** * Equivalent to hitting the back button on the * browser. The browser history is unchanged on * failure. The page content is refetched as there * is no concept of content caching in SimpleTest. * @return boolean True if history entry and * fetch succeeded * @access public */ function back() { if (! $this->_history->back()) { return false; } $content = $this->retry(); if (! $content) { $this->_history->forward(); } return $content; } /** * Equivalent to hitting the forward button on the * browser. The browser history is unchanged on * failure. The page content is refetched as there * is no concept of content caching in SimpleTest. * @return boolean True if history entry and * fetch succeeded * @access public */ function forward() { if (! $this->_history->forward()) { return false; } $content = $this->retry(); if (! $content) { $this->_history->back(); } return $content; } /** * Retries a request after setting the authentication * for the current realm. * @param string $username Username for realm. * @param string $password Password for realm. * @return boolean True if successful fetch. Note * that authentication may still have * failed. * @access public */ function authenticate($username, $password) { if (! $this->_page->getRealm()) { return false; } $url = $this->_page->getUrl(); if (! $url) { return false; } $this->_user_agent->setIdentity( $url->getHost(), $this->_page->getRealm(), $username, $password); return $this->retry(); } /** * Accessor for a breakdown of the frameset. * @return array Hash tree of frames by name * or index if no name. * @access public */ function getFrames() { return $this->_page->getFrames(); } /** * Accessor for current frame focus. Will be * false if no frame has focus. * @return integer/string/boolean Label if any, otherwise * the position in the frameset * or false if none. * @access public */ function getFrameFocus() { return $this->_page->getFrameFocus(); } /** * Sets the focus by index. The integer index starts from 1. * @param integer $choice Chosen frame. * @return boolean True if frame exists. * @access public */ function setFrameFocusByIndex($choice) { return $this->_page->setFrameFocusByIndex($choice); } /** * Sets the focus by name. * @param string $name Chosen frame. * @return boolean True if frame exists. * @access public */ function setFrameFocus($name) { return $this->_page->setFrameFocus($name); } /** * Clears the frame focus. All frames will be searched * for content. * @access public */ function clearFrameFocus() { return $this->_page->clearFrameFocus(); } /** * Accessor for last error. * @return string Error from last response. * @access public */ function getTransportError() { return $this->_page->getTransportError(); } /** * Accessor for current MIME type. * @return string MIME type as string; e.g. 'text/html' * @access public */ function getMimeType() { return $this->_page->getMimeType(); } /** * Accessor for last response code. * @return integer Last HTTP response code received. * @access public */ function getResponseCode() { return $this->_page->getResponseCode(); } /** * Accessor for last Authentication type. Only valid * straight after a challenge (401). * @return string Description of challenge type. * @access public */ function getAuthentication() { return $this->_page->getAuthentication(); } /** * Accessor for last Authentication realm. Only valid * straight after a challenge (401). * @return string Name of security realm. * @access public */ function getRealm() { return $this->_page->getRealm(); } /** * Accessor for current URL of page or frame if * focused. * @return string Location of current page or frame as * a string. */ function getUrl() { $url = $this->_page->getUrl(); return $url ? $url->asString() : false; } /** * Accessor for raw bytes sent down the wire. * @return string Original text sent. * @access public */ function getRequest() { return $this->_page->getRequest(); } /** * Accessor for raw header information. * @return string Header block. * @access public */ function getHeaders() { return $this->_page->getHeaders(); } /** * Accessor for raw page information. * @return string Original text content of web page. * @access public */ function getContent() { return $this->_page->getRaw(); } /** * Accessor for plain text version of the page. * @return string Normalised text representation. * @access public */ function getContentAsText() { return $this->_page->getText(); } /** * Accessor for parsed title. * @return string Title or false if no title is present. * @access public */ function getTitle() { return $this->_page->getTitle(); } /** * Accessor for a list of all fixed links in current page. * @return array List of urls with scheme of * http or https and hostname. * @access public */ function getAbsoluteUrls() { return $this->_page->getAbsoluteUrls(); } /** * Accessor for a list of all relative links. * @return array List of urls without hostname. * @access public */ function getRelativeUrls() { return $this->_page->getRelativeUrls(); } /** * Sets all form fields with that name. * @param string $label Name or label of field in forms. * @param string $value New value of field. * @return boolean True if field exists, otherwise false. * @access public */ function setField($label, $value) { return $this->_page->setField(new SimpleByLabelOrName($label), $value); } /** * Sets all form fields with that name. Will use label if * one is available (not yet implemented). * @param string $name Name of field in forms. * @param string $value New value of field. * @return boolean True if field exists, otherwise false. * @access public */ function setFieldByName($name, $value) { return $this->_page->setField(new SimpleByName($name), $value); } /** * Sets all form fields with that id attribute. * @param string/integer $id Id of field in forms. * @param string $value New value of field. * @return boolean True if field exists, otherwise false. * @access public */ function setFieldById($id, $value) { return $this->_page->setField(new SimpleById($id), $value); } /** * Accessor for a form element value within the page. * Finds the first match. * @param string $label Field label. * @return string/boolean A value if the field is * present, false if unchecked * and null if missing. * @access public */ function getField($label) { return $this->_page->getField(new SimpleByLabelOrName($label)); } /** * Accessor for a form element value within the page. * Finds the first match. * @param string $name Field name. * @return string/boolean A string if the field is * present, false if unchecked * and null if missing. * @access public */ function getFieldByName($name) { return $this->_page->getField(new SimpleByName($name)); } /** * Accessor for a form element value within the page. * @param string/integer $id Id of field in forms. * @return string/boolean A string if the field is * present, false if unchecked * and null if missing. * @access public */ function getFieldById($id) { return $this->_page->getField(new SimpleById($id)); } /** * Clicks the submit button by label. The owning * form will be submitted by this. * @param string $label Button label. An unlabeled * button can be triggered by 'Submit'. * @param hash $additional Additional form data. * @return string/boolean Page on success. * @access public */ function clickSubmit($label = 'Submit', $additional = false) { if (! ($form = &$this->_page->getFormBySubmit(new SimpleByLabel($label)))) { return false; } $success = $this->_load( $form->getAction(), $form->submitButton(new SimpleByLabel($label), $additional)); return ($success ? $this->getContent() : $success); } /** * Clicks the submit button by name attribute. The owning * form will be submitted by this. * @param string $name Button name. * @param hash $additional Additional form data. * @return string/boolean Page on success. * @access public */ function clickSubmitByName($name, $additional = false) { if (! ($form = &$this->_page->getFormBySubmit(new SimpleByName($name)))) { return false; } $success = $this->_load( $form->getAction(), $form->submitButton(new SimpleByName($name), $additional)); return ($success ? $this->getContent() : $success); } /** * Clicks the submit button by ID attribute of the button * itself. The owning form will be submitted by this. * @param string $id Button ID. * @param hash $additional Additional form data. * @return string/boolean Page on success. * @access public */ function clickSubmitById($id, $additional = false) { if (! ($form = &$this->_page->getFormBySubmit(new SimpleById($id)))) { return false; } $success = $this->_load( $form->getAction(), $form->submitButton(new SimpleById($id), $additional)); return ($success ? $this->getContent() : $success); } /** * Tests to see if a submit button exists with this * label. * @param string $label Button label. * @return boolean True if present. * @access public */ function isSubmit($label) { return (boolean)$this->_page->getFormBySubmit(new SimpleByLabel($label)); } /** * Clicks the submit image by some kind of label. Usually * the alt tag or the nearest equivalent. The owning * form will be submitted by this. Clicking outside of * the boundary of the coordinates will result in * a failure. * @param string $label ID attribute of button. * @param integer $x X-coordinate of imaginary click. * @param integer $y Y-coordinate of imaginary click. * @param hash $additional Additional form data. * @return string/boolean Page on success. * @access public */ function clickImage($label, $x = 1, $y = 1, $additional = false) { if (! ($form = &$this->_page->getFormByImage(new SimpleByLabel($label)))) { return false; } $success = $this->_load( $form->getAction(), $form->submitImage(new SimpleByLabel($label), $x, $y, $additional)); return ($success ? $this->getContent() : $success); } /** * Clicks the submit image by the name. Usually * the alt tag or the nearest equivalent. The owning * form will be submitted by this. Clicking outside of * the boundary of the coordinates will result in * a failure. * @param string $name Name attribute of button. * @param integer $x X-coordinate of imaginary click. * @param integer $y Y-coordinate of imaginary click. * @param hash $additional Additional form data. * @return string/boolean Page on success. * @access public */ function clickImageByName($name, $x = 1, $y = 1, $additional = false) { if (! ($form = &$this->_page->getFormByImage(new SimpleByName($name)))) { return false; } $success = $this->_load( $form->getAction(), $form->submitImage(new SimpleByName($name), $x, $y, $additional)); return ($success ? $this->getContent() : $success); } /** * Clicks the submit image by ID attribute. The owning * form will be submitted by this. Clicking outside of * the boundary of the coordinates will result in * a failure. * @param integer/string $id ID attribute of button. * @param integer $x X-coordinate of imaginary click. * @param integer $y Y-coordinate of imaginary click. * @param hash $additional Additional form data. * @return string/boolean Page on success. * @access public */ function clickImageById($id, $x = 1, $y = 1, $additional = false) { if (! ($form = &$this->_page->getFormByImage(new SimpleById($id)))) { return false; } $success = $this->_load( $form->getAction(), $form->submitImage(new SimpleById($id), $x, $y, $additional)); return ($success ? $this->getContent() : $success); } /** * Tests to see if an image exists with this * title or alt text. * @param string $label Image text. * @return boolean True if present. * @access public */ function isImage($label) { return (boolean)$this->_page->getFormByImage(new SimpleByLabel($label)); } /** * Submits a form by the ID. * @param string $id The form ID. No submit button value * will be sent. * @return string/boolean Page on success. * @access public */ function submitFormById($id) { if (! ($form = &$this->_page->getFormById($id))) { return false; } $success = $this->_load( $form->getAction(), $form->submit()); return ($success ? $this->getContent() : $success); } /** * Finds a URL by label. Will find the first link * found with this link text by default, or a later * one if an index is given. The match ignores case and * white space issues. * @param string $label Text between the anchor tags. * @param integer $index Link position counting from zero. * @return string/boolean URL on success. * @access public */ function getLink($label, $index = 0) { $urls = $this->_page->getUrlsByLabel($label); if (count($urls) == 0) { return false; } if (count($urls) < $index + 1) { return false; } return $urls[$index]; } /** * Follows a link by label. Will click the first link * found with this link text by default, or a later * one if an index is given. The match ignores case and * white space issues. * @param string $label Text between the anchor tags. * @param integer $index Link position counting from zero. * @return string/boolean Page on success. * @access public */ function clickLink($label, $index = 0) { $url = $this->getLink($label, $index); if ($url === false) { return false; } $this->_load($url, new SimpleGetEncoding()); return $this->getContent(); } /** * Finds a link by id attribute. * @param string $id ID attribute value. * @return string/boolean URL on success. * @access public */ function getLinkById($id) { return $this->_page->getUrlById($id); } /** * Follows a link by id attribute. * @param string $id ID attribute value. * @return string/boolean Page on success. * @access public */ function clickLinkById($id) { if (! ($url = $this->getLinkById($id))) { return false; } $this->_load($url, new SimpleGetEncoding()); return $this->getContent(); } /** * Clicks a visible text item. Will first try buttons, * then links and then images. * @param string $label Visible text or alt text. * @return string/boolean Raw page or false. * @access public */ function click($label) { $raw = $this->clickSubmit($label); if (! $raw) { $raw = $this->clickLink($label); } if (! $raw) { $raw = $this->clickImage($label); } return $raw; } /** * Tests to see if a click target exists. * @param string $label Visible text or alt text. * @return boolean True if target present. * @access public */ function isClickable($label) { return $this->isSubmit($label) || ($this->getLink($label) !== false) || $this->isImage($label); } } ?>postfixadmin-2.3.7/tests/simpletest/url.php0000664000175000017620000004426211157271050021134 0ustar davidpalepurple_chompCoordinates($url); $this->setCoordinates($x, $y); $this->_scheme = $this->_chompScheme($url); list($this->_username, $this->_password) = $this->_chompLogin($url); $this->_host = $this->_chompHost($url); $this->_port = false; if (preg_match('/(.*?):(.*)/', $this->_host, $host_parts)) { $this->_host = $host_parts[1]; $this->_port = (integer)$host_parts[2]; } $this->_path = $this->_chompPath($url); $this->_request = $this->_parseRequest($this->_chompRequest($url)); $this->_fragment = (strncmp($url, "#", 1) == 0 ? substr($url, 1) : false); $this->_target = false; } /** * Extracts the X, Y coordinate pair from an image map. * @param string $url URL so far. The coordinates will be * removed. * @return array X, Y as a pair of integers. * @access private */ function _chompCoordinates(&$url) { if (preg_match('/(.*)\?(\d+),(\d+)$/', $url, $matches)) { $url = $matches[1]; return array((integer)$matches[2], (integer)$matches[3]); } return array(false, false); } /** * Extracts the scheme part of an incoming URL. * @param string $url URL so far. The scheme will be * removed. * @return string Scheme part or false. * @access private */ function _chompScheme(&$url) { if (preg_match('/(.*?):(\/\/)(.*)/', $url, $matches)) { $url = $matches[2] . $matches[3]; return $matches[1]; } return false; } /** * Extracts the username and password from the * incoming URL. The // prefix will be reattached * to the URL after the doublet is extracted. * @param string $url URL so far. The username and * password are removed. * @return array Two item list of username and * password. Will urldecode() them. * @access private */ function _chompLogin(&$url) { $prefix = ''; if (preg_match('/^(\/\/)(.*)/', $url, $matches)) { $prefix = $matches[1]; $url = $matches[2]; } if (preg_match('/(.*?)@(.*)/', $url, $matches)) { $url = $prefix . $matches[2]; $parts = split(":", $matches[1]); return array( urldecode($parts[0]), isset($parts[1]) ? urldecode($parts[1]) : false); } $url = $prefix . $url; return array(false, false); } /** * Extracts the host part of an incoming URL. * Includes the port number part. Will extract * the host if it starts with // or it has * a top level domain or it has at least two * dots. * @param string $url URL so far. The host will be * removed. * @return string Host part guess or false. * @access private */ function _chompHost(&$url) { if (preg_match('/^(\/\/)(.*?)(\/.*|\?.*|#.*|$)/', $url, $matches)) { $url = $matches[3]; return $matches[2]; } if (preg_match('/(.*?)(\.\.\/|\.\/|\/|\?|#|$)(.*)/', $url, $matches)) { $tlds = SimpleUrl::getAllTopLevelDomains(); if (preg_match('/[a-z0-9\-]+\.(' . $tlds . ')/i', $matches[1])) { $url = $matches[2] . $matches[3]; return $matches[1]; } elseif (preg_match('/[a-z0-9\-]+\.[a-z0-9\-]+\.[a-z0-9\-]+/i', $matches[1])) { $url = $matches[2] . $matches[3]; return $matches[1]; } } return false; } /** * Extracts the path information from the incoming * URL. Strips this path from the URL. * @param string $url URL so far. The host will be * removed. * @return string Path part or '/'. * @access private */ function _chompPath(&$url) { if (preg_match('/(.*?)(\?|#|$)(.*)/', $url, $matches)) { $url = $matches[2] . $matches[3]; return ($matches[1] ? $matches[1] : ''); } return ''; } /** * Strips off the request data. * @param string $url URL so far. The request will be * removed. * @return string Raw request part. * @access private */ function _chompRequest(&$url) { if (preg_match('/\?(.*?)(#|$)(.*)/', $url, $matches)) { $url = $matches[2] . $matches[3]; return $matches[1]; } return ''; } /** * Breaks the request down into an object. * @param string $raw Raw request. * @return SimpleFormEncoding Parsed data. * @access private */ function _parseRequest($raw) { $this->_raw = $raw; $request = new SimpleGetEncoding(); foreach (split("&", $raw) as $pair) { if (preg_match('/(.*?)=(.*)/', $pair, $matches)) { $request->add($matches[1], urldecode($matches[2])); } elseif ($pair) { $request->add($pair, ''); } } return $request; } /** * Accessor for protocol part. * @param string $default Value to use if not present. * @return string Scheme name, e.g "http". * @access public */ function getScheme($default = false) { return $this->_scheme ? $this->_scheme : $default; } /** * Accessor for user name. * @return string Username preceding host. * @access public */ function getUsername() { return $this->_username; } /** * Accessor for password. * @return string Password preceding host. * @access public */ function getPassword() { return $this->_password; } /** * Accessor for hostname and port. * @param string $default Value to use if not present. * @return string Hostname only. * @access public */ function getHost($default = false) { return $this->_host ? $this->_host : $default; } /** * Accessor for top level domain. * @return string Last part of host. * @access public */ function getTld() { $path_parts = pathinfo($this->getHost()); return (isset($path_parts['extension']) ? $path_parts['extension'] : false); } /** * Accessor for port number. * @return integer TCP/IP port number. * @access public */ function getPort() { return $this->_port; } /** * Accessor for path. * @return string Full path including leading slash if implied. * @access public */ function getPath() { if (! $this->_path && $this->_host) { return '/'; } return $this->_path; } /** * Accessor for page if any. This may be a * directory name if ambiguious. * @return Page name. * @access public */ function getPage() { if (! preg_match('/([^\/]*?)$/', $this->getPath(), $matches)) { return false; } return $matches[1]; } /** * Gets the path to the page. * @return string Path less the page. * @access public */ function getBasePath() { if (! preg_match('/(.*\/)[^\/]*?$/', $this->getPath(), $matches)) { return false; } return $matches[1]; } /** * Accessor for fragment at end of URL after the "#". * @return string Part after "#". * @access public */ function getFragment() { return $this->_fragment; } /** * Sets image coordinates. Set to false to clear * them. * @param integer $x Horizontal position. * @param integer $y Vertical position. * @access public */ function setCoordinates($x = false, $y = false) { if (($x === false) || ($y === false)) { $this->_x = $this->_y = false; return; } $this->_x = (integer)$x; $this->_y = (integer)$y; } /** * Accessor for horizontal image coordinate. * @return integer X value. * @access public */ function getX() { return $this->_x; } /** * Accessor for vertical image coordinate. * @return integer Y value. * @access public */ function getY() { return $this->_y; } /** * Accessor for current request parameters * in URL string form. Will return teh original request * if at all possible even if it doesn't make much * sense. * @return string Form is string "?a=1&b=2", etc. * @access public */ function getEncodedRequest() { if ($this->_raw) { $encoded = $this->_raw; } else { $encoded = $this->_request->asUrlRequest(); } if ($encoded) { return '?' . preg_replace('/^\?/', '', $encoded); } return ''; } /** * Adds an additional parameter to the request. * @param string $key Name of parameter. * @param string $value Value as string. * @access public */ function addRequestParameter($key, $value) { $this->_raw = false; $this->_request->add($key, $value); } /** * Adds additional parameters to the request. * @param hash/SimpleFormEncoding $parameters Additional * parameters. * @access public */ function addRequestParameters($parameters) { $this->_raw = false; $this->_request->merge($parameters); } /** * Clears down all parameters. * @access public */ function clearRequest() { $this->_raw = false; $this->_request = &new SimpleGetEncoding(); } /** * Gets the frame target if present. Although * not strictly part of the URL specification it * acts as similarily to the browser. * @return boolean/string Frame name or false if none. * @access public */ function getTarget() { return $this->_target; } /** * Attaches a frame target. * @param string $frame Name of frame. * @access public */ function setTarget($frame) { $this->_raw = false; $this->_target = $frame; } /** * Renders the URL back into a string. * @return string URL in canonical form. * @access public */ function asString() { $scheme = $identity = $host = $path = $encoded = $fragment = ''; if ($this->_username && $this->_password) { $identity = $this->_username . ':' . $this->_password . '@'; } if ($this->getHost()) { $scheme = $this->getScheme() ? $this->getScheme() : 'http'; $host = $this->getHost(); } if (substr($this->_path, 0, 1) == '/') { $path = $this->normalisePath($this->_path); } $encoded = $this->getEncodedRequest(); $fragment = $this->getFragment() ? '#'. $this->getFragment() : ''; $coords = $this->getX() === false ? '' : '?' . $this->getX() . ',' . $this->getY(); return "$scheme://$identity$host$path$encoded$fragment$coords"; } /** * Replaces unknown sections to turn a relative * URL into an absolute one. The base URL can * be either a string or a SimpleUrl object. * @param string/SimpleUrl $base Base URL. * @access public */ function makeAbsolute($base) { if (! is_object($base)) { $base = new SimpleUrl($base); } $scheme = $this->getScheme() ? $this->getScheme() : $base->getScheme(); if ($this->getHost()) { $host = $this->getHost(); $port = $this->getPort() ? ':' . $this->getPort() : ''; $identity = $this->getIdentity() ? $this->getIdentity() . '@' : ''; if (! $identity) { $identity = $base->getIdentity() ? $base->getIdentity() . '@' : ''; } } else { $host = $base->getHost(); $port = $base->getPort() ? ':' . $base->getPort() : ''; $identity = $base->getIdentity() ? $base->getIdentity() . '@' : ''; } $path = $this->normalisePath($this->_extractAbsolutePath($base)); $encoded = $this->getEncodedRequest(); $fragment = $this->getFragment() ? '#'. $this->getFragment() : ''; $coords = $this->getX() === false ? '' : '?' . $this->getX() . ',' . $this->getY(); return new SimpleUrl("$scheme://$identity$host$port$path$encoded$fragment$coords"); } /** * Replaces unknown sections of the path with base parts * to return a complete absolute one. * @param string/SimpleUrl $base Base URL. * @param string Absolute path. * @access private */ function _extractAbsolutePath($base) { if ($this->getHost()) { return $this->_path; } if (! $this->_isRelativePath($this->_path)) { return $this->_path; } if ($this->_path) { return $base->getBasePath() . $this->_path; } return $base->getPath(); } /** * Simple test to see if a path part is relative. * @param string $path Path to test. * @return boolean True if starts with a "/". * @access private */ function _isRelativePath($path) { return (substr($path, 0, 1) != '/'); } /** * Extracts the username and password for use in rendering * a URL. * @return string/boolean Form of username:password or false. * @access public */ function getIdentity() { if ($this->_username && $this->_password) { return $this->_username . ':' . $this->_password; } return false; } /** * Replaces . and .. sections of the path. * @param string $path Unoptimised path. * @return string Path with dots removed if possible. * @access public */ function normalisePath($path) { $path = preg_replace('|/\./|', '/', $path); return preg_replace('|/[^/]+/\.\./|', '/', $path); } /** * A pipe seperated list of all TLDs that result in two part * domain names. * @return string Pipe separated list. * @access public * @static */ function getAllTopLevelDomains() { return 'com|edu|net|org|gov|mil|int|biz|info|name|pro|aero|coop|museum'; } } ?>postfixadmin-2.3.7/tests/simpletest/mock_objects.php0000664000175000017620000015115411157271050022773 0ustar davidpalepurple= 0) { require_once(dirname(__FILE__) . '/reflection_php5.php'); } else { require_once(dirname(__FILE__) . '/reflection_php4.php'); } /**#@-*/ /** * Default character simpletest will substitute for any value */ if (! defined('MOCK_ANYTHING')) { define('MOCK_ANYTHING', '*'); } /** * Parameter comparison assertion. * @package SimpleTest * @subpackage MockObjects */ class ParametersExpectation extends SimpleExpectation { var $_expected; /** * Sets the expected parameter list. * @param array $parameters Array of parameters including * those that are wildcarded. * If the value is not an array * then it is considered to match any. * @param string $message Customised message on failure. * @access public */ function ParametersExpectation($expected = false, $message = '%s') { $this->SimpleExpectation($message); $this->_expected = $expected; } /** * Tests the assertion. True if correct. * @param array $parameters Comparison values. * @return boolean True if correct. * @access public */ function test($parameters) { if (! is_array($this->_expected)) { return true; } if (count($this->_expected) != count($parameters)) { return false; } for ($i = 0; $i < count($this->_expected); $i++) { if (! $this->_testParameter($parameters[$i], $this->_expected[$i])) { return false; } } return true; } /** * Tests an individual parameter. * @param mixed $parameter Value to test. * @param mixed $expected Comparison value. * @return boolean True if expectation * fulfilled. * @access private */ function _testParameter($parameter, $expected) { $comparison = $this->_coerceToExpectation($expected); return $comparison->test($parameter); } /** * Returns a human readable test message. * @param array $comparison Incoming parameter list. * @return string Description of success * or failure. * @access public */ function testMessage($parameters) { if ($this->test($parameters)) { return "Expectation of " . count($this->_expected) . " arguments of [" . $this->_renderArguments($this->_expected) . "] is correct"; } else { return $this->_describeDifference($this->_expected, $parameters); } } /** * Message to display if expectation differs from * the parameters actually received. * @param array $expected Expected parameters as list. * @param array $parameters Actual parameters received. * @return string Description of difference. * @access private */ function _describeDifference($expected, $parameters) { if (count($expected) != count($parameters)) { return "Expected " . count($expected) . " arguments of [" . $this->_renderArguments($expected) . "] but got " . count($parameters) . " arguments of [" . $this->_renderArguments($parameters) . "]"; } $messages = array(); for ($i = 0; $i < count($expected); $i++) { $comparison = $this->_coerceToExpectation($expected[$i]); if (! $comparison->test($parameters[$i])) { $messages[] = "parameter " . ($i + 1) . " with [" . $comparison->overlayMessage($parameters[$i], $this->_getDumper()) . "]"; } } return "Parameter expectation differs at " . implode(" and ", $messages); } /** * Creates an identical expectation if the * object/value is not already some type * of expectation. * @param mixed $expected Expected value. * @return SimpleExpectation Expectation object. * @access private */ function _coerceToExpectation($expected) { if (SimpleExpectation::isExpectation($expected)) { return $expected; } return new IdenticalExpectation($expected); } /** * Renders the argument list as a string for * messages. * @param array $args Incoming arguments. * @return string Simple description of type and value. * @access private */ function _renderArguments($args) { $descriptions = array(); if (is_array($args)) { foreach ($args as $arg) { $dumper = &new SimpleDumper(); $descriptions[] = $dumper->describeValue($arg); } } return implode(', ', $descriptions); } } /** * Confirms that the number of calls on a method is as expected. * @package SimpleTest * @subpackage MockObjects */ class CallCountExpectation extends SimpleExpectation { var $_method; var $_count; /** * Stashes the method and expected count for later * reporting. * @param string $method Name of method to confirm against. * @param integer $count Expected number of calls. * @param string $message Custom error message. */ function CallCountExpectation($method, $count, $message = '%s') { $this->_method = $method; $this->_count = $count; $this->SimpleExpectation($message); } /** * Tests the assertion. True if correct. * @param integer $compare Measured call count. * @return boolean True if expected. * @access public */ function test($compare) { return ($this->_count == $compare); } /** * Reports the comparison. * @param integer $compare Measured call count. * @return string Message to show. * @access public */ function testMessage($compare) { return 'Expected call count for [' . $this->_method . '] was [' . $this->_count . '] got [' . $compare . ']'; } } /** * Confirms that the number of calls on a method is as expected. * @package SimpleTest * @subpackage MockObjects */ class MinimumCallCountExpectation extends SimpleExpectation { var $_method; var $_count; /** * Stashes the method and expected count for later * reporting. * @param string $method Name of method to confirm against. * @param integer $count Minimum number of calls. * @param string $message Custom error message. */ function MinimumCallCountExpectation($method, $count, $message = '%s') { $this->_method = $method; $this->_count = $count; $this->SimpleExpectation($message); } /** * Tests the assertion. True if correct. * @param integer $compare Measured call count. * @return boolean True if enough. * @access public */ function test($compare) { return ($this->_count <= $compare); } /** * Reports the comparison. * @param integer $compare Measured call count. * @return string Message to show. * @access public */ function testMessage($compare) { return 'Minimum call count for [' . $this->_method . '] was [' . $this->_count . '] got [' . $compare . ']'; } } /** * Confirms that the number of calls on a method is as expected. * @package SimpleTest * @subpackage MockObjects */ class MaximumCallCountExpectation extends SimpleExpectation { var $_method; var $_count; /** * Stashes the method and expected count for later * reporting. * @param string $method Name of method to confirm against. * @param integer $count Minimum number of calls. * @param string $message Custom error message. */ function MaximumCallCountExpectation($method, $count, $message = '%s') { $this->_method = $method; $this->_count = $count; $this->SimpleExpectation($message); } /** * Tests the assertion. True if correct. * @param integer $compare Measured call count. * @return boolean True if not over. * @access public */ function test($compare) { return ($this->_count >= $compare); } /** * Reports the comparison. * @param integer $compare Measured call count. * @return string Message to show. * @access public */ function testMessage($compare) { return 'Maximum call count for [' . $this->_method . '] was [' . $this->_count . '] got [' . $compare . ']'; } } /** * Retrieves values and references by searching the * parameter lists until a match is found. * @package SimpleTest * @subpackage MockObjects */ class CallMap { var $_map; /** * Creates an empty call map. * @access public */ function CallMap() { $this->_map = array(); } /** * Stashes a value against a method call. * @param array $parameters Arguments including wildcards. * @param mixed $value Value copied into the map. * @access public */ function addValue($parameters, $value) { $this->addReference($parameters, $value); } /** * Stashes a reference against a method call. * @param array $parameters Array of arguments (including wildcards). * @param mixed $reference Array reference placed in the map. * @access public */ function addReference($parameters, &$reference) { $place = count($this->_map); $this->_map[$place] = array(); $this->_map[$place]["params"] = new ParametersExpectation($parameters); $this->_map[$place]["content"] = &$reference; } /** * Searches the call list for a matching parameter * set. Returned by reference. * @param array $parameters Parameters to search by * without wildcards. * @return object Object held in the first matching * slot, otherwise null. * @access public */ function &findFirstMatch($parameters) { $slot = $this->_findFirstSlot($parameters); if (!isset($slot)) { $null = null; return $null; } return $slot["content"]; } /** * Searches the call list for a matching parameter * set. True if successful. * @param array $parameters Parameters to search by * without wildcards. * @return boolean True if a match is present. * @access public */ function isMatch($parameters) { return ($this->_findFirstSlot($parameters) != null); } /** * Searches the map for a matching item. * @param array $parameters Parameters to search by * without wildcards. * @return array Reference to slot or null. * @access private */ function &_findFirstSlot($parameters) { $count = count($this->_map); for ($i = 0; $i < $count; $i++) { if ($this->_map[$i]["params"]->test($parameters)) { return $this->_map[$i]; } } $null = null; return $null; } } /** * An empty collection of methods that can have their * return values set and expectations made of the * calls upon them. The mock will assert the * expectations against it's attached test case in * addition to the server stub behaviour. * @package SimpleTest * @subpackage MockObjects */ class SimpleMock { var $_wildcard = MOCK_ANYTHING; var $_is_strict = true; var $_returns; var $_return_sequence; var $_call_counts; var $_expected_counts; var $_max_counts; var $_expected_args; var $_expected_args_at; /** * Creates an empty return list and expectation list. * All call counts are set to zero. * @param SimpleTestCase $test Test case to test expectations in. * @param mixed $wildcard Parameter matching wildcard. * @param boolean $is_strict Enables method name checks on * expectations. */ function SimpleMock() { $this->_returns = array(); $this->_return_sequence = array(); $this->_call_counts = array(); $test = &$this->_getCurrentTestCase(); $test->tell($this); $this->_expected_counts = array(); $this->_max_counts = array(); $this->_expected_args = array(); $this->_expected_args_at = array(); } /** * Disables a name check when setting expectations. * This hack is needed for the partial mocks. * @access public */ function disableExpectationNameChecks() { $this->_is_strict = false; } /** * Finds currently running test. * @return SimpeTestCase Current test case. * @access protected */ function &_getCurrentTestCase() { $context = &SimpleTest::getContext(); return $context->getTest(); } /** * Die if bad arguments array is passed * @param mixed $args The arguments value to be checked. * @param string $task Description of task attempt. * @return boolean Valid arguments * @access private */ function _checkArgumentsIsArray($args, $task) { if (! is_array($args)) { trigger_error( "Cannot $task as \$args parameter is not an array", E_USER_ERROR); } } /** * Triggers a PHP error if the method is not part * of this object. * @param string $method Name of method. * @param string $task Description of task attempt. * @access protected */ function _dieOnNoMethod($method, $task) { if ($this->_is_strict && ! method_exists($this, $method)) { trigger_error( "Cannot $task as no ${method}() in class " . get_class($this), E_USER_ERROR); } } /** * Replaces wildcard matches with wildcard * expectations in the argument list. * @param array $args Raw argument list. * @return array Argument list with * expectations. * @access private */ function _replaceWildcards($args) { if ($args === false) { return false; } for ($i = 0; $i < count($args); $i++) { if ($args[$i] === $this->_wildcard) { $args[$i] = new AnythingExpectation(); } } return $args; } /** * Adds one to the call count of a method. * @param string $method Method called. * @param array $args Arguments as an array. * @access protected */ function _addCall($method, $args) { if (!isset($this->_call_counts[$method])) { $this->_call_counts[$method] = 0; } $this->_call_counts[$method]++; } /** * Fetches the call count of a method so far. * @param string $method Method name called. * @return Number of calls so far. * @access public */ function getCallCount($method) { $this->_dieOnNoMethod($method, "get call count"); $method = strtolower($method); if (! isset($this->_call_counts[$method])) { return 0; } return $this->_call_counts[$method]; } /** * Sets a return for a parameter list that will * be passed by value for all calls to this method. * @param string $method Method name. * @param mixed $value Result of call passed by value. * @param array $args List of parameters to match * including wildcards. * @access public */ function setReturnValue($method, $value, $args = false) { $this->_dieOnNoMethod($method, "set return value"); $args = $this->_replaceWildcards($args); $method = strtolower($method); if (! isset($this->_returns[$method])) { $this->_returns[$method] = new CallMap(); } $this->_returns[$method]->addValue($args, $value); } /** * Sets a return for a parameter list that will * be passed by value only when the required call count * is reached. * @param integer $timing Number of calls in the future * to which the result applies. If * not set then all calls will return * the value. * @param string $method Method name. * @param mixed $value Result of call passed by value. * @param array $args List of parameters to match * including wildcards. * @access public */ function setReturnValueAt($timing, $method, $value, $args = false) { $this->_dieOnNoMethod($method, "set return value sequence"); $args = $this->_replaceWildcards($args); $method = strtolower($method); if (! isset($this->_return_sequence[$method])) { $this->_return_sequence[$method] = array(); } if (! isset($this->_return_sequence[$method][$timing])) { $this->_return_sequence[$method][$timing] = new CallMap(); } $this->_return_sequence[$method][$timing]->addValue($args, $value); } /** * Sets a return for a parameter list that will * be passed by reference for all calls. * @param string $method Method name. * @param mixed $reference Result of the call will be this object. * @param array $args List of parameters to match * including wildcards. * @access public */ function setReturnReference($method, &$reference, $args = false) { $this->_dieOnNoMethod($method, "set return reference"); $args = $this->_replaceWildcards($args); $method = strtolower($method); if (! isset($this->_returns[$method])) { $this->_returns[$method] = new CallMap(); } $this->_returns[$method]->addReference($args, $reference); } /** * Sets a return for a parameter list that will * be passed by value only when the required call count * is reached. * @param integer $timing Number of calls in the future * to which the result applies. If * not set then all calls will return * the value. * @param string $method Method name. * @param mixed $reference Result of the call will be this object. * @param array $args List of parameters to match * including wildcards. * @access public */ function setReturnReferenceAt($timing, $method, &$reference, $args = false) { $this->_dieOnNoMethod($method, "set return reference sequence"); $args = $this->_replaceWildcards($args); $method = strtolower($method); if (! isset($this->_return_sequence[$method])) { $this->_return_sequence[$method] = array(); } if (! isset($this->_return_sequence[$method][$timing])) { $this->_return_sequence[$method][$timing] = new CallMap(); } $this->_return_sequence[$method][$timing]->addReference($args, $reference); } /** * Sets up an expected call with a set of * expected parameters in that call. All * calls will be compared to these expectations * regardless of when the call is made. * @param string $method Method call to test. * @param array $args Expected parameters for the call * including wildcards. * @param string $message Overridden message. * @access public */ function expect($method, $args, $message = '%s') { $this->_dieOnNoMethod($method, 'set expected arguments'); $this->_checkArgumentsIsArray($args, 'set expected arguments'); $args = $this->_replaceWildcards($args); $message .= Mock::getExpectationLine(); $this->_expected_args[strtolower($method)] = new ParametersExpectation($args, $message); } /** * @deprecated */ function expectArguments($method, $args, $message = '%s') { return $this->expect($method, $args, $message); } /** * Sets up an expected call with a set of * expected parameters in that call. The * expected call count will be adjusted if it * is set too low to reach this call. * @param integer $timing Number of calls in the future at * which to test. Next call is 0. * @param string $method Method call to test. * @param array $args Expected parameters for the call * including wildcards. * @param string $message Overridden message. * @access public */ function expectAt($timing, $method, $args, $message = '%s') { $this->_dieOnNoMethod($method, 'set expected arguments at time'); $this->_checkArgumentsIsArray($args, 'set expected arguments at time'); $args = $this->_replaceWildcards($args); if (! isset($this->_expected_args_at[$timing])) { $this->_expected_args_at[$timing] = array(); } $method = strtolower($method); $message .= Mock::getExpectationLine(); $this->_expected_args_at[$timing][$method] = new ParametersExpectation($args, $message); } /** * @deprecated */ function expectArgumentsAt($timing, $method, $args, $message = '%s') { return $this->expectAt($timing, $method, $args, $message); } /** * Sets an expectation for the number of times * a method will be called. The tally method * is used to check this. * @param string $method Method call to test. * @param integer $count Number of times it should * have been called at tally. * @param string $message Overridden message. * @access public */ function expectCallCount($method, $count, $message = '%s') { $this->_dieOnNoMethod($method, 'set expected call count'); $message .= Mock::getExpectationLine(); $this->_expected_counts[strtolower($method)] = new CallCountExpectation($method, $count, $message); } /** * Sets the number of times a method may be called * before a test failure is triggered. * @param string $method Method call to test. * @param integer $count Most number of times it should * have been called. * @param string $message Overridden message. * @access public */ function expectMaximumCallCount($method, $count, $message = '%s') { $this->_dieOnNoMethod($method, 'set maximum call count'); $message .= Mock::getExpectationLine(); $this->_max_counts[strtolower($method)] = new MaximumCallCountExpectation($method, $count, $message); } /** * Sets the number of times to call a method to prevent * a failure on the tally. * @param string $method Method call to test. * @param integer $count Least number of times it should * have been called. * @param string $message Overridden message. * @access public */ function expectMinimumCallCount($method, $count, $message = '%s') { $this->_dieOnNoMethod($method, 'set minimum call count'); $message .= Mock::getExpectationLine(); $this->_expected_counts[strtolower($method)] = new MinimumCallCountExpectation($method, $count, $message); } /** * Convenience method for barring a method * call. * @param string $method Method call to ban. * @param string $message Overridden message. * @access public */ function expectNever($method, $message = '%s') { $this->expectMaximumCallCount($method, 0, $message); } /** * Convenience method for a single method * call. * @param string $method Method call to track. * @param array $args Expected argument list or * false for any arguments. * @param string $message Overridden message. * @access public */ function expectOnce($method, $args = false, $message = '%s') { $this->expectCallCount($method, 1, $message); if ($args !== false) { $this->expectArguments($method, $args, $message); } } /** * Convenience method for requiring a method * call. * @param string $method Method call to track. * @param array $args Expected argument list or * false for any arguments. * @param string $message Overridden message. * @access public */ function expectAtLeastOnce($method, $args = false, $message = '%s') { $this->expectMinimumCallCount($method, 1, $message); if ($args !== false) { $this->expectArguments($method, $args, $message); } } /** * @deprecated */ function tally() { } /** * Receives event from unit test that the current * test method has finished. Totals up the call * counts and triggers a test assertion if a test * is present for expected call counts. * @param string $test_method Current method name. * @param SimpleTestCase $test Test to send message to. * @access public */ function atTestEnd($test_method, &$test) { foreach ($this->_expected_counts as $method => $expectation) { $test->assert($expectation, $this->getCallCount($method)); } foreach ($this->_max_counts as $method => $expectation) { if ($expectation->test($this->getCallCount($method))) { $test->assert($expectation, $this->getCallCount($method)); } } } /** * Returns the expected value for the method name * and checks expectations. Will generate any * test assertions as a result of expectations * if there is a test present. * @param string $method Name of method to simulate. * @param array $args Arguments as an array. * @return mixed Stored return. * @access private */ function &_invoke($method, $args) { $method = strtolower($method); $step = $this->getCallCount($method); $this->_addCall($method, $args); $this->_checkExpectations($method, $args, $step); $result = &$this->_getReturn($method, $args, $step); return $result; } /** * Finds the return value matching the incoming * arguments. If there is no matching value found * then an error is triggered. * @param string $method Method name. * @param array $args Calling arguments. * @param integer $step Current position in the * call history. * @return mixed Stored return. * @access protected */ function &_getReturn($method, $args, $step) { if (isset($this->_return_sequence[$method][$step])) { if ($this->_return_sequence[$method][$step]->isMatch($args)) { $result = &$this->_return_sequence[$method][$step]->findFirstMatch($args); return $result; } } if (isset($this->_returns[$method])) { $result = &$this->_returns[$method]->findFirstMatch($args); return $result; } $null = null; return $null; } /** * Tests the arguments against expectations. * @param string $method Method to check. * @param array $args Argument list to match. * @param integer $timing The position of this call * in the call history. * @access private */ function _checkExpectations($method, $args, $timing) { $test = &$this->_getCurrentTestCase(); if (isset($this->_max_counts[$method])) { if (! $this->_max_counts[$method]->test($timing + 1)) { $test->assert($this->_max_counts[$method], $timing + 1); } } if (isset($this->_expected_args_at[$timing][$method])) { $test->assert( $this->_expected_args_at[$timing][$method], $args, "Mock method [$method] at [$timing] -> %s"); } elseif (isset($this->_expected_args[$method])) { $test->assert( $this->_expected_args[$method], $args, "Mock method [$method] -> %s"); } } } /** * Static methods only service class for code generation of * mock objects. * @package SimpleTest * @subpackage MockObjects */ class Mock { /** * Factory for mock object classes. * @access public */ function Mock() { trigger_error('Mock factory methods are static.'); } /** * Clones a class' interface and creates a mock version * that can have return values and expectations set. * @param string $class Class to clone. * @param string $mock_class New class name. Default is * the old name with "Mock" * prepended. * @param array $methods Additional methods to add beyond * those in the cloned class. Use this * to emulate the dynamic addition of * methods in the cloned class or when * the class hasn't been written yet. * @static * @access public */ function generate($class, $mock_class = false, $methods = false) { $generator = new MockGenerator($class, $mock_class); return $generator->generate($methods); } /** * Temporary method while refactoring. */ function generateSubclass($class, $mock_class = false, $methods = array()) { $generator = new MockGenerator($class, $mock_class); return $generator->generateSubclass($methods); } /** * Generates a version of a class with selected * methods mocked only. Inherits the old class * and chains the mock methods of an aggregated * mock object. * @param string $class Class to clone. * @param string $mock_class New class name. * @param array $methods Methods to be overridden * with mock versions. * @static * @access public */ function generatePartial($class, $mock_class, $methods) { $generator = new MockGenerator($class, $mock_class); return $generator->generatePartial($methods); } /** * Uses a stack trace to find the line of an assertion. * @access public * @static */ function getExpectationLine() { $trace = new SimpleStackTrace(array('expect')); return $trace->traceMethod(); } } /** * @package SimpleTest * @subpackage MockObjects * @deprecated */ class Stub extends Mock { } /** * Service class for code generation of mock objects. * @package SimpleTest * @subpackage MockObjects */ class MockGenerator { var $_class; var $_mock_class; var $_mock_base; var $_reflection; function MockGenerator($class, $mock_class) { $this->_class = $class; $this->_mock_class = $mock_class; if (! $this->_mock_class) { $this->_mock_class = 'Mock' . $this->_class; } $this->_mock_base = SimpleTest::getMockBaseClass(); $this->_reflection = new SimpleReflection($this->_class); } /** * Clones a class' interface and creates a mock version * that can have return values and expectations set. * @param array $methods Additional methods to add beyond * those in th cloned class. Use this * to emulate the dynamic addition of * methods in the cloned class or when * the class hasn't been written yet. * @access public */ function generate($methods) { if (! $this->_reflection->classOrInterfaceExists()) { return false; } $mock_reflection = new SimpleReflection($this->_mock_class); if ($mock_reflection->classExistsSansAutoload()) { return false; } return eval( $this->_createClassCode($methods ? $methods : array()) . " return true;"); } /** * Subclasses a class and overrides every method with a mock one. * that can have return values and expectations set. * @param array $methods Additional methods to add beyond * those in th cloned class. Use this * to emulate the dynamic addition of * methods in the cloned class or when * the class hasn't been written yet. * @access public */ function generateSubclass($methods) { if (! $this->_reflection->classOrInterfaceExists()) { return false; } $mock_reflection = new SimpleReflection($this->_mock_class); if ($mock_reflection->classExistsSansAutoload()) { return false; } if ($this->_reflection->isInterface()) { return eval( $this->_createClassCode($methods ? $methods : array()) . " return true;"); } else { return eval( $this->_createSubclassCode($methods ? $methods : array()) . " return true;"); } } /** * Generates a version of a class with selected * methods mocked only. Inherits the old class * and chains the mock methods of an aggregated * mock object. * @param array $methods Methods to be overridden * with mock versions. * @access public */ function generatePartial($methods) { if (! $this->_reflection->classExists($this->_class)) { return false; } $mock_reflection = new SimpleReflection($this->_mock_class); if ($mock_reflection->classExistsSansAutoload()) { trigger_error('Partial mock class [' . $this->_mock_class . '] already exists'); return false; } return eval($this->_extendClassCode($methods)); } /** * The new mock class code as a string. * @param array $methods Additional methods. * @return string Code for new mock class. * @access private */ function _createClassCode($methods) { $implements = ''; $interfaces = $this->_reflection->getInterfaces(); if (function_exists('spl_classes')) { $interfaces = array_diff($interfaces, array('Traversable')); } if (count($interfaces) > 0) { $implements = 'implements ' . implode(', ', $interfaces); } $code = "class " . $this->_mock_class . " extends " . $this->_mock_base . " $implements {\n"; $code .= " function " . $this->_mock_class . "() {\n"; $code .= " \$this->" . $this->_mock_base . "();\n"; $code .= " }\n"; if (in_array('__construct', $this->_reflection->getMethods())) { $code .= " " . $this->_reflection->getSignature('__construct') . " {\n"; $code .= " \$this->" . $this->_mock_base . "();\n"; $code .= " }\n"; } $code .= $this->_createHandlerCode($methods); $code .= "}\n"; return $code; } /** * The new mock class code as a string. The mock will * be a subclass of the original mocked class. * @param array $methods Additional methods. * @return string Code for new mock class. * @access private */ function _createSubclassCode($methods) { $code = "class " . $this->_mock_class . " extends " . $this->_class . " {\n"; $code .= " var \$_mock;\n"; $code .= $this->_addMethodList(array_merge($methods, $this->_reflection->getMethods())); $code .= "\n"; $code .= " function " . $this->_mock_class . "() {\n"; $code .= " \$this->_mock = &new " . $this->_mock_base . "();\n"; $code .= " \$this->_mock->disableExpectationNameChecks();\n"; $code .= " }\n"; $code .= $this->_chainMockReturns(); $code .= $this->_chainMockExpectations(); $code .= $this->_overrideMethods($this->_reflection->getMethods()); $code .= $this->_createNewMethodCode($methods); $code .= "}\n"; return $code; } /** * The extension class code as a string. The class * composites a mock object and chains mocked methods * to it. * @param array $methods Mocked methods. * @return string Code for a new class. * @access private */ function _extendClassCode($methods) { $code = "class " . $this->_mock_class . " extends " . $this->_class . " {\n"; $code .= " var \$_mock;\n"; $code .= $this->_addMethodList($methods); $code .= "\n"; $code .= " function " . $this->_mock_class . "() {\n"; $code .= " \$this->_mock = &new " . $this->_mock_base . "();\n"; $code .= " \$this->_mock->disableExpectationNameChecks();\n"; $code .= " }\n"; $code .= $this->_chainMockReturns(); $code .= $this->_chainMockExpectations(); $code .= $this->_overrideMethods($methods); $code .= "}\n"; return $code; } /** * Creates code within a class to generate replaced * methods. All methods call the _invoke() handler * with the method name and the arguments in an * array. * @param array $methods Additional methods. * @access private */ function _createHandlerCode($methods) { $code = ''; $methods = array_merge($methods, $this->_reflection->getMethods()); foreach ($methods as $method) { if ($this->_isConstructor($method)) { continue; } $mock_reflection = new SimpleReflection($this->_mock_base); if (in_array($method, $mock_reflection->getMethods())) { continue; } $code .= " " . $this->_reflection->getSignature($method) . " {\n"; $code .= " \$args = func_get_args();\n"; $code .= " \$result = &\$this->_invoke(\"$method\", \$args);\n"; $code .= " return \$result;\n"; $code .= " }\n"; } return $code; } /** * Creates code within a class to generate a new * methods. All methods call the _invoke() handler * on the internal mock with the method name and * the arguments in an array. * @param array $methods Additional methods. * @access private */ function _createNewMethodCode($methods) { $code = ''; foreach ($methods as $method) { if ($this->_isConstructor($method)) { continue; } $mock_reflection = new SimpleReflection($this->_mock_base); if (in_array($method, $mock_reflection->getMethods())) { continue; } $code .= " " . $this->_reflection->getSignature($method) . " {\n"; $code .= " \$args = func_get_args();\n"; $code .= " \$result = &\$this->_mock->_invoke(\"$method\", \$args);\n"; $code .= " return \$result;\n"; $code .= " }\n"; } return $code; } /** * Tests to see if a special PHP method is about to * be stubbed by mistake. * @param string $method Method name. * @return boolean True if special. * @access private */ function _isConstructor($method) { return in_array( strtolower($method), array('__construct', '__destruct')); } /** * Creates a list of mocked methods for error checking. * @param array $methods Mocked methods. * @return string Code for a method list. * @access private */ function _addMethodList($methods) { return " var \$_mocked_methods = array('" . implode("', '", $methods) . "');\n"; } /** * Creates code to abandon the expectation if not mocked. * @param string $alias Parameter name of method name. * @return string Code for bail out. * @access private */ function _bailOutIfNotMocked($alias) { $code = " if (! in_array($alias, \$this->_mocked_methods)) {\n"; $code .= " trigger_error(\"Method [$alias] is not mocked\");\n"; $code .= " \$null = null;\n"; $code .= " return \$null;\n"; $code .= " }\n"; return $code; } /** * Creates source code for chaining to the composited * mock object. * @return string Code for mock set up. * @access private */ function _chainMockReturns() { $code = " function setReturnValue(\$method, \$value, \$args = false) {\n"; $code .= $this->_bailOutIfNotMocked("\$method"); $code .= " \$this->_mock->setReturnValue(\$method, \$value, \$args);\n"; $code .= " }\n"; $code .= " function setReturnValueAt(\$timing, \$method, \$value, \$args = false) {\n"; $code .= $this->_bailOutIfNotMocked("\$method"); $code .= " \$this->_mock->setReturnValueAt(\$timing, \$method, \$value, \$args);\n"; $code .= " }\n"; $code .= " function setReturnReference(\$method, &\$ref, \$args = false) {\n"; $code .= $this->_bailOutIfNotMocked("\$method"); $code .= " \$this->_mock->setReturnReference(\$method, \$ref, \$args);\n"; $code .= " }\n"; $code .= " function setReturnReferenceAt(\$timing, \$method, &\$ref, \$args = false) {\n"; $code .= $this->_bailOutIfNotMocked("\$method"); $code .= " \$this->_mock->setReturnReferenceAt(\$timing, \$method, \$ref, \$args);\n"; $code .= " }\n"; return $code; } /** * Creates source code for chaining to an aggregated * mock object. * @return string Code for expectations. * @access private */ function _chainMockExpectations() { $code = " function expect(\$method, \$args = false, \$msg = '%s') {\n"; $code .= $this->_bailOutIfNotMocked("\$method"); $code .= " \$this->_mock->expect(\$method, \$args, \$msg);\n"; $code .= " }\n"; $code .= " function expectArguments(\$method, \$args = false, \$msg = '%s') {\n"; $code .= $this->_bailOutIfNotMocked("\$method"); $code .= " \$this->_mock->expectArguments(\$method, \$args, \$msg);\n"; $code .= " }\n"; $code .= " function expectAt(\$timing, \$method, \$args = false, \$msg = '%s') {\n"; $code .= $this->_bailOutIfNotMocked("\$method"); $code .= " \$this->_mock->expectArgumentsAt(\$timing, \$method, \$args, \$msg);\n"; $code .= " }\n"; $code .= " function expectArgumentsAt(\$timing, \$method, \$args = false, \$msg = '%s') {\n"; $code .= $this->_bailOutIfNotMocked("\$method"); $code .= " \$this->_mock->expectArgumentsAt(\$timing, \$method, \$args, \$msg);\n"; $code .= " }\n"; $code .= " function expectCallCount(\$method, \$count) {\n"; $code .= $this->_bailOutIfNotMocked("\$method"); $code .= " \$this->_mock->expectCallCount(\$method, \$count, \$msg = '%s');\n"; $code .= " }\n"; $code .= " function expectMaximumCallCount(\$method, \$count, \$msg = '%s') {\n"; $code .= $this->_bailOutIfNotMocked("\$method"); $code .= " \$this->_mock->expectMaximumCallCount(\$method, \$count, \$msg = '%s');\n"; $code .= " }\n"; $code .= " function expectMinimumCallCount(\$method, \$count, \$msg = '%s') {\n"; $code .= $this->_bailOutIfNotMocked("\$method"); $code .= " \$this->_mock->expectMinimumCallCount(\$method, \$count, \$msg = '%s');\n"; $code .= " }\n"; $code .= " function expectNever(\$method) {\n"; $code .= $this->_bailOutIfNotMocked("\$method"); $code .= " \$this->_mock->expectNever(\$method);\n"; $code .= " }\n"; $code .= " function expectOnce(\$method, \$args = false, \$msg = '%s') {\n"; $code .= $this->_bailOutIfNotMocked("\$method"); $code .= " \$this->_mock->expectOnce(\$method, \$args, \$msg);\n"; $code .= " }\n"; $code .= " function expectAtLeastOnce(\$method, \$args = false, \$msg = '%s') {\n"; $code .= $this->_bailOutIfNotMocked("\$method"); $code .= " \$this->_mock->expectAtLeastOnce(\$method, \$args, \$msg);\n"; $code .= " }\n"; $code .= " function tally() {\n"; $code .= " \$this->_mock->tally();\n"; $code .= " }\n"; return $code; } /** * Creates source code to override a list of methods * with mock versions. * @param array $methods Methods to be overridden * with mock versions. * @return string Code for overridden chains. * @access private */ function _overrideMethods($methods) { $code = ""; foreach ($methods as $method) { if ($this->_isConstructor($method)) { continue; } $code .= " " . $this->_reflection->getSignature($method) . " {\n"; $code .= " \$args = func_get_args();\n"; $code .= " \$result = &\$this->_mock->_invoke(\"$method\", \$args);\n"; $code .= " return \$result;\n"; $code .= " }\n"; } return $code; } } ?> postfixadmin-2.3.7/tests/simpletest/invoker.php0000664000175000017620000000775711157271050022017 0ustar davidpalepurple_test_case = &$test_case; } /** * Accessor for test case being run. * @return SimpleTestCase Test case. * @access public */ function &getTestCase() { return $this->_test_case; } /** * Runs test level set up. Used for changing * the mechanics of base test cases. * @param string $method Test method to call. * @access public */ function before($method) { $this->_test_case->before($method); } /** * Invokes a test method and buffered with setUp() * and tearDown() calls. * @param string $method Test method to call. * @access public */ function invoke($method) { $this->_test_case->setUp(); $this->_test_case->$method(); $this->_test_case->tearDown(); } /** * Runs test level clean up. Used for changing * the mechanics of base test cases. * @param string $method Test method to call. * @access public */ function after($method) { $this->_test_case->after($method); } } /** * Do nothing decorator. Just passes the invocation * straight through. * @package SimpleTest * @subpackage UnitTester */ class SimpleInvokerDecorator { var $_invoker; /** * Stores the invoker to wrap. * @param SimpleInvoker $invoker Test method runner. */ function SimpleInvokerDecorator(&$invoker) { $this->_invoker = &$invoker; } /** * Accessor for test case being run. * @return SimpleTestCase Test case. * @access public */ function &getTestCase() { return $this->_invoker->getTestCase(); } /** * Runs test level set up. Used for changing * the mechanics of base test cases. * @param string $method Test method to call. * @access public */ function before($method) { $this->_invoker->before($method); } /** * Invokes a test method and buffered with setUp() * and tearDown() calls. * @param string $method Test method to call. * @access public */ function invoke($method) { $this->_invoker->invoke($method); } /** * Runs test level clean up. Used for changing * the mechanics of base test cases. * @param string $method Test method to call. * @access public */ function after($method) { $this->_invoker->after($method); } } ?> postfixadmin-2.3.7/tests/simpletest/detached.php0000664000175000017620000000614111157271050022065 0ustar davidpalepurple_command = $command; $this->_dry_command = $dry_command ? $dry_command : $command; $this->_size = false; } /** * Accessor for the test name for subclasses. * @return string Name of the test. * @access public */ function getLabel() { return $this->_command; } /** * Runs the top level test for this class. Currently * reads the data as a single chunk. I'll fix this * once I have added iteration to the browser. * @param SimpleReporter $reporter Target of test results. * @returns boolean True if no failures. * @access public */ function run(&$reporter) { $shell = &new SimpleShell(); $shell->execute($this->_command); $parser = &$this->_createParser($reporter); if (! $parser->parse($shell->getOutput())) { trigger_error('Cannot parse incoming XML from [' . $this->_command . ']'); return false; } return true; } /** * Accessor for the number of subtests. * @return integer Number of test cases. * @access public */ function getSize() { if ($this->_size === false) { $shell = &new SimpleShell(); $shell->execute($this->_dry_command); $reporter = &new SimpleReporter(); $parser = &$this->_createParser($reporter); if (! $parser->parse($shell->getOutput())) { trigger_error('Cannot parse incoming XML from [' . $this->_dry_command . ']'); return false; } $this->_size = $reporter->getTestCaseCount(); } return $this->_size; } /** * Creates the XML parser. * @param SimpleReporter $reporter Target of test results. * @return SimpleTestXmlListener XML reader. * @access protected */ function &_createParser(&$reporter) { return new SimpleTestXmlParser($reporter); } } ?>postfixadmin-2.3.7/tests/simpletest/encoding.php0000664000175000017620000003672211157271050022122 0ustar davidpalepurple_key = $key; $this->_value = $value; } /** * The pair as a single string. * @return string Encoded pair. * @access public */ function asRequest() { return urlencode($this->_key) . '=' . urlencode($this->_value); } /** * The MIME part as a string. * @return string MIME part encoding. * @access public */ function asMime() { $part = 'Content-Disposition: form-data; '; $part .= "name=\"" . $this->_key . "\"\r\n"; $part .= "\r\n" . $this->_value; return $part; } /** * Is this the value we are looking for? * @param string $key Identifier. * @return boolean True if matched. * @access public */ function isKey($key) { return $key == $this->_key; } /** * Is this the value we are looking for? * @return string Identifier. * @access public */ function getKey() { return $this->_key; } /** * Is this the value we are looking for? * @return string Content. * @access public */ function getValue() { return $this->_value; } } /** * Single post parameter. * @package SimpleTest * @subpackage WebTester */ class SimpleAttachment { var $_key; var $_content; var $_filename; /** * Stashes the data for rendering later. * @param string $key Key to add value to. * @param string $content Raw data. * @param hash $filename Original filename. */ function SimpleAttachment($key, $content, $filename) { $this->_key = $key; $this->_content = $content; $this->_filename = $filename; } /** * The pair as a single string. * @return string Encoded pair. * @access public */ function asRequest() { return ''; } /** * The MIME part as a string. * @return string MIME part encoding. * @access public */ function asMime() { $part = 'Content-Disposition: form-data; '; $part .= 'name="' . $this->_key . '"; '; $part .= 'filename="' . $this->_filename . '"'; $part .= "\r\nContent-Type: " . $this->_deduceMimeType(); $part .= "\r\n\r\n" . $this->_content; return $part; } /** * Attempts to figure out the MIME type from the * file extension and the content. * @return string MIME type. * @access private */ function _deduceMimeType() { if ($this->_isOnlyAscii($this->_content)) { return 'text/plain'; } return 'application/octet-stream'; } /** * Tests each character is in the range 0-127. * @param string $ascii String to test. * @access private */ function _isOnlyAscii($ascii) { for ($i = 0, $length = strlen($ascii); $i < $length; $i++) { if (ord($ascii[$i]) > 127) { return false; } } return true; } /** * Is this the value we are looking for? * @param string $key Identifier. * @return boolean True if matched. * @access public */ function isKey($key) { return $key == $this->_key; } /** * Is this the value we are looking for? * @return string Identifier. * @access public */ function getKey() { return $this->_key; } /** * Is this the value we are looking for? * @return string Content. * @access public */ function getValue() { return $this->_filename; } } /** * Bundle of GET/POST parameters. Can include * repeated parameters. * @package SimpleTest * @subpackage WebTester */ class SimpleEncoding { var $_request; /** * Starts empty. * @param array $query Hash of parameters. * Multiple values are * as lists on a single key. * @access public */ function SimpleEncoding($query = false) { if (! $query) { $query = array(); } $this->clear(); $this->merge($query); } /** * Empties the request of parameters. * @access public */ function clear() { $this->_request = array(); } /** * Adds a parameter to the query. * @param string $key Key to add value to. * @param string/array $value New data. * @access public */ function add($key, $value) { if ($value === false) { return; } if (is_array($value)) { foreach ($value as $item) { $this->_addPair($key, $item); } } else { $this->_addPair($key, $value); } } /** * Adds a new value into the request. * @param string $key Key to add value to. * @param string/array $value New data. * @access private */ function _addPair($key, $value) { $this->_request[] = new SimpleEncodedPair($key, $value); } /** * Adds a MIME part to the query. Does nothing for a * form encoded packet. * @param string $key Key to add value to. * @param string $content Raw data. * @param hash $filename Original filename. * @access public */ function attach($key, $content, $filename) { $this->_request[] = new SimpleAttachment($key, $content, $filename); } /** * Adds a set of parameters to this query. * @param array/SimpleQueryString $query Multiple values are * as lists on a single key. * @access public */ function merge($query) { if (is_object($query)) { $this->_request = array_merge($this->_request, $query->getAll()); } elseif (is_array($query)) { foreach ($query as $key => $value) { $this->add($key, $value); } } } /** * Accessor for single value. * @return string/array False if missing, string * if present and array if * multiple entries. * @access public */ function getValue($key) { $values = array(); foreach ($this->_request as $pair) { if ($pair->isKey($key)) { $values[] = $pair->getValue(); } } if (count($values) == 0) { return false; } elseif (count($values) == 1) { return $values[0]; } else { return $values; } } /** * Accessor for listing of pairs. * @return array All pair objects. * @access public */ function getAll() { return $this->_request; } /** * Renders the query string as a URL encoded * request part. * @return string Part of URL. * @access protected */ function _encode() { $statements = array(); foreach ($this->_request as $pair) { if ($statement = $pair->asRequest()) { $statements[] = $statement; } } return implode('&', $statements); } } /** * Bundle of GET parameters. Can include * repeated parameters. * @package SimpleTest * @subpackage WebTester */ class SimpleGetEncoding extends SimpleEncoding { /** * Starts empty. * @param array $query Hash of parameters. * Multiple values are * as lists on a single key. * @access public */ function SimpleGetEncoding($query = false) { $this->SimpleEncoding($query); } /** * HTTP request method. * @return string Always GET. * @access public */ function getMethod() { return 'GET'; } /** * Writes no extra headers. * @param SimpleSocket $socket Socket to write to. * @access public */ function writeHeadersTo(&$socket) { } /** * No data is sent to the socket as the data is encoded into * the URL. * @param SimpleSocket $socket Socket to write to. * @access public */ function writeTo(&$socket) { } /** * Renders the query string as a URL encoded * request part for attaching to a URL. * @return string Part of URL. * @access public */ function asUrlRequest() { return $this->_encode(); } } /** * Bundle of URL parameters for a HEAD request. * @package SimpleTest * @subpackage WebTester */ class SimpleHeadEncoding extends SimpleGetEncoding { /** * Starts empty. * @param array $query Hash of parameters. * Multiple values are * as lists on a single key. * @access public */ function SimpleHeadEncoding($query = false) { $this->SimpleGetEncoding($query); } /** * HTTP request method. * @return string Always HEAD. * @access public */ function getMethod() { return 'HEAD'; } } /** * Bundle of POST parameters. Can include * repeated parameters. * @package SimpleTest * @subpackage WebTester */ class SimplePostEncoding extends SimpleEncoding { /** * Starts empty. * @param array $query Hash of parameters. * Multiple values are * as lists on a single key. * @access public */ function SimplePostEncoding($query = false) { $this->SimpleEncoding($query); } /** * HTTP request method. * @return string Always POST. * @access public */ function getMethod() { return 'POST'; } /** * Dispatches the form headers down the socket. * @param SimpleSocket $socket Socket to write to. * @access public */ function writeHeadersTo(&$socket) { $socket->write("Content-Length: " . (integer)strlen($this->_encode()) . "\r\n"); $socket->write("Content-Type: application/x-www-form-urlencoded\r\n"); } /** * Dispatches the form data down the socket. * @param SimpleSocket $socket Socket to write to. * @access public */ function writeTo(&$socket) { $socket->write($this->_encode()); } /** * Renders the query string as a URL encoded * request part for attaching to a URL. * @return string Part of URL. * @access public */ function asUrlRequest() { return ''; } } /** * Bundle of POST parameters in the multipart * format. Can include file uploads. * @package SimpleTest * @subpackage WebTester */ class SimpleMultipartEncoding extends SimplePostEncoding { var $_boundary; /** * Starts empty. * @param array $query Hash of parameters. * Multiple values are * as lists on a single key. * @access public */ function SimpleMultipartEncoding($query = false, $boundary = false) { $this->SimplePostEncoding($query); $this->_boundary = ($boundary === false ? uniqid('st') : $boundary); } /** * Dispatches the form headers down the socket. * @param SimpleSocket $socket Socket to write to. * @access public */ function writeHeadersTo(&$socket) { $socket->write("Content-Length: " . (integer)strlen($this->_encode()) . "\r\n"); $socket->write("Content-Type: multipart/form-data, boundary=" . $this->_boundary . "\r\n"); } /** * Dispatches the form data down the socket. * @param SimpleSocket $socket Socket to write to. * @access public */ function writeTo(&$socket) { $socket->write($this->_encode()); } /** * Renders the query string as a URL encoded * request part. * @return string Part of URL. * @access public */ function _encode() { $stream = ''; foreach ($this->_request as $pair) { $stream .= "--" . $this->_boundary . "\r\n"; $stream .= $pair->asMime() . "\r\n"; } $stream .= "--" . $this->_boundary . "--\r\n"; return $stream; } } ?>postfixadmin-2.3.7/tests/simpletest/compatibility.php0000664000175000017620000001363311157271050023201 0ustar davidpalepurple= 0) { eval('$copy = clone $object;'); return $copy; } return $object; } /** * Identity test. Drops back to equality + types for PHP5 * objects as the === operator counts as the * stronger reference constraint. * @param mixed $first Test subject. * @param mixed $second Comparison object. * @return boolean True if identical. * @access public * @static */ function isIdentical($first, $second) { if ($first != $second) { return false; } if (version_compare(phpversion(), '5') >= 0) { return SimpleTestCompatibility::_isIdenticalType($first, $second); } return ($first === $second); } /** * Recursive type test. * @param mixed $first Test subject. * @param mixed $second Comparison object. * @return boolean True if same type. * @access private * @static */ function _isIdenticalType($first, $second) { if (gettype($first) != gettype($second)) { return false; } if (is_object($first) && is_object($second)) { if (get_class($first) != get_class($second)) { return false; } return SimpleTestCompatibility::_isArrayOfIdenticalTypes( get_object_vars($first), get_object_vars($second)); } if (is_array($first) && is_array($second)) { return SimpleTestCompatibility::_isArrayOfIdenticalTypes($first, $second); } if ($first !== $second) { return false; } return true; } /** * Recursive type test for each element of an array. * @param mixed $first Test subject. * @param mixed $second Comparison object. * @return boolean True if identical. * @access private * @static */ function _isArrayOfIdenticalTypes($first, $second) { if (array_keys($first) != array_keys($second)) { return false; } foreach (array_keys($first) as $key) { $is_identical = SimpleTestCompatibility::_isIdenticalType( $first[$key], $second[$key]); if (! $is_identical) { return false; } } return true; } /** * Test for two variables being aliases. * @param mixed $first Test subject. * @param mixed $second Comparison object. * @return boolean True if same. * @access public * @static */ function isReference(&$first, &$second) { if (version_compare(phpversion(), '5', '>=') && is_object($first)) { return ($first === $second); } if (is_object($first) && is_object($second)) { $id = uniqid("test"); $first->$id = true; $is_ref = isset($second->$id); unset($first->$id); return $is_ref; } $temp = $first; $first = uniqid("test"); $is_ref = ($first === $second); $first = $temp; return $is_ref; } /** * Test to see if an object is a member of a * class hiearchy. * @param object $object Object to test. * @param string $class Root name of hiearchy. * @return boolean True if class in hiearchy. * @access public * @static */ function isA($object, $class) { if (version_compare(phpversion(), '5') >= 0) { if (! class_exists($class, false)) { if (function_exists('interface_exists')) { if (! interface_exists($class, false)) { return false; } } } eval("\$is_a = \$object instanceof $class;"); return $is_a; } if (function_exists('is_a')) { return is_a($object, $class); } return ((strtolower($class) == get_class($object)) or (is_subclass_of($object, $class))); } /** * Sets a socket timeout for each chunk. * @param resource $handle Socket handle. * @param integer $timeout Limit in seconds. * @access public * @static */ function setTimeout($handle, $timeout) { if (function_exists('stream_set_timeout')) { stream_set_timeout($handle, $timeout, 0); } elseif (function_exists('socket_set_timeout')) { socket_set_timeout($handle, $timeout, 0); } elseif (function_exists('set_socket_timeout')) { set_socket_timeout($handle, $timeout, 0); } } } ?>postfixadmin-2.3.7/tests/simpletest/web_tester.php0000664000175000017620000016643211157271050022501 0ustar davidpalepurpleSimpleExpectation($message); if (is_array($value)) { sort($value); } $this->_value = $value; } /** * Tests the expectation. True if it matches * a string value or an array value in any order. * @param mixed $compare Comparison value. False for * an unset field. * @return boolean True if correct. * @access public */ function test($compare) { if ($this->_value === false) { return ($compare === false); } if ($this->_isSingle($this->_value)) { return $this->_testSingle($compare); } if (is_array($this->_value)) { return $this->_testMultiple($compare); } return false; } /** * Tests for valid field comparisons with a single option. * @param mixed $value Value to type check. * @return boolean True if integer, string or float. * @access private */ function _isSingle($value) { return is_string($value) || is_integer($value) || is_float($value); } /** * String comparison for simple field with a single option. * @param mixed $compare String to test against. * @returns boolean True if matching. * @access private */ function _testSingle($compare) { if (is_array($compare) && count($compare) == 1) { $compare = $compare[0]; } if (! $this->_isSingle($compare)) { return false; } return ($this->_value == $compare); } /** * List comparison for multivalue field. * @param mixed $compare List in any order to test against. * @returns boolean True if matching. * @access private */ function _testMultiple($compare) { if (is_string($compare)) { $compare = array($compare); } if (! is_array($compare)) { return false; } sort($compare); return ($this->_value === $compare); } /** * Returns a human readable test message. * @param mixed $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { $dumper = &$this->_getDumper(); if (is_array($compare)) { sort($compare); } if ($this->test($compare)) { return "Field expectation [" . $dumper->describeValue($this->_value) . "]"; } else { return "Field expectation [" . $dumper->describeValue($this->_value) . "] fails with [" . $dumper->describeValue($compare) . "] " . $dumper->describeDifference($this->_value, $compare); } } } /** * Test for a specific HTTP header within a header block. * @package SimpleTest * @subpackage WebTester */ class HttpHeaderExpectation extends SimpleExpectation { var $_expected_header; var $_expected_value; /** * Sets the field and value to compare against. * @param string $header Case insenstive trimmed header name. * @param mixed $value Optional value to compare. If not * given then any value will match. If * an expectation object then that will * be used instead. * @param string $message Optiona message override. Can use %s as * a placeholder for the original message. */ function HttpHeaderExpectation($header, $value = false, $message = '%s') { $this->SimpleExpectation($message); $this->_expected_header = $this->_normaliseHeader($header); $this->_expected_value = $value; } /** * Accessor for aggregated object. * @return mixed Expectation set in constructor. * @access protected */ function _getExpectation() { return $this->_expected_value; } /** * Removes whitespace at ends and case variations. * @param string $header Name of header. * @param string Trimmed and lowecased header * name. * @access private */ function _normaliseHeader($header) { return strtolower(trim($header)); } /** * Tests the expectation. True if it matches * a string value or an array value in any order. * @param mixed $compare Raw header block to search. * @return boolean True if header present. * @access public */ function test($compare) { return is_string($this->_findHeader($compare)); } /** * Searches the incoming result. Will extract the matching * line as text. * @param mixed $compare Raw header block to search. * @return string Matching header line. * @access protected */ function _findHeader($compare) { $lines = split("\r\n", $compare); foreach ($lines as $line) { if ($this->_testHeaderLine($line)) { return $line; } } return false; } /** * Compares a single header line against the expectation. * @param string $line A single line to compare. * @return boolean True if matched. * @access private */ function _testHeaderLine($line) { if (count($parsed = split(':', $line, 2)) < 2) { return false; } list($header, $value) = $parsed; if ($this->_normaliseHeader($header) != $this->_expected_header) { return false; } return $this->_testHeaderValue($value, $this->_expected_value); } /** * Tests the value part of the header. * @param string $value Value to test. * @param mixed $expected Value to test against. * @return boolean True if matched. * @access protected */ function _testHeaderValue($value, $expected) { if ($expected === false) { return true; } if (SimpleExpectation::isExpectation($expected)) { return $expected->test(trim($value)); } return (trim($value) == trim($expected)); } /** * Returns a human readable test message. * @param mixed $compare Raw header block to search. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { if (SimpleExpectation::isExpectation($this->_expected_value)) { $message = $this->_expected_value->overlayMessage($compare, $this->_getDumper()); } else { $message = $this->_expected_header . ($this->_expected_value ? ': ' . $this->_expected_value : ''); } if (is_string($line = $this->_findHeader($compare))) { return "Searching for header [$message] found [$line]"; } else { return "Failed to find header [$message]"; } } } /** * Test for a specific HTTP header within a header block that * should not be found. * @package SimpleTest * @subpackage WebTester */ class NoHttpHeaderExpectation extends HttpHeaderExpectation { var $_expected_header; var $_expected_value; /** * Sets the field and value to compare against. * @param string $unwanted Case insenstive trimmed header name. * @param string $message Optiona message override. Can use %s as * a placeholder for the original message. */ function NoHttpHeaderExpectation($unwanted, $message = '%s') { $this->HttpHeaderExpectation($unwanted, false, $message); } /** * Tests that the unwanted header is not found. * @param mixed $compare Raw header block to search. * @return boolean True if header present. * @access public */ function test($compare) { return ($this->_findHeader($compare) === false); } /** * Returns a human readable test message. * @param mixed $compare Raw header block to search. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { $expectation = $this->_getExpectation(); if (is_string($line = $this->_findHeader($compare))) { return "Found unwanted header [$expectation] with [$line]"; } else { return "Did not find unwanted header [$expectation]"; } } } /** * Test for a text substring. * @package SimpleTest * @subpackage UnitTester */ class TextExpectation extends SimpleExpectation { var $_substring; /** * Sets the value to compare against. * @param string $substring Text to search for. * @param string $message Customised message on failure. * @access public */ function TextExpectation($substring, $message = '%s') { $this->SimpleExpectation($message); $this->_substring = $substring; } /** * Accessor for the substring. * @return string Text to match. * @access protected */ function _getSubstring() { return $this->_substring; } /** * Tests the expectation. True if the text contains the * substring. * @param string $compare Comparison value. * @return boolean True if correct. * @access public */ function test($compare) { return (strpos($compare, $this->_substring) !== false); } /** * Returns a human readable test message. * @param mixed $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { if ($this->test($compare)) { return $this->_describeTextMatch($this->_getSubstring(), $compare); } else { $dumper = &$this->_getDumper(); return "Text [" . $this->_getSubstring() . "] not detected in [" . $dumper->describeValue($compare) . "]"; } } /** * Describes a pattern match including the string * found and it's position. * @param string $substring Text to search for. * @param string $subject Subject to search. * @access protected */ function _describeTextMatch($substring, $subject) { $position = strpos($subject, $substring); $dumper = &$this->_getDumper(); return "Text [$substring] detected at character [$position] in [" . $dumper->describeValue($subject) . "] in region [" . $dumper->clipString($subject, 100, $position) . "]"; } } /** * Fail if a substring is detected within the * comparison text. * @package SimpleTest * @subpackage UnitTester */ class NoTextExpectation extends TextExpectation { /** * Sets the reject pattern * @param string $substring Text to search for. * @param string $message Customised message on failure. * @access public */ function NoTextExpectation($substring, $message = '%s') { $this->TextExpectation($substring, $message); } /** * Tests the expectation. False if the substring appears * in the text. * @param string $compare Comparison value. * @return boolean True if correct. * @access public */ function test($compare) { return ! parent::test($compare); } /** * Returns a human readable test message. * @param string $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { if ($this->test($compare)) { $dumper = &$this->_getDumper(); return "Text [" . $this->_getSubstring() . "] not detected in [" . $dumper->describeValue($compare) . "]"; } else { return $this->_describeTextMatch($this->_getSubstring(), $compare); } } } /** * Test case for testing of web pages. Allows * fetching of pages, parsing of HTML and * submitting forms. * @package SimpleTest * @subpackage WebTester */ class WebTestCase extends SimpleTestCase { var $_browser; var $_ignore_errors = false; /** * Creates an empty test case. Should be subclassed * with test methods for a functional test case. * @param string $label Name of test case. Will use * the class name if none specified. * @access public */ function WebTestCase($label = false) { $this->SimpleTestCase($label); } /** * Announces the start of the test. * @param string $method Test method just started. * @access public */ function before($method) { parent::before($method); $this->setBrowser($this->createBrowser()); } /** * Announces the end of the test. Includes private clean up. * @param string $method Test method just finished. * @access public */ function after($method) { $this->unsetBrowser(); parent::after($method); } /** * Gets a current browser reference for setting * special expectations or for detailed * examination of page fetches. * @return SimpleBrowser Current test browser object. * @access public */ function &getBrowser() { return $this->_browser; } /** * Gets a current browser reference for setting * special expectations or for detailed * examination of page fetches. * @param SimpleBrowser $browser New test browser object. * @access public */ function setBrowser(&$browser) { return $this->_browser = &$browser; } /** * Clears the current browser reference to help the * PHP garbage collector. * @access public */ function unsetBrowser() { unset($this->_browser); } /** * Creates a new default web browser object. * Will be cleared at the end of the test method. * @return TestBrowser New browser. * @access public */ function &createBrowser() { $browser = &new SimpleBrowser(); return $browser; } /** * Gets the last response error. * @return string Last low level HTTP error. * @access public */ function getTransportError() { return $this->_browser->getTransportError(); } /** * Accessor for the currently selected URL. * @return string Current location or false if * no page yet fetched. * @access public */ function getUrl() { return $this->_browser->getUrl(); } /** * Dumps the current request for debugging. * @access public */ function showRequest() { $this->dump($this->_browser->getRequest()); } /** * Dumps the current HTTP headers for debugging. * @access public */ function showHeaders() { $this->dump($this->_browser->getHeaders()); } /** * Dumps the current HTML source for debugging. * @access public */ function showSource() { $this->dump($this->_browser->getContent()); } /** * Dumps the visible text only for debugging. * @access public */ function showText() { $this->dump(wordwrap($this->_browser->getContentAsText(), 80)); } /** * Simulates the closing and reopening of the browser. * Temporary cookies will be discarded and timed * cookies will be expired if later than the * specified time. * @param string/integer $date Time when session restarted. * If ommitted then all persistent * cookies are kept. Time is either * Cookie format string or timestamp. * @access public */ function restart($date = false) { if ($date === false) { $date = time(); } $this->_browser->restart($date); } /** * Moves cookie expiry times back into the past. * Useful for testing timeouts and expiries. * @param integer $interval Amount to age in seconds. * @access public */ function ageCookies($interval) { $this->_browser->ageCookies($interval); } /** * Disables frames support. Frames will not be fetched * and the frameset page will be used instead. * @access public */ function ignoreFrames() { $this->_browser->ignoreFrames(); } /** * Switches off cookie sending and recieving. * @access public */ function ignoreCookies() { $this->_browser->ignoreCookies(); } /** * Skips errors for the next request only. You might * want to confirm that a page is unreachable for * example. * @access public */ function ignoreErrors() { $this->_ignore_errors = true; } /** * Issues a fail if there is a transport error anywhere * in the current frameset. Only one such error is * reported. * @param string/boolean $result HTML or failure. * @return string/boolean $result Passes through result. * @access private */ function _failOnError($result) { if (! $this->_ignore_errors) { if ($error = $this->_browser->getTransportError()) { $this->fail($error); } } $this->_ignore_errors = false; return $result; } /** * Adds a header to every fetch. * @param string $header Header line to add to every * request until cleared. * @access public */ function addHeader($header) { $this->_browser->addHeader($header); } /** * Sets the maximum number of redirects before * the web page is loaded regardless. * @param integer $max Maximum hops. * @access public */ function setMaximumRedirects($max) { if (! $this->_browser) { trigger_error( 'Can only set maximum redirects in a test method, setUp() or tearDown()'); } $this->_browser->setMaximumRedirects($max); } /** * Sets the socket timeout for opening a connection and * receiving at least one byte of information. * @param integer $timeout Maximum time in seconds. * @access public */ function setConnectionTimeout($timeout) { $this->_browser->setConnectionTimeout($timeout); } /** * Sets proxy to use on all requests for when * testing from behind a firewall. Set URL * to false to disable. * @param string $proxy Proxy URL. * @param string $username Proxy username for authentication. * @param string $password Proxy password for authentication. * @access public */ function useProxy($proxy, $username = false, $password = false) { $this->_browser->useProxy($proxy, $username, $password); } /** * Fetches a page into the page buffer. If * there is no base for the URL then the * current base URL is used. After the fetch * the base URL reflects the new location. * @param string $url URL to fetch. * @param hash $parameters Optional additional GET data. * @return boolean/string Raw page on success. * @access public */ function get($url, $parameters = false) { return $this->_failOnError($this->_browser->get($url, $parameters)); } /** * Fetches a page by POST into the page buffer. * If there is no base for the URL then the * current base URL is used. After the fetch * the base URL reflects the new location. * @param string $url URL to fetch. * @param hash $parameters Optional additional GET data. * @return boolean/string Raw page on success. * @access public */ function post($url, $parameters = false) { return $this->_failOnError($this->_browser->post($url, $parameters)); } /** * Does a HTTP HEAD fetch, fetching only the page * headers. The current base URL is unchanged by this. * @param string $url URL to fetch. * @param hash $parameters Optional additional GET data. * @return boolean True on success. * @access public */ function head($url, $parameters = false) { return $this->_failOnError($this->_browser->head($url, $parameters)); } /** * Equivalent to hitting the retry button on the * browser. Will attempt to repeat the page fetch. * @return boolean True if fetch succeeded. * @access public */ function retry() { return $this->_failOnError($this->_browser->retry()); } /** * Equivalent to hitting the back button on the * browser. * @return boolean True if history entry and * fetch succeeded. * @access public */ function back() { return $this->_failOnError($this->_browser->back()); } /** * Equivalent to hitting the forward button on the * browser. * @return boolean True if history entry and * fetch succeeded. * @access public */ function forward() { return $this->_failOnError($this->_browser->forward()); } /** * Retries a request after setting the authentication * for the current realm. * @param string $username Username for realm. * @param string $password Password for realm. * @return boolean/string HTML on successful fetch. Note * that authentication may still have * failed. * @access public */ function authenticate($username, $password) { return $this->_failOnError( $this->_browser->authenticate($username, $password)); } /** * Gets the cookie value for the current browser context. * @param string $name Name of cookie. * @return string Value of cookie or false if unset. * @access public */ function getCookie($name) { return $this->_browser->getCurrentCookieValue($name); } /** * Sets a cookie in the current browser. * @param string $name Name of cookie. * @param string $value Cookie value. * @param string $host Host upon which the cookie is valid. * @param string $path Cookie path if not host wide. * @param string $expiry Expiry date. * @access public */ function setCookie($name, $value, $host = false, $path = '/', $expiry = false) { $this->_browser->setCookie($name, $value, $host, $path, $expiry); } /** * Accessor for current frame focus. Will be * false if no frame has focus. * @return integer/string/boolean Label if any, otherwise * the position in the frameset * or false if none. * @access public */ function getFrameFocus() { return $this->_browser->getFrameFocus(); } /** * Sets the focus by index. The integer index starts from 1. * @param integer $choice Chosen frame. * @return boolean True if frame exists. * @access public */ function setFrameFocusByIndex($choice) { return $this->_browser->setFrameFocusByIndex($choice); } /** * Sets the focus by name. * @param string $name Chosen frame. * @return boolean True if frame exists. * @access public */ function setFrameFocus($name) { return $this->_browser->setFrameFocus($name); } /** * Clears the frame focus. All frames will be searched * for content. * @access public */ function clearFrameFocus() { return $this->_browser->clearFrameFocus(); } /** * Clicks a visible text item. Will first try buttons, * then links and then images. * @param string $label Visible text or alt text. * @return string/boolean Raw page or false. * @access public */ function click($label) { return $this->_failOnError($this->_browser->click($label)); } /** * Checks for a click target. * @param string $label Visible text or alt text. * @return boolean True if click target. * @access public */ function assertClickable($label, $message = '%s') { return $this->assertTrue( $this->_browser->isClickable($label), sprintf($message, "Click target [$label] should exist")); } /** * Clicks the submit button by label. The owning * form will be submitted by this. * @param string $label Button label. An unlabeled * button can be triggered by 'Submit'. * @param hash $additional Additional form values. * @return boolean/string Page on success, else false. * @access public */ function clickSubmit($label = 'Submit', $additional = false) { return $this->_failOnError( $this->_browser->clickSubmit($label, $additional)); } /** * Clicks the submit button by name attribute. The owning * form will be submitted by this. * @param string $name Name attribute of button. * @param hash $additional Additional form values. * @return boolean/string Page on success. * @access public */ function clickSubmitByName($name, $additional = false) { return $this->_failOnError( $this->_browser->clickSubmitByName($name, $additional)); } /** * Clicks the submit button by ID attribute. The owning * form will be submitted by this. * @param string $id ID attribute of button. * @param hash $additional Additional form values. * @return boolean/string Page on success. * @access public */ function clickSubmitById($id, $additional = false) { return $this->_failOnError( $this->_browser->clickSubmitById($id, $additional)); } /** * Checks for a valid button label. * @param string $label Visible text. * @return boolean True if click target. * @access public */ function assertSubmit($label, $message = '%s') { return $this->assertTrue( $this->_browser->isSubmit($label), sprintf($message, "Submit button [$label] should exist")); } /** * Clicks the submit image by some kind of label. Usually * the alt tag or the nearest equivalent. The owning * form will be submitted by this. Clicking outside of * the boundary of the coordinates will result in * a failure. * @param string $label Alt attribute of button. * @param integer $x X-coordinate of imaginary click. * @param integer $y Y-coordinate of imaginary click. * @param hash $additional Additional form values. * @return boolean/string Page on success. * @access public */ function clickImage($label, $x = 1, $y = 1, $additional = false) { return $this->_failOnError( $this->_browser->clickImage($label, $x, $y, $additional)); } /** * Clicks the submit image by the name. Usually * the alt tag or the nearest equivalent. The owning * form will be submitted by this. Clicking outside of * the boundary of the coordinates will result in * a failure. * @param string $name Name attribute of button. * @param integer $x X-coordinate of imaginary click. * @param integer $y Y-coordinate of imaginary click. * @param hash $additional Additional form values. * @return boolean/string Page on success. * @access public */ function clickImageByName($name, $x = 1, $y = 1, $additional = false) { return $this->_failOnError( $this->_browser->clickImageByName($name, $x, $y, $additional)); } /** * Clicks the submit image by ID attribute. The owning * form will be submitted by this. Clicking outside of * the boundary of the coordinates will result in * a failure. * @param integer/string $id ID attribute of button. * @param integer $x X-coordinate of imaginary click. * @param integer $y Y-coordinate of imaginary click. * @param hash $additional Additional form values. * @return boolean/string Page on success. * @access public */ function clickImageById($id, $x = 1, $y = 1, $additional = false) { return $this->_failOnError( $this->_browser->clickImageById($id, $x, $y, $additional)); } /** * Checks for a valid image with atht alt text or title. * @param string $label Visible text. * @return boolean True if click target. * @access public */ function assertImage($label, $message = '%s') { return $this->assertTrue( $this->_browser->isImage($label), sprintf($message, "Image with text [$label] should exist")); } /** * Submits a form by the ID. * @param string $id Form ID. No button information * is submitted this way. * @return boolean/string Page on success. * @access public */ function submitFormById($id) { return $this->_failOnError($this->_browser->submitFormById($id)); } /** * Follows a link by name. Will click the first link * found with this link text by default, or a later * one if an index is given. Match is case insensitive * with normalised space. * @param string $label Text between the anchor tags. * @param integer $index Link position counting from zero. * @return boolean/string Page on success. * @access public */ function clickLink($label, $index = 0) { return $this->_failOnError($this->_browser->clickLink($label, $index)); } /** * Follows a link by id attribute. * @param string $id ID attribute value. * @return boolean/string Page on success. * @access public */ function clickLinkById($id) { return $this->_failOnError($this->_browser->clickLinkById($id)); } /** * Tests for the presence of a link label. Match is * case insensitive with normalised space. * @param string $label Text between the anchor tags. * @param mixed $expected Expected URL or expectation object. * @param string $message Message to display. Default * can be embedded with %s. * @return boolean True if link present. * @access public */ function assertLink($label, $expected = true, $message = '%s') { $url = $this->_browser->getLink($label); if ($expected === true) { return $this->assertTrue($url !== false, sprintf($message, "Link [$label] should exist")); } if (! SimpleExpectation::isExpectation($expected)) { $expected = new IdenticalExpectation($expected); } return $this->assert($expected, $url->asString(), sprintf($message, "Link [$label] should match")); } /** * Tests for the non-presence of a link label. Match is * case insensitive with normalised space. * @param string/integer $label Text between the anchor tags * or ID attribute. * @param string $message Message to display. Default * can be embedded with %s. * @return boolean True if link missing. * @access public */ function assertNoLink($label, $message = '%s') { return $this->assertTrue( $this->_browser->getLink($label) === false, sprintf($message, "Link [$label] should not exist")); } /** * Tests for the presence of a link id attribute. * @param string $id Id attribute value. * @param mixed $expected Expected URL or expectation object. * @param string $message Message to display. Default * can be embedded with %s. * @return boolean True if link present. * @access public */ function assertLinkById($id, $expected = true, $message = '%s') { $url = $this->_browser->getLinkById($id); if ($expected === true) { return $this->assertTrue($url !== false, sprintf($message, "Link ID [$id] should exist")); } if (! SimpleExpectation::isExpectation($expected)) { $expected = new IdenticalExpectation($expected); } return $this->assert($expected, $url->asString(), sprintf($message, "Link ID [$id] should match")); } /** * Tests for the non-presence of a link label. Match is * case insensitive with normalised space. * @param string $id Id attribute value. * @param string $message Message to display. Default * can be embedded with %s. * @return boolean True if link missing. * @access public */ function assertNoLinkById($id, $message = '%s') { return $this->assertTrue( $this->_browser->getLinkById($id) === false, sprintf($message, "Link ID [$id] should not exist")); } /** * Sets all form fields with that label, or name if there * is no label attached. * @param string $name Name of field in forms. * @param string $value New value of field. * @return boolean True if field exists, otherwise false. * @access public */ function setField($label, $value) { return $this->_browser->setField($label, $value); } /** * Sets all form fields with that name. * @param string $name Name of field in forms. * @param string $value New value of field. * @return boolean True if field exists, otherwise false. * @access public */ function setFieldByName($name, $value) { return $this->_browser->setFieldByName($name, $value); } /** * Sets all form fields with that name. * @param string/integer $id Id of field in forms. * @param string $value New value of field. * @return boolean True if field exists, otherwise false. * @access public */ function setFieldById($id, $value) { return $this->_browser->setFieldById($id, $value); } /** * Confirms that the form element is currently set * to the expected value. A missing form will always * fail. If no value is given then only the existence * of the field is checked. * @param string $name Name of field in forms. * @param mixed $expected Expected string/array value or * false for unset fields. * @param string $message Message to display. Default * can be embedded with %s. * @return boolean True if pass. * @access public */ function assertField($label, $expected = true, $message = '%s') { $value = $this->_browser->getField($label); return $this->_assertFieldValue($label, $value, $expected, $message); } /** * Confirms that the form element is currently set * to the expected value. A missing form element will always * fail. If no value is given then only the existence * of the field is checked. * @param string $name Name of field in forms. * @param mixed $expected Expected string/array value or * false for unset fields. * @param string $message Message to display. Default * can be embedded with %s. * @return boolean True if pass. * @access public */ function assertFieldByName($name, $expected = true, $message = '%s') { $value = $this->_browser->getFieldByName($name); return $this->_assertFieldValue($name, $value, $expected, $message); } /** * Confirms that the form element is currently set * to the expected value. A missing form will always * fail. If no ID is given then only the existence * of the field is checked. * @param string/integer $id Name of field in forms. * @param mixed $expected Expected string/array value or * false for unset fields. * @param string $message Message to display. Default * can be embedded with %s. * @return boolean True if pass. * @access public */ function assertFieldById($id, $expected = true, $message = '%s') { $value = $this->_browser->getFieldById($id); return $this->_assertFieldValue($id, $value, $expected, $message); } /** * Tests the field value against the expectation. * @param string $identifier Name, ID or label. * @param mixed $value Current field value. * @param mixed $expected Expected value to match. * @param string $message Failure message. * @return boolean True if pass * @access protected */ function _assertFieldValue($identifier, $value, $expected, $message) { if ($expected === true) { return $this->assertTrue( isset($value), sprintf($message, "Field [$identifier] should exist")); } if (! SimpleExpectation::isExpectation($expected)) { $identifier = str_replace('%', '%%', $identifier); $expected = new FieldExpectation( $expected, "Field [$identifier] should match with [%s]"); } return $this->assert($expected, $value, $message); } /** * Checks the response code against a list * of possible values. * @param array $responses Possible responses for a pass. * @param string $message Message to display. Default * can be embedded with %s. * @return boolean True if pass. * @access public */ function assertResponse($responses, $message = '%s') { $responses = (is_array($responses) ? $responses : array($responses)); $code = $this->_browser->getResponseCode(); $message = sprintf($message, "Expecting response in [" . implode(", ", $responses) . "] got [$code]"); return $this->assertTrue(in_array($code, $responses), $message); } /** * Checks the mime type against a list * of possible values. * @param array $types Possible mime types for a pass. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertMime($types, $message = '%s') { $types = (is_array($types) ? $types : array($types)); $type = $this->_browser->getMimeType(); $message = sprintf($message, "Expecting mime type in [" . implode(", ", $types) . "] got [$type]"); return $this->assertTrue(in_array($type, $types), $message); } /** * Attempt to match the authentication type within * the security realm we are currently matching. * @param string $authentication Usually basic. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertAuthentication($authentication = false, $message = '%s') { if (! $authentication) { $message = sprintf($message, "Expected any authentication type, got [" . $this->_browser->getAuthentication() . "]"); return $this->assertTrue( $this->_browser->getAuthentication(), $message); } else { $message = sprintf($message, "Expected authentication [$authentication] got [" . $this->_browser->getAuthentication() . "]"); return $this->assertTrue( strtolower($this->_browser->getAuthentication()) == strtolower($authentication), $message); } } /** * Checks that no authentication is necessary to view * the desired page. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertNoAuthentication($message = '%s') { $message = sprintf($message, "Expected no authentication type, got [" . $this->_browser->getAuthentication() . "]"); return $this->assertFalse($this->_browser->getAuthentication(), $message); } /** * Attempts to match the current security realm. * @param string $realm Name of security realm. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertRealm($realm, $message = '%s') { if (! SimpleExpectation::isExpectation($realm)) { $realm = new EqualExpectation($realm); } return $this->assert( $realm, $this->_browser->getRealm(), "Expected realm -> $message"); } /** * Checks each header line for the required value. If no * value is given then only an existence check is made. * @param string $header Case insensitive header name. * @param mixed $value Case sensitive trimmed string to * match against. An expectation object * can be used for pattern matching. * @return boolean True if pass. * @access public */ function assertHeader($header, $value = false, $message = '%s') { return $this->assert( new HttpHeaderExpectation($header, $value), $this->_browser->getHeaders(), $message); } /** * @deprecated */ function assertHeaderPattern($header, $pattern, $message = '%s') { return $this->assert( new HttpHeaderExpectation($header, new PatternExpectation($pattern)), $this->_browser->getHeaders(), $message); } /** * Confirms that the header type has not been received. * Only the landing page is checked. If you want to check * redirect pages, then you should limit redirects so * as to capture the page you want. * @param string $header Case insensitive header name. * @return boolean True if pass. * @access public */ function assertNoHeader($header, $message = '%s') { return $this->assert( new NoHttpHeaderExpectation($header), $this->_browser->getHeaders(), $message); } /** * @deprecated */ function assertNoUnwantedHeader($header, $message = '%s') { return $this->assertNoHeader($header, $message); } /** * Tests the text between the title tags. * @param string/SimpleExpectation $title Expected title. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertTitle($title = false, $message = '%s') { if (! SimpleExpectation::isExpectation($title)) { $title = new EqualExpectation($title); } return $this->assert($title, $this->_browser->getTitle(), $message); } /** * Will trigger a pass if the text is found in the plain * text form of the page. * @param string $text Text to look for. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertText($text, $message = '%s') { return $this->assert( new TextExpectation($text), $this->_browser->getContentAsText(), $message); } /** * @deprecated */ function assertWantedText($text, $message = '%s') { return $this->assertText($text, $message); } /** * Will trigger a pass if the text is not found in the plain * text form of the page. * @param string $text Text to look for. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertNoText($text, $message = '%s') { return $this->assert( new NoTextExpectation($text), $this->_browser->getContentAsText(), $message); } /** * @deprecated */ function assertNoUnwantedText($text, $message = '%s') { return $this->assertNoText($text, $message); } /** * Will trigger a pass if the Perl regex pattern * is found in the raw content. * @param string $pattern Perl regex to look for including * the regex delimiters. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertPattern($pattern, $message = '%s') { return $this->assert( new PatternExpectation($pattern), $this->_browser->getContent(), $message); } /** * @deprecated */ function assertWantedPattern($pattern, $message = '%s') { return $this->assertPattern($pattern, $message); } /** * Will trigger a pass if the perl regex pattern * is not present in raw content. * @param string $pattern Perl regex to look for including * the regex delimiters. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertNoPattern($pattern, $message = '%s') { return $this->assert( new NoPatternExpectation($pattern), $this->_browser->getContent(), $message); } /** * @deprecated */ function assertNoUnwantedPattern($pattern, $message = '%s') { return $this->assertNoPattern($pattern, $message); } /** * Checks that a cookie is set for the current page * and optionally checks the value. * @param string $name Name of cookie to test. * @param string $expected Expected value as a string or * false if any value will do. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertCookie($name, $expected = false, $message = '%s') { $value = $this->getCookie($name); if (! $expected) { return $this->assertTrue( $value, sprintf($message, "Expecting cookie [$name]")); } if (! SimpleExpectation::isExpectation($expected)) { $expected = new EqualExpectation($expected); } return $this->assert($expected, $value, "Expecting cookie [$name] -> $message"); } /** * Checks that no cookie is present or that it has * been successfully cleared. * @param string $name Name of cookie to test. * @param string $message Message to display. * @return boolean True if pass. * @access public */ function assertNoCookie($name, $message = '%s') { return $this->assertTrue( $this->getCookie($name) === false, sprintf($message, "Not expecting cookie [$name]")); } /** * Called from within the test methods to register * passes and failures. * @param boolean $result Pass on true. * @param string $message Message to display describing * the test state. * @return boolean True on pass * @access public */ function assertTrue($result, $message = false) { return $this->assert(new TrueExpectation(), $result, $message); } /** * Will be true on false and vice versa. False * is the PHP definition of false, so that null, * empty strings, zero and an empty array all count * as false. * @param boolean $result Pass on false. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertFalse($result, $message = '%s') { return $this->assert(new FalseExpectation(), $result, $message); } /** * Will trigger a pass if the two parameters have * the same value only. Otherwise a fail. This * is for testing hand extracted text, etc. * @param mixed $first Value to compare. * @param mixed $second Value to compare. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertEqual($first, $second, $message = '%s') { return $this->assert( new EqualExpectation($first), $second, $message); } /** * Will trigger a pass if the two parameters have * a different value. Otherwise a fail. This * is for testing hand extracted text, etc. * @param mixed $first Value to compare. * @param mixed $second Value to compare. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertNotEqual($first, $second, $message = '%s') { return $this->assert( new NotEqualExpectation($first), $second, $message); } /** * Uses a stack trace to find the line of an assertion. * @return string Line number of first assert* * method embedded in format string. * @access public */ function getAssertionLine() { $trace = new SimpleStackTrace(array('assert', 'click', 'pass', 'fail')); return $trace->traceMethod(); } } ?>postfixadmin-2.3.7/tests/simpletest/README0000664000175000017620000001072411157271050020475 0ustar davidpalepurpleSimpleTest ========== You probably got this package from... http://simpletest.sourceforge.net/projects/simpletest/ If there is no licence agreement with this package please download a version from the location above. You must read and accept that licence to use this software. The file is titled simply LICENSE. What is it? It's a framework for unit testing, web site testing and mock objects for PHP 4.2.0+. If you have used JUnit you will find this PHP unit testing version very similar. Also included is a mock objects and server stubs generator. The stubs can have return values set for different arguments, can have sequences set also by arguments and can return items by reference. The mocks inherit all of this functionality and can also have expectations set, again in sequences and for different arguments. A web tester similar in concept to JWebUnit is also included. There is no JavaScript or tables support, but forms, authentication, cookies and frames are handled. You can see a release schedule at http://www.lastcraft.com/overview.php which is also copied to the documentation folder with this release. A full PHPDocumenter API documentation exists at http://simpletest.sourceforge.net/. The user interface is minimal in the extreme, but a lot of information flows from the test suite. After version 1.0 we will release a better web UI, but we are leaving XUL and GTk versions to volunteers as everybody has their own opinion on a good GUI, and we don't want to discourage development by shipping one with the toolkit. You are looking at a first full release. The unit tests for SimpleTest itself can be run here... simpletest/test/unit_tests.php And tests involving live network connections as well are here... simpletest/test/all_tests.php The full tests will typically overrun the 8Mb limit usually allowed to a PHP process. A workaround is to run the tests on the command with a custom php.ini file if you do not have access to your server version. You will have to edit the all_tests.php file if you are accesssing the internet through a proxy server. See the comments in all_tests.php for instructions. The full tests read some test data from the LastCraft site. If the site is down or has been modified for a later version then you will get spurious errors. A unit_tests.php failure on the other hand would be very serious. As far as we know we haven't yet managed to check in any unit test failures so please correct us if you find one. Even if all of the tests run please verify that your existing test suites also function as expected. If they don't see the file... HELP_MY_TESTS_DONT_WORK_ANYMORE This contains information on interface changes. It also points out deprecated interfaces so you should read this even if all of your current tests appear to run. There is a documentation folder which contains the core reference information in English and French, although this information is fairly basic. You can find a tutorial on... http://www.lastcraft.com/first_test_tutorial.php ...to get you started and this material will eventually become included with the project documentation. A French translation exists at... http://www.onpk.net/index.php/2005/01/12/254-tutoriel-simpletest-decouvrir-les-tests-unitaires. If you download and use and possibly even extend this tool, please let us know. Any feedback, even bad, is always welcome and we will work to get your suggestions into the next release. Ideally please send your comments to... simpletest-support@lists.sourceforge.net ...so that others can read them too. We usually try to respond within 48 hours. There is no change log as yet except at Sourceforge. You can visit the release notes to see the completed TODO list after each cycle and also the status of any bugs, but if the bug is recent then it will be fixed in CVS only. The CVS check-ins always have all the tests passing and so CVS snapshots should be pretty usable, although the code may not look so good internally. Oh, yes. It is called "Simple" because it should be simple to use. We intend to add a complete set of tools for a test first and "test as you code" type of development. "Simple" does not mean "Lite" in this context. Thanks to everyone who has sent comments and offered suggestions. They really are invaluable, but sadly you are too many to mention in full. Thanks to all on the advanced PHP forum on SitePoint, especially Harry Feucks. Early adopters are always an inspiration. yours Marcus Baker, Jason Sweat, Travis Swicegood and Perrick Penet. -- marcus@lastcraft.com postfixadmin-2.3.7/tests/simpletest/parser.php0000664000175000017620000007027411157271050021630 0ustar davidpalepurple_case = $case; $this->_patterns = array(); $this->_labels = array(); $this->_regex = null; } /** * Adds a pattern with an optional label. * @param string $pattern Perl style regex, but ( and ) * lose the usual meaning. * @param string $label Label of regex to be returned * on a match. * @access public */ function addPattern($pattern, $label = true) { $count = count($this->_patterns); $this->_patterns[$count] = $pattern; $this->_labels[$count] = $label; $this->_regex = null; } /** * Attempts to match all patterns at once against * a string. * @param string $subject String to match against. * @param string $match First matched portion of * subject. * @return boolean True on success. * @access public */ function match($subject, &$match) { if (count($this->_patterns) == 0) { return false; } if (! preg_match($this->_getCompoundedRegex(), $subject, $matches)) { $match = ''; return false; } $match = $matches[0]; for ($i = 1; $i < count($matches); $i++) { if ($matches[$i]) { return $this->_labels[$i - 1]; } } return true; } /** * Compounds the patterns into a single * regular expression separated with the * "or" operator. Caches the regex. * Will automatically escape (, ) and / tokens. * @param array $patterns List of patterns in order. * @access private */ function _getCompoundedRegex() { if ($this->_regex == null) { for ($i = 0, $count = count($this->_patterns); $i < $count; $i++) { $this->_patterns[$i] = '(' . str_replace( array('/', '(', ')'), array('\/', '\(', '\)'), $this->_patterns[$i]) . ')'; } $this->_regex = "/" . implode("|", $this->_patterns) . "/" . $this->_getPerlMatchingFlags(); } return $this->_regex; } /** * Accessor for perl regex mode flags to use. * @return string Perl regex flags. * @access private */ function _getPerlMatchingFlags() { return ($this->_case ? "msS" : "msSi"); } } /** * States for a stack machine. * @package SimpleTest * @subpackage WebTester */ class SimpleStateStack { var $_stack; /** * Constructor. Starts in named state. * @param string $start Starting state name. * @access public */ function SimpleStateStack($start) { $this->_stack = array($start); } /** * Accessor for current state. * @return string State. * @access public */ function getCurrent() { return $this->_stack[count($this->_stack) - 1]; } /** * Adds a state to the stack and sets it * to be the current state. * @param string $state New state. * @access public */ function enter($state) { array_push($this->_stack, $state); } /** * Leaves the current state and reverts * to the previous one. * @return boolean False if we drop off * the bottom of the list. * @access public */ function leave() { if (count($this->_stack) == 1) { return false; } array_pop($this->_stack); return true; } } /** * Accepts text and breaks it into tokens. * Some optimisation to make the sure the * content is only scanned by the PHP regex * parser once. Lexer modes must not start * with leading underscores. * @package SimpleTest * @subpackage WebTester */ class SimpleLexer { var $_regexes; var $_parser; var $_mode; var $_mode_handlers; var $_case; /** * Sets up the lexer in case insensitive matching * by default. * @param SimpleSaxParser $parser Handling strategy by * reference. * @param string $start Starting handler. * @param boolean $case True for case sensitive. * @access public */ function SimpleLexer(&$parser, $start = "accept", $case = false) { $this->_case = $case; $this->_regexes = array(); $this->_parser = &$parser; $this->_mode = &new SimpleStateStack($start); $this->_mode_handlers = array($start => $start); } /** * Adds a token search pattern for a particular * parsing mode. The pattern does not change the * current mode. * @param string $pattern Perl style regex, but ( and ) * lose the usual meaning. * @param string $mode Should only apply this * pattern when dealing with * this type of input. * @access public */ function addPattern($pattern, $mode = "accept") { if (! isset($this->_regexes[$mode])) { $this->_regexes[$mode] = new ParallelRegex($this->_case); } $this->_regexes[$mode]->addPattern($pattern); if (! isset($this->_mode_handlers[$mode])) { $this->_mode_handlers[$mode] = $mode; } } /** * Adds a pattern that will enter a new parsing * mode. Useful for entering parenthesis, strings, * tags, etc. * @param string $pattern Perl style regex, but ( and ) * lose the usual meaning. * @param string $mode Should only apply this * pattern when dealing with * this type of input. * @param string $new_mode Change parsing to this new * nested mode. * @access public */ function addEntryPattern($pattern, $mode, $new_mode) { if (! isset($this->_regexes[$mode])) { $this->_regexes[$mode] = new ParallelRegex($this->_case); } $this->_regexes[$mode]->addPattern($pattern, $new_mode); if (! isset($this->_mode_handlers[$new_mode])) { $this->_mode_handlers[$new_mode] = $new_mode; } } /** * Adds a pattern that will exit the current mode * and re-enter the previous one. * @param string $pattern Perl style regex, but ( and ) * lose the usual meaning. * @param string $mode Mode to leave. * @access public */ function addExitPattern($pattern, $mode) { if (! isset($this->_regexes[$mode])) { $this->_regexes[$mode] = new ParallelRegex($this->_case); } $this->_regexes[$mode]->addPattern($pattern, "__exit"); if (! isset($this->_mode_handlers[$mode])) { $this->_mode_handlers[$mode] = $mode; } } /** * Adds a pattern that has a special mode. Acts as an entry * and exit pattern in one go, effectively calling a special * parser handler for this token only. * @param string $pattern Perl style regex, but ( and ) * lose the usual meaning. * @param string $mode Should only apply this * pattern when dealing with * this type of input. * @param string $special Use this mode for this one token. * @access public */ function addSpecialPattern($pattern, $mode, $special) { if (! isset($this->_regexes[$mode])) { $this->_regexes[$mode] = new ParallelRegex($this->_case); } $this->_regexes[$mode]->addPattern($pattern, "_$special"); if (! isset($this->_mode_handlers[$special])) { $this->_mode_handlers[$special] = $special; } } /** * Adds a mapping from a mode to another handler. * @param string $mode Mode to be remapped. * @param string $handler New target handler. * @access public */ function mapHandler($mode, $handler) { $this->_mode_handlers[$mode] = $handler; } /** * Splits the page text into tokens. Will fail * if the handlers report an error or if no * content is consumed. If successful then each * unparsed and parsed token invokes a call to the * held listener. * @param string $raw Raw HTML text. * @return boolean True on success, else false. * @access public */ function parse($raw) { if (! isset($this->_parser)) { return false; } $length = strlen($raw); while (is_array($parsed = $this->_reduce($raw))) { list($raw, $unmatched, $matched, $mode) = $parsed; if (! $this->_dispatchTokens($unmatched, $matched, $mode)) { return false; } if ($raw === '') { return true; } if (strlen($raw) == $length) { return false; } $length = strlen($raw); } if (! $parsed) { return false; } return $this->_invokeParser($raw, LEXER_UNMATCHED); } /** * Sends the matched token and any leading unmatched * text to the parser changing the lexer to a new * mode if one is listed. * @param string $unmatched Unmatched leading portion. * @param string $matched Actual token match. * @param string $mode Mode after match. A boolean * false mode causes no change. * @return boolean False if there was any error * from the parser. * @access private */ function _dispatchTokens($unmatched, $matched, $mode = false) { if (! $this->_invokeParser($unmatched, LEXER_UNMATCHED)) { return false; } if (is_bool($mode)) { return $this->_invokeParser($matched, LEXER_MATCHED); } if ($this->_isModeEnd($mode)) { if (! $this->_invokeParser($matched, LEXER_EXIT)) { return false; } return $this->_mode->leave(); } if ($this->_isSpecialMode($mode)) { $this->_mode->enter($this->_decodeSpecial($mode)); if (! $this->_invokeParser($matched, LEXER_SPECIAL)) { return false; } return $this->_mode->leave(); } $this->_mode->enter($mode); return $this->_invokeParser($matched, LEXER_ENTER); } /** * Tests to see if the new mode is actually to leave * the current mode and pop an item from the matching * mode stack. * @param string $mode Mode to test. * @return boolean True if this is the exit mode. * @access private */ function _isModeEnd($mode) { return ($mode === "__exit"); } /** * Test to see if the mode is one where this mode * is entered for this token only and automatically * leaves immediately afterwoods. * @param string $mode Mode to test. * @return boolean True if this is the exit mode. * @access private */ function _isSpecialMode($mode) { return (strncmp($mode, "_", 1) == 0); } /** * Strips the magic underscore marking single token * modes. * @param string $mode Mode to decode. * @return string Underlying mode name. * @access private */ function _decodeSpecial($mode) { return substr($mode, 1); } /** * Calls the parser method named after the current * mode. Empty content will be ignored. The lexer * has a parser handler for each mode in the lexer. * @param string $content Text parsed. * @param boolean $is_match Token is recognised rather * than unparsed data. * @access private */ function _invokeParser($content, $is_match) { if (($content === '') || ($content === false)) { return true; } $handler = $this->_mode_handlers[$this->_mode->getCurrent()]; return $this->_parser->$handler($content, $is_match); } /** * Tries to match a chunk of text and if successful * removes the recognised chunk and any leading * unparsed data. Empty strings will not be matched. * @param string $raw The subject to parse. This is the * content that will be eaten. * @return array/boolean Three item list of unparsed * content followed by the * recognised token and finally the * action the parser is to take. * True if no match, false if there * is a parsing error. * @access private */ function _reduce($raw) { if ($action = $this->_regexes[$this->_mode->getCurrent()]->match($raw, $match)) { $unparsed_character_count = strpos($raw, $match); $unparsed = substr($raw, 0, $unparsed_character_count); $raw = substr($raw, $unparsed_character_count + strlen($match)); return array($raw, $unparsed, $match, $action); } return true; } } /** * Breas HTML into SAX events. * @package SimpleTest * @subpackage WebTester */ class SimpleHtmlLexer extends SimpleLexer { /** * Sets up the lexer with case insensitive matching * and adds the HTML handlers. * @param SimpleSaxParser $parser Handling strategy by * reference. * @access public */ function SimpleHtmlLexer(&$parser) { $this->SimpleLexer($parser, 'text'); $this->mapHandler('text', 'acceptTextToken'); $this->_addSkipping(); foreach ($this->_getParsedTags() as $tag) { $this->_addTag($tag); } $this->_addInTagTokens(); } /** * List of parsed tags. Others are ignored. * @return array List of searched for tags. * @access private */ function _getParsedTags() { return array('a', 'title', 'form', 'input', 'button', 'textarea', 'select', 'option', 'frameset', 'frame', 'label'); } /** * The lexer has to skip certain sections such * as server code, client code and styles. * @access private */ function _addSkipping() { $this->mapHandler('css', 'ignore'); $this->addEntryPattern('addExitPattern('', 'css'); $this->mapHandler('js', 'ignore'); $this->addEntryPattern('addExitPattern('', 'js'); $this->mapHandler('comment', 'ignore'); $this->addEntryPattern('', 'comment'); } /** * Pattern matches to start and end a tag. * @param string $tag Name of tag to scan for. * @access private */ function _addTag($tag) { $this->addSpecialPattern("", 'text', 'acceptEndToken'); $this->addEntryPattern("<$tag", 'text', 'tag'); } /** * Pattern matches to parse the inside of a tag * including the attributes and their quoting. * @access private */ function _addInTagTokens() { $this->mapHandler('tag', 'acceptStartToken'); $this->addSpecialPattern('\s+', 'tag', 'ignore'); $this->_addAttributeTokens(); $this->addExitPattern('/>', 'tag'); $this->addExitPattern('>', 'tag'); } /** * Matches attributes that are either single quoted, * double quoted or unquoted. * @access private */ function _addAttributeTokens() { $this->mapHandler('dq_attribute', 'acceptAttributeToken'); $this->addEntryPattern('=\s*"', 'tag', 'dq_attribute'); $this->addPattern("\\\\\"", 'dq_attribute'); $this->addExitPattern('"', 'dq_attribute'); $this->mapHandler('sq_attribute', 'acceptAttributeToken'); $this->addEntryPattern("=\s*'", 'tag', 'sq_attribute'); $this->addPattern("\\\\'", 'sq_attribute'); $this->addExitPattern("'", 'sq_attribute'); $this->mapHandler('uq_attribute', 'acceptAttributeToken'); $this->addSpecialPattern('=\s*[^>\s]*', 'tag', 'uq_attribute'); } } /** * Converts HTML tokens into selected SAX events. * @package SimpleTest * @subpackage WebTester */ class SimpleHtmlSaxParser { var $_lexer; var $_listener; var $_tag; var $_attributes; var $_current_attribute; /** * Sets the listener. * @param SimpleSaxListener $listener SAX event handler. * @access public */ function SimpleHtmlSaxParser(&$listener) { $this->_listener = &$listener; $this->_lexer = &$this->createLexer($this); $this->_tag = ''; $this->_attributes = array(); $this->_current_attribute = ''; } /** * Runs the content through the lexer which * should call back to the acceptors. * @param string $raw Page text to parse. * @return boolean False if parse error. * @access public */ function parse($raw) { return $this->_lexer->parse($raw); } /** * Sets up the matching lexer. Starts in 'text' mode. * @param SimpleSaxParser $parser Event generator, usually $self. * @return SimpleLexer Lexer suitable for this parser. * @access public * @static */ function &createLexer(&$parser) { $lexer = &new SimpleHtmlLexer($parser); return $lexer; } /** * Accepts a token from the tag mode. If the * starting element completes then the element * is dispatched and the current attributes * set back to empty. The element or attribute * name is converted to lower case. * @param string $token Incoming characters. * @param integer $event Lexer event type. * @return boolean False if parse error. * @access public */ function acceptStartToken($token, $event) { if ($event == LEXER_ENTER) { $this->_tag = strtolower(substr($token, 1)); return true; } if ($event == LEXER_EXIT) { $success = $this->_listener->startElement( $this->_tag, $this->_attributes); $this->_tag = ''; $this->_attributes = array(); return $success; } if ($token != '=') { $this->_current_attribute = strtolower(SimpleHtmlSaxParser::decodeHtml($token)); $this->_attributes[$this->_current_attribute] = ''; } return true; } /** * Accepts a token from the end tag mode. * The element name is converted to lower case. * @param string $token Incoming characters. * @param integer $event Lexer event type. * @return boolean False if parse error. * @access public */ function acceptEndToken($token, $event) { if (! preg_match('/<\/(.*)>/', $token, $matches)) { return false; } return $this->_listener->endElement(strtolower($matches[1])); } /** * Part of the tag data. * @param string $token Incoming characters. * @param integer $event Lexer event type. * @return boolean False if parse error. * @access public */ function acceptAttributeToken($token, $event) { if ($this->_current_attribute) { if ($event == LEXER_UNMATCHED) { $this->_attributes[$this->_current_attribute] .= SimpleHtmlSaxParser::decodeHtml($token); } if ($event == LEXER_SPECIAL) { $this->_attributes[$this->_current_attribute] .= preg_replace('/^=\s*/' , '', SimpleHtmlSaxParser::decodeHtml($token)); } } return true; } /** * A character entity. * @param string $token Incoming characters. * @param integer $event Lexer event type. * @return boolean False if parse error. * @access public */ function acceptEntityToken($token, $event) { } /** * Character data between tags regarded as * important. * @param string $token Incoming characters. * @param integer $event Lexer event type. * @return boolean False if parse error. * @access public */ function acceptTextToken($token, $event) { return $this->_listener->addContent($token); } /** * Incoming data to be ignored. * @param string $token Incoming characters. * @param integer $event Lexer event type. * @return boolean False if parse error. * @access public */ function ignore($token, $event) { return true; } /** * Decodes any HTML entities. * @param string $html Incoming HTML. * @return string Outgoing plain text. * @access public * @static */ function decodeHtml($html) { static $translations; if (! isset($translations)) { $translations = array_flip(get_html_translation_table(HTML_ENTITIES)); } return strtr($html, $translations); } /** * Turns HTML into text browser visible text. Images * are converted to their alt text and tags are supressed. * Entities are converted to their visible representation. * @param string $html HTML to convert. * @return string Plain text. * @access public * @static */ function normalise($html) { $text = preg_replace('||', '', $html); $text = preg_replace('||', ' \1 ', $text); $text = preg_replace('||', ' \1 ', $text); $text = preg_replace('||', ' \1 ', $text); $text = preg_replace('|<.*?>|', '', $text); $text = SimpleHtmlSaxParser::decodeHtml($text); $text = preg_replace('|\s+|', ' ', $text); return trim($text); } } /** * SAX event handler. * @package SimpleTest * @subpackage WebTester * @abstract */ class SimpleSaxListener { /** * Sets the document to write to. * @access public */ function SimpleSaxListener() { } /** * Start of element event. * @param string $name Element name. * @param hash $attributes Name value pairs. * Attributes without content * are marked as true. * @return boolean False on parse error. * @access public */ function startElement($name, $attributes) { } /** * End of element event. * @param string $name Element name. * @return boolean False on parse error. * @access public */ function endElement($name) { } /** * Unparsed, but relevant data. * @param string $text May include unparsed tags. * @return boolean False on parse error. * @access public */ function addContent($text) { } } ?>postfixadmin-2.3.7/tests/simpletest/unit_tester.php0000664000175000017620000004001011157271050022662 0ustar davidpalepurpleSimpleTestCase($label); } /** * Called from within the test methods to register * passes and failures. * @param boolean $result Pass on true. * @param string $message Message to display describing * the test state. * @return boolean True on pass * @access public */ function assertTrue($result, $message = false) { return $this->assert(new TrueExpectation(), $result, $message); } /** * Will be true on false and vice versa. False * is the PHP definition of false, so that null, * empty strings, zero and an empty array all count * as false. * @param boolean $result Pass on false. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertFalse($result, $message = '%s') { return $this->assert(new FalseExpectation(), $result, $message); } /** * Will be true if the value is null. * @param null $value Supposedly null value. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertNull($value, $message = '%s') { $dumper = &new SimpleDumper(); $message = sprintf( $message, '[' . $dumper->describeValue($value) . '] should be null'); return $this->assertTrue(! isset($value), $message); } /** * Will be true if the value is set. * @param mixed $value Supposedly set value. * @param string $message Message to display. * @return boolean True on pass. * @access public */ function assertNotNull($value, $message = '%s') { $dumper = &new SimpleDumper(); $message = sprintf( $message, '[' . $dumper->describeValue($value) . '] should not be null'); return $this->assertTrue(isset($value), $message); } /** * Type and class test. Will pass if class * matches the type name or is a subclass or * if not an object, but the type is correct. * @param mixed $object Object to test. * @param string $type Type name as string. * @param string $message Message to display. * @return boolean True on pass. * @access public */ function assertIsA($object, $type, $message = '%s') { return $this->assert( new IsAExpectation($type), $object, $message); } /** * Type and class mismatch test. Will pass if class * name or underling type does not match the one * specified. * @param mixed $object Object to test. * @param string $type Type name as string. * @param string $message Message to display. * @return boolean True on pass. * @access public */ function assertNotA($object, $type, $message = '%s') { return $this->assert( new NotAExpectation($type), $object, $message); } /** * Will trigger a pass if the two parameters have * the same value only. Otherwise a fail. * @param mixed $first Value to compare. * @param mixed $second Value to compare. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertEqual($first, $second, $message = '%s') { return $this->assert( new EqualExpectation($first), $second, $message); } /** * Will trigger a pass if the two parameters have * a different value. Otherwise a fail. * @param mixed $first Value to compare. * @param mixed $second Value to compare. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertNotEqual($first, $second, $message = '%s') { return $this->assert( new NotEqualExpectation($first), $second, $message); } /** * Will trigger a pass if the if the first parameter * is near enough to the second by the margin. * @param mixed $first Value to compare. * @param mixed $second Value to compare. * @param mixed $margin Fuzziness of match. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertWithinMargin($first, $second, $margin, $message = '%s') { return $this->assert( new WithinMarginExpectation($first, $margin), $second, $message); } /** * Will trigger a pass if the two parameters differ * by more than the margin. * @param mixed $first Value to compare. * @param mixed $second Value to compare. * @param mixed $margin Fuzziness of match. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertOutsideMargin($first, $second, $margin, $message = '%s') { return $this->assert( new OutsideMarginExpectation($first, $margin), $second, $message); } /** * Will trigger a pass if the two parameters have * the same value and same type. Otherwise a fail. * @param mixed $first Value to compare. * @param mixed $second Value to compare. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertIdentical($first, $second, $message = '%s') { return $this->assert( new IdenticalExpectation($first), $second, $message); } /** * Will trigger a pass if the two parameters have * the different value or different type. * @param mixed $first Value to compare. * @param mixed $second Value to compare. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertNotIdentical($first, $second, $message = '%s') { return $this->assert( new NotIdenticalExpectation($first), $second, $message); } /** * Will trigger a pass if both parameters refer * to the same object. Fail otherwise. * @param mixed $first Object reference to check. * @param mixed $second Hopefully the same object. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertReference(&$first, &$second, $message = '%s') { $dumper = &new SimpleDumper(); $message = sprintf( $message, '[' . $dumper->describeValue($first) . '] and [' . $dumper->describeValue($second) . '] should reference the same object'); return $this->assertTrue( SimpleTestCompatibility::isReference($first, $second), $message); } /** * Will trigger a pass if both parameters refer * to different objects. Fail otherwise. The objects * have to be identical though. * @param mixed $first Object reference to check. * @param mixed $second Hopefully not the same object. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertClone(&$first, &$second, $message = '%s') { $dumper = &new SimpleDumper(); $message = sprintf( $message, '[' . $dumper->describeValue($first) . '] and [' . $dumper->describeValue($second) . '] should not be the same object'); $identical = &new IdenticalExpectation($first); return $this->assertTrue( $identical->test($second) && ! SimpleTestCompatibility::isReference($first, $second), $message); } /** * @deprecated */ function assertCopy(&$first, &$second, $message = "%s") { $dumper = &new SimpleDumper(); $message = sprintf( $message, "[" . $dumper->describeValue($first) . "] and [" . $dumper->describeValue($second) . "] should not be the same object"); return $this->assertFalse( SimpleTestCompatibility::isReference($first, $second), $message); } /** * Will trigger a pass if the Perl regex pattern * is found in the subject. Fail otherwise. * @param string $pattern Perl regex to look for including * the regex delimiters. * @param string $subject String to search in. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertPattern($pattern, $subject, $message = '%s') { return $this->assert( new PatternExpectation($pattern), $subject, $message); } /** * @deprecated */ function assertWantedPattern($pattern, $subject, $message = '%s') { return $this->assertPattern($pattern, $subject, $message); } /** * Will trigger a pass if the perl regex pattern * is not present in subject. Fail if found. * @param string $pattern Perl regex to look for including * the regex delimiters. * @param string $subject String to search in. * @param string $message Message to display. * @return boolean True on pass * @access public */ function assertNoPattern($pattern, $subject, $message = '%s') { return $this->assert( new NoPatternExpectation($pattern), $subject, $message); } /** * @deprecated */ function assertNoUnwantedPattern($pattern, $subject, $message = '%s') { return $this->assertNoPattern($pattern, $subject, $message); } /** * @deprecated */ function swallowErrors() { $context = &SimpleTest::getContext(); $queue = &$context->get('SimpleErrorQueue'); $queue->clear(); } /** * @deprecated */ function assertNoErrors($message = '%s') { $context = &SimpleTest::getContext(); $queue = &$context->get('SimpleErrorQueue'); return $queue->assertNoErrors($message); } /** * @deprecated */ function assertError($expected = false, $message = '%s') { $context = &SimpleTest::getContext(); $queue = &$context->get('SimpleErrorQueue'); return $queue->assertError($this->_coerceExpectation($expected), $message); } /** * Prepares for an error. If the error mismatches it * passes through, otherwise it is swallowed. Any * left over errors trigger failures. * @param SimpleExpectation/string $expected The error to match. * @param string $message Message on failure. * @access public */ function expectError($expected = false, $message = '%s') { $context = &SimpleTest::getContext(); $queue = &$context->get('SimpleErrorQueue'); $queue->expectError($this->_coerceExpectation($expected), $message); } /** * Prepares for an exception. If the error mismatches it * passes through, otherwise it is swallowed. Any * left over errors trigger failures. * @param SimpleExpectation/Exception $expected The error to match. * @param string $message Message on failure. * @access public */ function expectException($expected = false, $message = '%s') { $context = &SimpleTest::getContext(); $queue = &$context->get('SimpleExceptionTrap'); $queue->expectException($expected, $message . $this->getAssertionLine()); } /** * Creates an equality expectation if the * object/value is not already some type * of expectation. * @param mixed $expected Expected value. * @return SimpleExpectation Expectation object. * @access private */ function _coerceExpectation($expected) { if ($expected == false) { return new AnythingExpectation(); } if (SimpleTestCompatibility::isA($expected, 'SimpleExpectation')) { return $expected; } if(is_string($expected)) { $expected = str_replace('%', '%%', $expected); } return new EqualExpectation($expected); } /** * @deprecated */ function assertErrorPattern($pattern, $message = '%s') { return $this->assertError(new PatternExpectation($pattern), $message); } } ?>postfixadmin-2.3.7/tests/simpletest/form.php0000664000175000017620000003131311157271050021266 0ustar davidpalepurple_method = $tag->getAttribute('method'); $this->_action = $this->_createAction($tag->getAttribute('action'), $url); $this->_encoding = $this->_setEncodingClass($tag); $this->_default_target = false; $this->_id = $tag->getAttribute('id'); $this->_buttons = array(); $this->_images = array(); $this->_widgets = array(); $this->_radios = array(); $this->_checkboxes = array(); } /** * Creates the request packet to be sent by the form. * @param SimpleTag $tag Form tag to read. * @return string Packet class. * @access private */ function _setEncodingClass($tag) { if (strtolower($tag->getAttribute('method')) == 'post') { if (strtolower($tag->getAttribute('enctype')) == 'multipart/form-data') { return 'SimpleMultipartEncoding'; } return 'SimplePostEncoding'; } return 'SimpleGetEncoding'; } /** * Sets the frame target within a frameset. * @param string $frame Name of frame. * @access public */ function setDefaultTarget($frame) { $this->_default_target = $frame; } /** * Accessor for method of form submission. * @return string Either get or post. * @access public */ function getMethod() { return ($this->_method ? strtolower($this->_method) : 'get'); } /** * Combined action attribute with current location * to get an absolute form target. * @param string $action Action attribute from form tag. * @param SimpleUrl $base Page location. * @return SimpleUrl Absolute form target. */ function _createAction($action, $base) { if (($action === '') || ($action === false)) { return $base; } $url = new SimpleUrl($action); return $url->makeAbsolute($base); } /** * Absolute URL of the target. * @return SimpleUrl URL target. * @access public */ function getAction() { $url = $this->_action; if ($this->_default_target && ! $url->getTarget()) { $url->setTarget($this->_default_target); } return $url; } /** * Creates the encoding for the current values in the * form. * @return SimpleFormEncoding Request to submit. * @access private */ function _encode() { $class = $this->_encoding; $encoding = new $class(); for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) { $this->_widgets[$i]->write($encoding); } return $encoding; } /** * ID field of form for unique identification. * @return string Unique tag ID. * @access public */ function getId() { return $this->_id; } /** * Adds a tag contents to the form. * @param SimpleWidget $tag Input tag to add. * @access public */ function addWidget(&$tag) { if (strtolower($tag->getAttribute('type')) == 'submit') { $this->_buttons[] = &$tag; } elseif (strtolower($tag->getAttribute('type')) == 'image') { $this->_images[] = &$tag; } elseif ($tag->getName()) { $this->_setWidget($tag); } } /** * Sets the widget into the form, grouping radio * buttons if any. * @param SimpleWidget $tag Incoming form control. * @access private */ function _setWidget(&$tag) { if (strtolower($tag->getAttribute('type')) == 'radio') { $this->_addRadioButton($tag); } elseif (strtolower($tag->getAttribute('type')) == 'checkbox') { $this->_addCheckbox($tag); } else { $this->_widgets[] = &$tag; } } /** * Adds a radio button, building a group if necessary. * @param SimpleRadioButtonTag $tag Incoming form control. * @access private */ function _addRadioButton(&$tag) { if (! isset($this->_radios[$tag->getName()])) { $this->_widgets[] = &new SimpleRadioGroup(); $this->_radios[$tag->getName()] = count($this->_widgets) - 1; } $this->_widgets[$this->_radios[$tag->getName()]]->addWidget($tag); } /** * Adds a checkbox, making it a group on a repeated name. * @param SimpleCheckboxTag $tag Incoming form control. * @access private */ function _addCheckbox(&$tag) { if (! isset($this->_checkboxes[$tag->getName()])) { $this->_widgets[] = &$tag; $this->_checkboxes[$tag->getName()] = count($this->_widgets) - 1; } else { $index = $this->_checkboxes[$tag->getName()]; if (! SimpleTestCompatibility::isA($this->_widgets[$index], 'SimpleCheckboxGroup')) { $previous = &$this->_widgets[$index]; $this->_widgets[$index] = &new SimpleCheckboxGroup(); $this->_widgets[$index]->addWidget($previous); } $this->_widgets[$index]->addWidget($tag); } } /** * Extracts current value from form. * @param SimpleSelector $selector Criteria to apply. * @return string/array Value(s) as string or null * if not set. * @access public */ function getValue($selector) { for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) { if ($selector->isMatch($this->_widgets[$i])) { return $this->_widgets[$i]->getValue(); } } foreach ($this->_buttons as $button) { if ($selector->isMatch($button)) { return $button->getValue(); } } return null; } /** * Sets a widget value within the form. * @param SimpleSelector $selector Criteria to apply. * @param string $value Value to input into the widget. * @return boolean True if value is legal, false * otherwise. If the field is not * present, nothing will be set. * @access public */ function setField($selector, $value) { $success = false; for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) { if ($selector->isMatch($this->_widgets[$i])) { if ($this->_widgets[$i]->setValue($value)) { $success = true; } } } return $success; } /** * Used by the page object to set widgets labels to * external label tags. * @param SimpleSelector $selector Criteria to apply. * @access public */ function attachLabelBySelector($selector, $label) { for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) { if ($selector->isMatch($this->_widgets[$i])) { if (method_exists($this->_widgets[$i], 'setLabel')) { $this->_widgets[$i]->setLabel($label); return; } } } } /** * Test to see if a form has a submit button. * @param SimpleSelector $selector Criteria to apply. * @return boolean True if present. * @access public */ function hasSubmit($selector) { foreach ($this->_buttons as $button) { if ($selector->isMatch($button)) { return true; } } return false; } /** * Test to see if a form has an image control. * @param SimpleSelector $selector Criteria to apply. * @return boolean True if present. * @access public */ function hasImage($selector) { foreach ($this->_images as $image) { if ($selector->isMatch($image)) { return true; } } return false; } /** * Gets the submit values for a selected button. * @param SimpleSelector $selector Criteria to apply. * @param hash $additional Additional data for the form. * @return SimpleEncoding Submitted values or false * if there is no such button * in the form. * @access public */ function submitButton($selector, $additional = false) { $additional = $additional ? $additional : array(); foreach ($this->_buttons as $button) { if ($selector->isMatch($button)) { $encoding = $this->_encode(); $button->write($encoding); if ($additional) { $encoding->merge($additional); } return $encoding; } } return false; } /** * Gets the submit values for an image. * @param SimpleSelector $selector Criteria to apply. * @param integer $x X-coordinate of click. * @param integer $y Y-coordinate of click. * @param hash $additional Additional data for the form. * @return SimpleEncoding Submitted values or false * if there is no such button in the * form. * @access public */ function submitImage($selector, $x, $y, $additional = false) { $additional = $additional ? $additional : array(); foreach ($this->_images as $image) { if ($selector->isMatch($image)) { $encoding = $this->_encode(); $image->write($encoding, $x, $y); if ($additional) { $encoding->merge($additional); } return $encoding; } } return false; } /** * Simply submits the form without the submit button * value. Used when there is only one button or it * is unimportant. * @return hash Submitted values. * @access public */ function submit() { return $this->_encode(); } } ?> postfixadmin-2.3.7/tests/simpletest/tag.php0000664000175000017620000012472311157271050021106 0ustar davidpalepurple_name = strtolower(trim($name)); $this->_attributes = $attributes; $this->_content = ''; } /** * Check to see if the tag can have both start and * end tags with content in between. * @return boolean True if content allowed. * @access public */ function expectEndTag() { return true; } /** * The current tag should not swallow all content for * itself as it's searchable page content. Private * content tags are usually widgets that contain default * values. * @return boolean False as content is available * to other tags by default. * @access public */ function isPrivateContent() { return false; } /** * Appends string content to the current content. * @param string $content Additional text. * @access public */ function addContent($content) { $this->_content .= (string)$content; } /** * Adds an enclosed tag to the content. * @param SimpleTag $tag New tag. * @access public */ function addTag(&$tag) { } /** * Accessor for tag name. * @return string Name of tag. * @access public */ function getTagName() { return $this->_name; } /** * List of legal child elements. * @return array List of element names. * @access public */ function getChildElements() { return array(); } /** * Accessor for an attribute. * @param string $label Attribute name. * @return string Attribute value. * @access public */ function getAttribute($label) { $label = strtolower($label); if (! isset($this->_attributes[$label])) { return false; } return (string)$this->_attributes[$label]; } /** * Sets an attribute. * @param string $label Attribute name. * @return string $value New attribute value. * @access protected */ function _setAttribute($label, $value) { $this->_attributes[strtolower($label)] = $value; } /** * Accessor for the whole content so far. * @return string Content as big raw string. * @access public */ function getContent() { return $this->_content; } /** * Accessor for content reduced to visible text. Acts * like a text mode browser, normalising space and * reducing images to their alt text. * @return string Content as plain text. * @access public */ function getText() { return SimpleHtmlSaxParser::normalise($this->_content); } /** * Test to see if id attribute matches. * @param string $id ID to test against. * @return boolean True on match. * @access public */ function isId($id) { return ($this->getAttribute('id') == $id); } } /** * Page title. * @package SimpleTest * @subpackage WebTester */ class SimpleTitleTag extends SimpleTag { /** * Starts with a named tag with attributes only. * @param hash $attributes Attribute names and * string values. */ function SimpleTitleTag($attributes) { $this->SimpleTag('title', $attributes); } } /** * Link. * @package SimpleTest * @subpackage WebTester */ class SimpleAnchorTag extends SimpleTag { /** * Starts with a named tag with attributes only. * @param hash $attributes Attribute names and * string values. */ function SimpleAnchorTag($attributes) { $this->SimpleTag('a', $attributes); } /** * Accessor for URL as string. * @return string Coerced as string. * @access public */ function getHref() { $url = $this->getAttribute('href'); if (is_bool($url)) { $url = ''; } return $url; } } /** * Form element. * @package SimpleTest * @subpackage WebTester */ class SimpleWidget extends SimpleTag { var $_value; var $_label; var $_is_set; /** * Starts with a named tag with attributes only. * @param string $name Tag name. * @param hash $attributes Attribute names and * string values. */ function SimpleWidget($name, $attributes) { $this->SimpleTag($name, $attributes); $this->_value = false; $this->_label = false; $this->_is_set = false; } /** * Accessor for name submitted as the key in * GET/POST variables hash. * @return string Parsed value. * @access public */ function getName() { return $this->getAttribute('name'); } /** * Accessor for default value parsed with the tag. * @return string Parsed value. * @access public */ function getDefault() { return $this->getAttribute('value'); } /** * Accessor for currently set value or default if * none. * @return string Value set by form or default * if none. * @access public */ function getValue() { if (! $this->_is_set) { return $this->getDefault(); } return $this->_value; } /** * Sets the current form element value. * @param string $value New value. * @return boolean True if allowed. * @access public */ function setValue($value) { $this->_value = $value; $this->_is_set = true; return true; } /** * Resets the form element value back to the * default. * @access public */ function resetValue() { $this->_is_set = false; } /** * Allows setting of a label externally, say by a * label tag. * @param string $label Label to attach. * @access public */ function setLabel($label) { $this->_label = trim($label); } /** * Reads external or internal label. * @param string $label Label to test. * @return boolean True is match. * @access public */ function isLabel($label) { return $this->_label == trim($label); } /** * Dispatches the value into the form encoded packet. * @param SimpleEncoding $encoding Form packet. * @access public */ function write(&$encoding) { if ($this->getName()) { $encoding->add($this->getName(), $this->getValue()); } } } /** * Text, password and hidden field. * @package SimpleTest * @subpackage WebTester */ class SimpleTextTag extends SimpleWidget { /** * Starts with a named tag with attributes only. * @param hash $attributes Attribute names and * string values. */ function SimpleTextTag($attributes) { $this->SimpleWidget('input', $attributes); if ($this->getAttribute('value') === false) { $this->_setAttribute('value', ''); } } /** * Tag contains no content. * @return boolean False. * @access public */ function expectEndTag() { return false; } /** * Sets the current form element value. Cannot * change the value of a hidden field. * @param string $value New value. * @return boolean True if allowed. * @access public */ function setValue($value) { if ($this->getAttribute('type') == 'hidden') { return false; } return parent::setValue($value); } } /** * Submit button as input tag. * @package SimpleTest * @subpackage WebTester */ class SimpleSubmitTag extends SimpleWidget { /** * Starts with a named tag with attributes only. * @param hash $attributes Attribute names and * string values. */ function SimpleSubmitTag($attributes) { $this->SimpleWidget('input', $attributes); if ($this->getAttribute('value') === false) { $this->_setAttribute('value', 'Submit'); } } /** * Tag contains no end element. * @return boolean False. * @access public */ function expectEndTag() { return false; } /** * Disables the setting of the button value. * @param string $value Ignored. * @return boolean True if allowed. * @access public */ function setValue($value) { return false; } /** * Value of browser visible text. * @return string Visible label. * @access public */ function getLabel() { return $this->getValue(); } /** * Test for a label match when searching. * @param string $label Label to test. * @return boolean True on match. * @access public */ function isLabel($label) { return trim($label) == trim($this->getLabel()); } } /** * Image button as input tag. * @package SimpleTest * @subpackage WebTester */ class SimpleImageSubmitTag extends SimpleWidget { /** * Starts with a named tag with attributes only. * @param hash $attributes Attribute names and * string values. */ function SimpleImageSubmitTag($attributes) { $this->SimpleWidget('input', $attributes); } /** * Tag contains no end element. * @return boolean False. * @access public */ function expectEndTag() { return false; } /** * Disables the setting of the button value. * @param string $value Ignored. * @return boolean True if allowed. * @access public */ function setValue($value) { return false; } /** * Value of browser visible text. * @return string Visible label. * @access public */ function getLabel() { if ($this->getAttribute('title')) { return $this->getAttribute('title'); } return $this->getAttribute('alt'); } /** * Test for a label match when searching. * @param string $label Label to test. * @return boolean True on match. * @access public */ function isLabel($label) { return trim($label) == trim($this->getLabel()); } /** * Dispatches the value into the form encoded packet. * @param SimpleEncoding $encoding Form packet. * @param integer $x X coordinate of click. * @param integer $y Y coordinate of click. * @access public */ function write(&$encoding, $x, $y) { if ($this->getName()) { $encoding->add($this->getName() . '.x', $x); $encoding->add($this->getName() . '.y', $y); } else { $encoding->add('x', $x); $encoding->add('y', $y); } } } /** * Submit button as button tag. * @package SimpleTest * @subpackage WebTester */ class SimpleButtonTag extends SimpleWidget { /** * Starts with a named tag with attributes only. * Defaults are very browser dependent. * @param hash $attributes Attribute names and * string values. */ function SimpleButtonTag($attributes) { $this->SimpleWidget('button', $attributes); } /** * Check to see if the tag can have both start and * end tags with content in between. * @return boolean True if content allowed. * @access public */ function expectEndTag() { return true; } /** * Disables the setting of the button value. * @param string $value Ignored. * @return boolean True if allowed. * @access public */ function setValue($value) { return false; } /** * Value of browser visible text. * @return string Visible label. * @access public */ function getLabel() { return $this->getContent(); } /** * Test for a label match when searching. * @param string $label Label to test. * @return boolean True on match. * @access public */ function isLabel($label) { return trim($label) == trim($this->getLabel()); } } /** * Content tag for text area. * @package SimpleTest * @subpackage WebTester */ class SimpleTextAreaTag extends SimpleWidget { /** * Starts with a named tag with attributes only. * @param hash $attributes Attribute names and * string values. */ function SimpleTextAreaTag($attributes) { $this->SimpleWidget('textarea', $attributes); } /** * Accessor for starting value. * @return string Parsed value. * @access public */ function getDefault() { return $this->_wrap(SimpleHtmlSaxParser::decodeHtml($this->getContent())); } /** * Applies word wrapping if needed. * @param string $value New value. * @return boolean True if allowed. * @access public */ function setValue($value) { return parent::setValue($this->_wrap($value)); } /** * Test to see if text should be wrapped. * @return boolean True if wrapping on. * @access private */ function _wrapIsEnabled() { if ($this->getAttribute('cols')) { $wrap = $this->getAttribute('wrap'); if (($wrap == 'physical') || ($wrap == 'hard')) { return true; } } return false; } /** * Performs the formatting that is peculiar to * this tag. There is strange behaviour in this * one, including stripping a leading new line. * Go figure. I am using Firefox as a guide. * @param string $text Text to wrap. * @return string Text wrapped with carriage * returns and line feeds * @access private */ function _wrap($text) { $text = str_replace("\r\r\n", "\r\n", str_replace("\n", "\r\n", $text)); $text = str_replace("\r\n\n", "\r\n", str_replace("\r", "\r\n", $text)); if (strncmp($text, "\r\n", strlen("\r\n")) == 0) { $text = substr($text, strlen("\r\n")); } if ($this->_wrapIsEnabled()) { return wordwrap( $text, (integer)$this->getAttribute('cols'), "\r\n"); } return $text; } /** * The content of textarea is not part of the page. * @return boolean True. * @access public */ function isPrivateContent() { return true; } } /** * File upload widget. * @package SimpleTest * @subpackage WebTester */ class SimpleUploadTag extends SimpleWidget { /** * Starts with attributes only. * @param hash $attributes Attribute names and * string values. */ function SimpleUploadTag($attributes) { $this->SimpleWidget('input', $attributes); } /** * Tag contains no content. * @return boolean False. * @access public */ function expectEndTag() { return false; } /** * Dispatches the value into the form encoded packet. * @param SimpleEncoding $encoding Form packet. * @access public */ function write(&$encoding) { if (! file_exists($this->getValue())) { return; } $encoding->attach( $this->getName(), implode('', file($this->getValue())), basename($this->getValue())); } } /** * Drop down widget. * @package SimpleTest * @subpackage WebTester */ class SimpleSelectionTag extends SimpleWidget { var $_options; var $_choice; /** * Starts with attributes only. * @param hash $attributes Attribute names and * string values. */ function SimpleSelectionTag($attributes) { $this->SimpleWidget('select', $attributes); $this->_options = array(); $this->_choice = false; } /** * Adds an option tag to a selection field. * @param SimpleOptionTag $tag New option. * @access public */ function addTag(&$tag) { if ($tag->getTagName() == 'option') { $this->_options[] = &$tag; } } /** * Text within the selection element is ignored. * @param string $content Ignored. * @access public */ function addContent($content) { } /** * Scans options for defaults. If none, then * the first option is selected. * @return string Selected field. * @access public */ function getDefault() { for ($i = 0, $count = count($this->_options); $i < $count; $i++) { if ($this->_options[$i]->getAttribute('selected') !== false) { return $this->_options[$i]->getDefault(); } } if ($count > 0) { return $this->_options[0]->getDefault(); } return ''; } /** * Can only set allowed values. * @param string $value New choice. * @return boolean True if allowed. * @access public */ function setValue($value) { for ($i = 0, $count = count($this->_options); $i < $count; $i++) { if ($this->_options[$i]->isValue($value)) { $this->_choice = $i; return true; } } return false; } /** * Accessor for current selection value. * @return string Value attribute or * content of opton. * @access public */ function getValue() { if ($this->_choice === false) { return $this->getDefault(); } return $this->_options[$this->_choice]->getValue(); } } /** * Drop down widget. * @package SimpleTest * @subpackage WebTester */ class MultipleSelectionTag extends SimpleWidget { var $_options; var $_values; /** * Starts with attributes only. * @param hash $attributes Attribute names and * string values. */ function MultipleSelectionTag($attributes) { $this->SimpleWidget('select', $attributes); $this->_options = array(); $this->_values = false; } /** * Adds an option tag to a selection field. * @param SimpleOptionTag $tag New option. * @access public */ function addTag(&$tag) { if ($tag->getTagName() == 'option') { $this->_options[] = &$tag; } } /** * Text within the selection element is ignored. * @param string $content Ignored. * @access public */ function addContent($content) { } /** * Scans options for defaults to populate the * value array(). * @return array Selected fields. * @access public */ function getDefault() { $default = array(); for ($i = 0, $count = count($this->_options); $i < $count; $i++) { if ($this->_options[$i]->getAttribute('selected') !== false) { $default[] = $this->_options[$i]->getDefault(); } } return $default; } /** * Can only set allowed values. Any illegal value * will result in a failure, but all correct values * will be set. * @param array $desired New choices. * @return boolean True if all allowed. * @access public */ function setValue($desired) { $achieved = array(); foreach ($desired as $value) { $success = false; for ($i = 0, $count = count($this->_options); $i < $count; $i++) { if ($this->_options[$i]->isValue($value)) { $achieved[] = $this->_options[$i]->getValue(); $success = true; break; } } if (! $success) { return false; } } $this->_values = $achieved; return true; } /** * Accessor for current selection value. * @return array List of currently set options. * @access public */ function getValue() { if ($this->_values === false) { return $this->getDefault(); } return $this->_values; } } /** * Option for selection field. * @package SimpleTest * @subpackage WebTester */ class SimpleOptionTag extends SimpleWidget { /** * Stashes the attributes. */ function SimpleOptionTag($attributes) { $this->SimpleWidget('option', $attributes); } /** * Does nothing. * @param string $value Ignored. * @return boolean Not allowed. * @access public */ function setValue($value) { return false; } /** * Test to see if a value matches the option. * @param string $compare Value to compare with. * @return boolean True if possible match. * @access public */ function isValue($compare) { $compare = trim($compare); if (trim($this->getValue()) == $compare) { return true; } return trim($this->getContent()) == $compare; } /** * Accessor for starting value. Will be set to * the option label if no value exists. * @return string Parsed value. * @access public */ function getDefault() { if ($this->getAttribute('value') === false) { return $this->getContent(); } return $this->getAttribute('value'); } /** * The content of options is not part of the page. * @return boolean True. * @access public */ function isPrivateContent() { return true; } } /** * Radio button. * @package SimpleTest * @subpackage WebTester */ class SimpleRadioButtonTag extends SimpleWidget { /** * Stashes the attributes. * @param array $attributes Hash of attributes. */ function SimpleRadioButtonTag($attributes) { $this->SimpleWidget('input', $attributes); if ($this->getAttribute('value') === false) { $this->_setAttribute('value', 'on'); } } /** * Tag contains no content. * @return boolean False. * @access public */ function expectEndTag() { return false; } /** * The only allowed value sn the one in the * "value" attribute. * @param string $value New value. * @return boolean True if allowed. * @access public */ function setValue($value) { if ($value === false) { return parent::setValue($value); } if ($value !== $this->getAttribute('value')) { return false; } return parent::setValue($value); } /** * Accessor for starting value. * @return string Parsed value. * @access public */ function getDefault() { if ($this->getAttribute('checked') !== false) { return $this->getAttribute('value'); } return false; } } /** * Checkbox widget. * @package SimpleTest * @subpackage WebTester */ class SimpleCheckboxTag extends SimpleWidget { /** * Starts with attributes only. * @param hash $attributes Attribute names and * string values. */ function SimpleCheckboxTag($attributes) { $this->SimpleWidget('input', $attributes); if ($this->getAttribute('value') === false) { $this->_setAttribute('value', 'on'); } } /** * Tag contains no content. * @return boolean False. * @access public */ function expectEndTag() { return false; } /** * The only allowed value in the one in the * "value" attribute. The default for this * attribute is "on". If this widget is set to * true, then the usual value will be taken. * @param string $value New value. * @return boolean True if allowed. * @access public */ function setValue($value) { if ($value === false) { return parent::setValue($value); } if ($value === true) { return parent::setValue($this->getAttribute('value')); } if ($value != $this->getAttribute('value')) { return false; } return parent::setValue($value); } /** * Accessor for starting value. The default * value is "on". * @return string Parsed value. * @access public */ function getDefault() { if ($this->getAttribute('checked') !== false) { return $this->getAttribute('value'); } return false; } } /** * A group of multiple widgets with some shared behaviour. * @package SimpleTest * @subpackage WebTester */ class SimpleTagGroup { var $_widgets = array(); /** * Adds a tag to the group. * @param SimpleWidget $widget * @access public */ function addWidget(&$widget) { $this->_widgets[] = &$widget; } /** * Accessor to widget set. * @return array All widgets. * @access protected */ function &_getWidgets() { return $this->_widgets; } /** * Accessor for an attribute. * @param string $label Attribute name. * @return boolean Always false. * @access public */ function getAttribute($label) { return false; } /** * Fetches the name for the widget from the first * member. * @return string Name of widget. * @access public */ function getName() { if (count($this->_widgets) > 0) { return $this->_widgets[0]->getName(); } } /** * Scans the widgets for one with the appropriate * ID field. * @param string $id ID value to try. * @return boolean True if matched. * @access public */ function isId($id) { for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) { if ($this->_widgets[$i]->isId($id)) { return true; } } return false; } /** * Scans the widgets for one with the appropriate * attached label. * @param string $label Attached label to try. * @return boolean True if matched. * @access public */ function isLabel($label) { for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) { if ($this->_widgets[$i]->isLabel($label)) { return true; } } return false; } /** * Dispatches the value into the form encoded packet. * @param SimpleEncoding $encoding Form packet. * @access public */ function write(&$encoding) { $encoding->add($this->getName(), $this->getValue()); } } /** * A group of tags with the same name within a form. * @package SimpleTest * @subpackage WebTester */ class SimpleCheckboxGroup extends SimpleTagGroup { /** * Accessor for current selected widget or false * if none. * @return string/array Widget values or false if none. * @access public */ function getValue() { $values = array(); $widgets = &$this->_getWidgets(); for ($i = 0, $count = count($widgets); $i < $count; $i++) { if ($widgets[$i]->getValue() !== false) { $values[] = $widgets[$i]->getValue(); } } return $this->_coerceValues($values); } /** * Accessor for starting value that is active. * @return string/array Widget values or false if none. * @access public */ function getDefault() { $values = array(); $widgets = &$this->_getWidgets(); for ($i = 0, $count = count($widgets); $i < $count; $i++) { if ($widgets[$i]->getDefault() !== false) { $values[] = $widgets[$i]->getDefault(); } } return $this->_coerceValues($values); } /** * Accessor for current set values. * @param string/array/boolean $values Either a single string, a * hash or false for nothing set. * @return boolean True if all values can be set. * @access public */ function setValue($values) { $values = $this->_makeArray($values); if (! $this->_valuesArePossible($values)) { return false; } $widgets = &$this->_getWidgets(); for ($i = 0, $count = count($widgets); $i < $count; $i++) { $possible = $widgets[$i]->getAttribute('value'); if (in_array($widgets[$i]->getAttribute('value'), $values)) { $widgets[$i]->setValue($possible); } else { $widgets[$i]->setValue(false); } } return true; } /** * Tests to see if a possible value set is legal. * @param string/array/boolean $values Either a single string, a * hash or false for nothing set. * @return boolean False if trying to set a * missing value. * @access private */ function _valuesArePossible($values) { $matches = array(); $widgets = &$this->_getWidgets(); for ($i = 0, $count = count($widgets); $i < $count; $i++) { $possible = $widgets[$i]->getAttribute('value'); if (in_array($possible, $values)) { $matches[] = $possible; } } return ($values == $matches); } /** * Converts the output to an appropriate format. This means * that no values is false, a single value is just that * value and only two or more are contained in an array. * @param array $values List of values of widgets. * @return string/array/boolean Expected format for a tag. * @access private */ function _coerceValues($values) { if (count($values) == 0) { return false; } elseif (count($values) == 1) { return $values[0]; } else { return $values; } } /** * Converts false or string into array. The opposite of * the coercian method. * @param string/array/boolean $value A single item is converted * to a one item list. False * gives an empty list. * @return array List of values, possibly empty. * @access private */ function _makeArray($value) { if ($value === false) { return array(); } if (is_string($value)) { return array($value); } return $value; } } /** * A group of tags with the same name within a form. * Used for radio buttons. * @package SimpleTest * @subpackage WebTester */ class SimpleRadioGroup extends SimpleTagGroup { /** * Each tag is tried in turn until one is * successfully set. The others will be * unchecked if successful. * @param string $value New value. * @return boolean True if any allowed. * @access public */ function setValue($value) { if (! $this->_valueIsPossible($value)) { return false; } $index = false; $widgets = &$this->_getWidgets(); for ($i = 0, $count = count($widgets); $i < $count; $i++) { if (! $widgets[$i]->setValue($value)) { $widgets[$i]->setValue(false); } } return true; } /** * Tests to see if a value is allowed. * @param string Attempted value. * @return boolean True if a valid value. * @access private */ function _valueIsPossible($value) { $widgets = &$this->_getWidgets(); for ($i = 0, $count = count($widgets); $i < $count; $i++) { if ($widgets[$i]->getAttribute('value') == $value) { return true; } } return false; } /** * Accessor for current selected widget or false * if none. * @return string/boolean Value attribute or * content of opton. * @access public */ function getValue() { $widgets = &$this->_getWidgets(); for ($i = 0, $count = count($widgets); $i < $count; $i++) { if ($widgets[$i]->getValue() !== false) { return $widgets[$i]->getValue(); } } return false; } /** * Accessor for starting value that is active. * @return string/boolean Value of first checked * widget or false if none. * @access public */ function getDefault() { $widgets = &$this->_getWidgets(); for ($i = 0, $count = count($widgets); $i < $count; $i++) { if ($widgets[$i]->getDefault() !== false) { return $widgets[$i]->getDefault(); } } return false; } } /** * Tag to keep track of labels. * @package SimpleTest * @subpackage WebTester */ class SimpleLabelTag extends SimpleTag { /** * Starts with a named tag with attributes only. * @param hash $attributes Attribute names and * string values. */ function SimpleLabelTag($attributes) { $this->SimpleTag('label', $attributes); } /** * Access for the ID to attach the label to. * @return string For attribute. * @access public */ function getFor() { return $this->getAttribute('for'); } } /** * Tag to aid parsing the form. * @package SimpleTest * @subpackage WebTester */ class SimpleFormTag extends SimpleTag { /** * Starts with a named tag with attributes only. * @param hash $attributes Attribute names and * string values. */ function SimpleFormTag($attributes) { $this->SimpleTag('form', $attributes); } } /** * Tag to aid parsing the frames in a page. * @package SimpleTest * @subpackage WebTester */ class SimpleFrameTag extends SimpleTag { /** * Starts with a named tag with attributes only. * @param hash $attributes Attribute names and * string values. */ function SimpleFrameTag($attributes) { $this->SimpleTag('frame', $attributes); } /** * Tag contains no content. * @return boolean False. * @access public */ function expectEndTag() { return false; } } ?>postfixadmin-2.3.7/tests/simpletest/collector.php0000664000175000017620000000715111157271050022314 0ustar davidpalepurple * @package SimpleTest * @subpackage UnitTester * @version $Id: collector.php,v 1.11 2006/11/21 00:26:55 lastcraft Exp $ */ /** * The basic collector for {@link GroupTest} * * @see collect(), GroupTest::collect() * @package SimpleTest * @subpackage UnitTester */ class SimpleCollector { /** * Strips off any kind of slash at the end so as to normalise the path. * @param string $path Path to normalise. * @return string Path without trailing slash. */ function _removeTrailingSlash($path) { if (substr($path, -1) == DIRECTORY_SEPARATOR) { return substr($path, 0, -1); } elseif (substr($path, -1) == '/') { return substr($path, 0, -1); } else { return $path; } } /** * Scans the directory and adds what it can. * @param object $test Group test with {@link GroupTest::addTestFile()} method. * @param string $path Directory to scan. * @see _attemptToAdd() */ function collect(&$test, $path) { $path = $this->_removeTrailingSlash($path); if ($handle = opendir($path)) { while (($entry = readdir($handle)) !== false) { $this->_handle($test, $path . DIRECTORY_SEPARATOR . $entry); } closedir($handle); } } /** * This method determines what should be done with a given file and adds * it via {@link GroupTest::addTestFile()} if necessary. * * This method should be overriden to provide custom matching criteria, * such as pattern matching, recursive matching, etc. For an example, see * {@link SimplePatternCollector::_handle()}. * * @param object $test Group test with {@link GroupTest::addTestFile()} method. * @param string $filename A filename as generated by {@link collect()} * @see collect() * @access protected */ function _handle(&$test, $file) { if (! is_dir($file)) { $test->addTestFile($file); } } } /** * An extension to {@link SimpleCollector} that only adds files matching a * given pattern. * * @package SimpleTest * @subpackage UnitTester * @see SimpleCollector */ class SimplePatternCollector extends SimpleCollector { var $_pattern; /** * * @param string $pattern Perl compatible regex to test name against * See {@link http://us4.php.net/manual/en/reference.pcre.pattern.syntax.php PHP's PCRE} * for full documentation of valid pattern.s */ function SimplePatternCollector($pattern = '/php$/i') { $this->_pattern = $pattern; } /** * Attempts to add files that match a given pattern. * * @see SimpleCollector::_handle() * @param object $test Group test with {@link GroupTest::addTestFile()} method. * @param string $path Directory to scan. * @access protected */ function _handle(&$test, $filename) { if (preg_match($this->_pattern, $filename)) { parent::_handle($test, $filename); } } } ?>postfixadmin-2.3.7/tests/simpletest/reporter.php0000664000175000017620000003657311157271050022202 0ustar davidpalepurpleSimpleReporter(); $this->_character_set = $character_set; } /** * Paints the top of the web page setting the * title to the name of the starting test. * @param string $test_name Name class of test. * @access public */ function paintHeader($test_name) { $this->sendNoCacheHeaders(); print ""; print "\n\n$test_name\n"; print "\n"; print "\n"; print "\n\n"; print "

    $test_name

    \n"; flush(); } /** * Send the headers necessary to ensure the page is * reloaded on every request. Otherwise you could be * scratching your head over out of date test data. * @access public * @static */ function sendNoCacheHeaders() { if (! headers_sent()) { header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache"); } } /** * Paints the CSS. Add additional styles here. * @return string CSS code as text. * @access protected */ function _getCss() { return ".fail { background-color: inherit; color: red; }" . ".pass { background-color: inherit; color: green; }" . " pre { background-color: lightgray; color: inherit; }"; } /** * Paints the end of the test with a summary of * the passes and failures. * @param string $test_name Name class of test. * @access public */ function paintFooter($test_name) { $colour = ($this->getFailCount() + $this->getExceptionCount() > 0 ? "red" : "green"); print "
    "; print $this->getTestCaseProgress() . "/" . $this->getTestCaseCount(); print " test cases complete:\n"; print "" . $this->getPassCount() . " passes, "; print "" . $this->getFailCount() . " fails and "; print "" . $this->getExceptionCount() . " exceptions."; print "
    \n"; print "\n\n"; } /** * Paints the test failure with a breadcrumbs * trail of the nesting test suites below the * top level test. * @param string $message Failure message displayed in * the context of the other tests. * @access public */ function paintFail($message) { parent::paintFail($message); print "Fail: "; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); print implode(" -> ", $breadcrumb); print " -> " . $this->_htmlEntities($message) . "
    \n"; } /** * Paints a PHP error. * @param string $message Message is ignored. * @access public */ function paintError($message) { parent::paintError($message); print "Exception: "; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); print implode(" -> ", $breadcrumb); print " -> " . $this->_htmlEntities($message) . "
    \n"; } /** * Paints a PHP exception. * @param Exception $exception Exception to display. * @access public */ function paintException($exception) { parent::paintException($exception); print "Exception: "; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); print implode(" -> ", $breadcrumb); $message = 'Unexpected exception of type [' . get_class($exception) . '] with message ['. $exception->getMessage() . '] in ['. $exception->getFile() . ' line ' . $exception->getLine() . ']'; print " -> " . $this->_htmlEntities($message) . "
    \n"; } /** * Prints the message for skipping tests. * @param string $message Text of skip condition. * @access public */ function paintSkip($message) { parent::paintSkip($message); print "Skipped: "; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); print implode(" -> ", $breadcrumb); print " -> " . $this->_htmlEntities($message) . "
    \n"; } /** * Paints formatted text such as dumped variables. * @param string $message Text to show. * @access public */ function paintFormattedMessage($message) { print '
    ' . $this->_htmlEntities($message) . '
    '; } /** * Character set adjusted entity conversion. * @param string $message Plain text or Unicode message. * @return string Browser readable message. * @access protected */ function _htmlEntities($message) { return htmlentities($message, ENT_COMPAT, $this->_character_set); } } /** * Sample minimal test displayer. Generates only * failure messages and a pass count. For command * line use. I've tried to make it look like JUnit, * but I wanted to output the errors as they arrived * which meant dropping the dots. * @package SimpleTest * @subpackage UnitTester */ class TextReporter extends SimpleReporter { /** * Does nothing yet. The first output will * be sent on the first test start. * @access public */ function TextReporter() { $this->SimpleReporter(); } /** * Paints the title only. * @param string $test_name Name class of test. * @access public */ function paintHeader($test_name) { if (! SimpleReporter::inCli()) { header('Content-type: text/plain'); } print "$test_name\n"; flush(); } /** * Paints the end of the test with a summary of * the passes and failures. * @param string $test_name Name class of test. * @access public */ function paintFooter($test_name) { if ($this->getFailCount() + $this->getExceptionCount() == 0) { print "OK\n"; } else { print "FAILURES!!!\n"; } print "Test cases run: " . $this->getTestCaseProgress() . "/" . $this->getTestCaseCount() . ", Passes: " . $this->getPassCount() . ", Failures: " . $this->getFailCount() . ", Exceptions: " . $this->getExceptionCount() . "\n"; } /** * Paints the test failure as a stack trace. * @param string $message Failure message displayed in * the context of the other tests. * @access public */ function paintFail($message) { parent::paintFail($message); print $this->getFailCount() . ") $message\n"; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); print "\tin " . implode("\n\tin ", array_reverse($breadcrumb)); print "\n"; } /** * Paints a PHP error or exception. * @param string $message Message to be shown. * @access public * @abstract */ function paintError($message) { parent::paintError($message); print "Exception " . $this->getExceptionCount() . "!\n$message\n"; } /** * Paints a PHP error or exception. * @param Exception $exception Exception to describe. * @access public * @abstract */ function paintException($exception) { parent::paintException($exception); $message = 'Unexpected exception of type [' . get_class($exception) . '] with message ['. $exception->getMessage() . '] in ['. $exception->getFile() . ' line ' . $exception->getLine() . ']'; print "Exception " . $this->getExceptionCount() . "!\n$message\n"; } /** * Prints the message for skipping tests. * @param string $message Text of skip condition. * @access public */ function paintSkip($message) { parent::paintSkip($message); print "Skip: $message\n"; } /** * Paints formatted text such as dumped variables. * @param string $message Text to show. * @access public */ function paintFormattedMessage($message) { print "$message\n"; flush(); } } /** * Runs just a single test group, a single case or * even a single test within that case. * @package SimpleTest * @subpackage UnitTester */ class SelectiveReporter extends SimpleReporterDecorator { var $_just_this_case =false; var $_just_this_test = false; var $_within_test_case = true; /** * Selects the test case or group to be run, * and optionally a specific test. * @param SimpleScorer $reporter Reporter to receive events. * @param string $just_this_case Only this case or group will run. * @param string $just_this_test Only this test method will run. */ function SelectiveReporter(&$reporter, $just_this_case = false, $just_this_test = false) { if (isset($just_this_case) && $just_this_case) { $this->_just_this_case = strtolower($just_this_case); $this->_within_test_case = false; } if (isset($just_this_test) && $just_this_test) { $this->_just_this_test = strtolower($just_this_test); } $this->SimpleReporterDecorator($reporter); } /** * Compares criteria to actual the case/group name. * @param string $test_case The incoming test. * @return boolean True if matched. * @access protected */ function _isCaseMatch($test_case) { if ($this->_just_this_case) { return $this->_just_this_case == strtolower($test_case); } return false; } /** * Compares criteria to actual the test name. * @param string $method The incoming test method. * @return boolean True if matched. * @access protected */ function _isTestMatch($method) { if ($this->_just_this_test) { return $this->_just_this_test == strtolower($method); } return true; } /** * Veto everything that doesn't match the method wanted. * @param string $test_case Name of test case. * @param string $method Name of test method. * @return boolean True if test should be run. * @access public */ function shouldInvoke($test_case, $method) { if ($this->_within_test_case && $this->_isTestMatch($method)) { return $this->_reporter->shouldInvoke($test_case, $method); } return false; } /** * Paints the start of a group test. * @param string $test_case Name of test or other label. * @param integer $size Number of test cases starting. * @access public */ function paintGroupStart($test_case, $size) { if ($this->_isCaseMatch($test_case)) { $this->_within_test_case = true; } if ($this->_within_test_case) { $this->_reporter->paintGroupStart($test_case, $size); } } /** * Paints the end of a group test. * @param string $test_case Name of test or other label. * @access public */ function paintGroupEnd($test_case) { if ($this->_within_test_case) { $this->_reporter->paintGroupEnd($test_case); } if ($this->_isCaseMatch($test_case)) { $this->_within_test_case = false; } } /** * Paints the start of a test case. * @param string $test_case Name of test or other label. * @access public */ function paintCaseStart($test_case) { if ($this->_isCaseMatch($test_case)) { $this->_within_test_case = true; } if ($this->_within_test_case) { $this->_reporter->paintCaseStart($test_case); } } /** * Paints the end of a test case. * @param string $test_case Name of test or other label. * @access public */ function paintCaseEnd($test_case) { if ($this->_within_test_case) { $this->_reporter->paintCaseEnd($test_case); } if ($this->_isCaseMatch($test_case)) { $this->_within_test_case = false; } } } ?>postfixadmin-2.3.7/tests/simpletest/eclipse.php0000664000175000017620000001103711157271050021750 0ustar davidpalepurple_listener = &$listener; $this->SimpleScorer(); $this->_case = ""; $this->_group = ""; $this->_method = ""; $this->_cc = $cc; $this->_error = false; $this->_fail = false; } function getDumper() { return new SimpleDumper(); } function &createListener($port,$host="127.0.0.1"){ $tmplistener = & new SimpleSocket($host,$port,5); return $tmplistener; } function &createInvoker(&$invoker){ $eclinvoker = & new EclipseInvoker( $invoker, $this->_listener); return $eclinvoker; } function escapeVal($val){ $needle = array("\\","\"","/","\b","\f","\n","\r","\t"); $replace = array('\\\\','\"','\/','\b','\f','\n','\r','\t'); return str_replace($needle,$replace,$val); } function paintPass($message){ //get the first passing item -- so that clicking the test item goes to first pass if (!$this->_pass){ $this->_message = $this->escapeVal($message); } $this->_pass = true; } function paintFail($message){ //only get the first failure or error if (!$this->_fail && !$this->_error){ $this->_fail = true; $this->_message = $this->escapeVal($message); $this->_listener->write('{status:"fail",message:"'.$this->_message.'",group:"'.$this->_group.'",case:"'.$this->_case.'",method:"'.$this->_method.'"}'); } } function paintError($message){ //only get the first failure or error if (!$this->_fail && !$this->_error){ $this->_error = true; $this->_message = $this->escapeVal($message); $this->_listener->write('{status:"error",message:"'.$this->_message.'",group:"'.$this->_group.'",case:"'.$this->_case.'",method:"'.$this->_method.'"}'); } } function paintHeader($method){ } function paintFooter($method){ } function paintMethodStart($method) { $this->_pass = false; $this->_fail = false; $this->_error = false; $this->_method = $this->escapeVal($method); } function paintMethodEnd($method){ if ($this->_fail || $this->_error || !$this->_pass){ //do nothing }else{ //this ensures we only get one message per method that passes $this->_listener->write('{status:"pass",message:"'.$this->_message.'",group:"'.$this->_group.'",case:"'.$this->_case.'",method:"'.$this->_method.'"}'); } } function paintCaseStart($case){ $this->_case = $this->escapeVal($case); } function paintCaseEnd($case){ $this->_case = ""; } function paintGroupStart($group,$size){ $this->_group = $this->escapeVal($group); if ($this->_cc){ if (extension_loaded('xdebug')){ xdebug_start_code_coverage(XDEBUG_CC_UNUSED| XDEBUG_CC_DEAD_CODE); } } } function paintGroupEnd($group){ $this->_group = ""; $cc = ""; if ($this->_cc){ if (extension_loaded('xdebug')){ $arrfiles = xdebug_get_code_coverage(); xdebug_stop_code_coverage(); $thisdir = dirname(__FILE__); $thisdirlen = strlen($thisdir); foreach ($arrfiles as $index=>$file){ if (substr($index,0,$thisdirlen)===$thisdir){ continue; } $lcnt = 0; $ccnt = 0; foreach ($file as $line){ if ($line == -2){ continue; } $lcnt++; if ($line==1){ $ccnt++; } } if ($lcnt > 0){ $cc.=round(($ccnt/$lcnt)*100,2).'%'; }else{ $cc.="0.00%"; } $cc.= "\t".$index."\n"; } } } $this->_listener->write('{status:"coverage",message:"'.EclipseReporter::escapeVal($cc).'"}'); } } /** * base invoker class for eclipse plugin * @package SimpleTest * @subpackage Eclipse */ class EclipseInvoker extends SimpleInvokerDecorator{ function EclipseInvoker(&$invoker,&$listener) { $this->_listener = &$listener; $this->SimpleInvokerDecorator($invoker); } function before($method){ ob_start(); $this->_invoker->before($method); } function after($method) { $this->_invoker->after($method); $output = ob_get_contents(); ob_end_clean(); if ($output!==""){ $result = $this->_listener->write('{status:"info",message:"'.EclipseReporter::escapeVal($output).'"}'); } } } ?>postfixadmin-2.3.7/tests/simpletest/http.php0000664000175000017620000005227611157271050021315 0ustar davidpalepurple_url = $url; } /** * Resource name. * @return SimpleUrl Current url. * @access protected */ function getUrl() { return $this->_url; } /** * Creates the first line which is the actual request. * @param string $method HTTP request method, usually GET. * @return string Request line content. * @access protected */ function _getRequestLine($method) { return $method . ' ' . $this->_url->getPath() . $this->_url->getEncodedRequest() . ' HTTP/1.0'; } /** * Creates the host part of the request. * @return string Host line content. * @access protected */ function _getHostLine() { $line = 'Host: ' . $this->_url->getHost(); if ($this->_url->getPort()) { $line .= ':' . $this->_url->getPort(); } return $line; } /** * Opens a socket to the route. * @param string $method HTTP request method, usually GET. * @param integer $timeout Connection timeout. * @return SimpleSocket New socket. * @access public */ function &createConnection($method, $timeout) { $default_port = ('https' == $this->_url->getScheme()) ? 443 : 80; $socket = &$this->_createSocket( $this->_url->getScheme() ? $this->_url->getScheme() : 'http', $this->_url->getHost(), $this->_url->getPort() ? $this->_url->getPort() : $default_port, $timeout); if (! $socket->isError()) { $socket->write($this->_getRequestLine($method) . "\r\n"); $socket->write($this->_getHostLine() . "\r\n"); $socket->write("Connection: close\r\n"); } return $socket; } /** * Factory for socket. * @param string $scheme Protocol to use. * @param string $host Hostname to connect to. * @param integer $port Remote port. * @param integer $timeout Connection timeout. * @return SimpleSocket/SimpleSecureSocket New socket. * @access protected */ function &_createSocket($scheme, $host, $port, $timeout) { if (in_array($scheme, array('https'))) { $socket = &new SimpleSecureSocket($host, $port, $timeout); } else { $socket = &new SimpleSocket($host, $port, $timeout); } return $socket; } } /** * Creates HTTP headers for the end point of * a HTTP request via a proxy server. * @package SimpleTest * @subpackage WebTester */ class SimpleProxyRoute extends SimpleRoute { var $_proxy; var $_username; var $_password; /** * Stashes the proxy address. * @param SimpleUrl $url URL as object. * @param string $proxy Proxy URL. * @param string $username Username for autentication. * @param string $password Password for autentication. * @access public */ function SimpleProxyRoute($url, $proxy, $username = false, $password = false) { $this->SimpleRoute($url); $this->_proxy = $proxy; $this->_username = $username; $this->_password = $password; } /** * Creates the first line which is the actual request. * @param string $method HTTP request method, usually GET. * @param SimpleUrl $url URL as object. * @return string Request line content. * @access protected */ function _getRequestLine($method) { $url = $this->getUrl(); $scheme = $url->getScheme() ? $url->getScheme() : 'http'; $port = $url->getPort() ? ':' . $url->getPort() : ''; return $method . ' ' . $scheme . '://' . $url->getHost() . $port . $url->getPath() . $url->getEncodedRequest() . ' HTTP/1.0'; } /** * Creates the host part of the request. * @param SimpleUrl $url URL as object. * @return string Host line content. * @access protected */ function _getHostLine() { $host = 'Host: ' . $this->_proxy->getHost(); $port = $this->_proxy->getPort() ? $this->_proxy->getPort() : 8080; return "$host:$port"; } /** * Opens a socket to the route. * @param string $method HTTP request method, usually GET. * @param integer $timeout Connection timeout. * @return SimpleSocket New socket. * @access public */ function &createConnection($method, $timeout) { $socket = &$this->_createSocket( $this->_proxy->getScheme() ? $this->_proxy->getScheme() : 'http', $this->_proxy->getHost(), $this->_proxy->getPort() ? $this->_proxy->getPort() : 8080, $timeout); if ($socket->isError()) { return $socket; } $socket->write($this->_getRequestLine($method) . "\r\n"); $socket->write($this->_getHostLine() . "\r\n"); if ($this->_username && $this->_password) { $socket->write('Proxy-Authorization: Basic ' . base64_encode($this->_username . ':' . $this->_password) . "\r\n"); } $socket->write("Connection: close\r\n"); return $socket; } } /** * HTTP request for a web page. Factory for * HttpResponse object. * @package SimpleTest * @subpackage WebTester */ class SimpleHttpRequest { var $_route; var $_encoding; var $_headers; var $_cookies; /** * Builds the socket request from the different pieces. * These include proxy information, URL, cookies, headers, * request method and choice of encoding. * @param SimpleRoute $route Request route. * @param SimpleFormEncoding $encoding Content to send with * request. * @access public */ function SimpleHttpRequest(&$route, $encoding) { $this->_route = &$route; $this->_encoding = $encoding; $this->_headers = array(); $this->_cookies = array(); } /** * Dispatches the content to the route's socket. * @param integer $timeout Connection timeout. * @return SimpleHttpResponse A response which may only have * an error, but hopefully has a * complete web page. * @access public */ function &fetch($timeout) { $socket = &$this->_route->createConnection($this->_encoding->getMethod(), $timeout); if (! $socket->isError()) { $this->_dispatchRequest($socket, $this->_encoding); } $response = &$this->_createResponse($socket); return $response; } /** * Sends the headers. * @param SimpleSocket $socket Open socket. * @param string $method HTTP request method, * usually GET. * @param SimpleFormEncoding $encoding Content to send with request. * @access private */ function _dispatchRequest(&$socket, $encoding) { foreach ($this->_headers as $header_line) { $socket->write($header_line . "\r\n"); } if (count($this->_cookies) > 0) { $socket->write("Cookie: " . implode(";", $this->_cookies) . "\r\n"); } $encoding->writeHeadersTo($socket); $socket->write("\r\n"); $encoding->writeTo($socket); } /** * Adds a header line to the request. * @param string $header_line Text of full header line. * @access public */ function addHeaderLine($header_line) { $this->_headers[] = $header_line; } /** * Reads all the relevant cookies from the * cookie jar. * @param SimpleCookieJar $jar Jar to read * @param SimpleUrl $url Url to use for scope. * @access public */ function readCookiesFromJar($jar, $url) { $this->_cookies = $jar->selectAsPairs($url); } /** * Wraps the socket in a response parser. * @param SimpleSocket $socket Responding socket. * @return SimpleHttpResponse Parsed response object. * @access protected */ function &_createResponse(&$socket) { $response = &new SimpleHttpResponse( $socket, $this->_route->getUrl(), $this->_encoding); return $response; } } /** * Collection of header lines in the response. * @package SimpleTest * @subpackage WebTester */ class SimpleHttpHeaders { var $_raw_headers; var $_response_code; var $_http_version; var $_mime_type; var $_location; var $_cookies; var $_authentication; var $_realm; /** * Parses the incoming header block. * @param string $headers Header block. * @access public */ function SimpleHttpHeaders($headers) { $this->_raw_headers = $headers; $this->_response_code = false; $this->_http_version = false; $this->_mime_type = ''; $this->_location = false; $this->_cookies = array(); $this->_authentication = false; $this->_realm = false; foreach (split("\r\n", $headers) as $header_line) { $this->_parseHeaderLine($header_line); } } /** * Accessor for parsed HTTP protocol version. * @return integer HTTP error code. * @access public */ function getHttpVersion() { return $this->_http_version; } /** * Accessor for raw header block. * @return string All headers as raw string. * @access public */ function getRaw() { return $this->_raw_headers; } /** * Accessor for parsed HTTP error code. * @return integer HTTP error code. * @access public */ function getResponseCode() { return (integer)$this->_response_code; } /** * Returns the redirected URL or false if * no redirection. * @return string URL or false for none. * @access public */ function getLocation() { return $this->_location; } /** * Test to see if the response is a valid redirect. * @return boolean True if valid redirect. * @access public */ function isRedirect() { return in_array($this->_response_code, array(301, 302, 303, 307)) && (boolean)$this->getLocation(); } /** * Test to see if the response is an authentication * challenge. * @return boolean True if challenge. * @access public */ function isChallenge() { return ($this->_response_code == 401) && (boolean)$this->_authentication && (boolean)$this->_realm; } /** * Accessor for MIME type header information. * @return string MIME type. * @access public */ function getMimeType() { return $this->_mime_type; } /** * Accessor for authentication type. * @return string Type. * @access public */ function getAuthentication() { return $this->_authentication; } /** * Accessor for security realm. * @return string Realm. * @access public */ function getRealm() { return $this->_realm; } /** * Writes new cookies to the cookie jar. * @param SimpleCookieJar $jar Jar to write to. * @param SimpleUrl $url Host and path to write under. * @access public */ function writeCookiesToJar(&$jar, $url) { foreach ($this->_cookies as $cookie) { $jar->setCookie( $cookie->getName(), $cookie->getValue(), $url->getHost(), $cookie->getPath(), $cookie->getExpiry()); } } /** * Called on each header line to accumulate the held * data within the class. * @param string $header_line One line of header. * @access protected */ function _parseHeaderLine($header_line) { if (preg_match('/HTTP\/(\d+\.\d+)\s+(\d+)/i', $header_line, $matches)) { $this->_http_version = $matches[1]; $this->_response_code = $matches[2]; } if (preg_match('/Content-type:\s*(.*)/i', $header_line, $matches)) { $this->_mime_type = trim($matches[1]); } if (preg_match('/Location:\s*(.*)/i', $header_line, $matches)) { $this->_location = trim($matches[1]); } if (preg_match('/Set-cookie:(.*)/i', $header_line, $matches)) { $this->_cookies[] = $this->_parseCookie($matches[1]); } if (preg_match('/WWW-Authenticate:\s+(\S+)\s+realm=\"(.*?)\"/i', $header_line, $matches)) { $this->_authentication = $matches[1]; $this->_realm = trim($matches[2]); } } /** * Parse the Set-cookie content. * @param string $cookie_line Text after "Set-cookie:" * @return SimpleCookie New cookie object. * @access private */ function _parseCookie($cookie_line) { $parts = split(";", $cookie_line); $cookie = array(); preg_match('/\s*(.*?)\s*=(.*)/', array_shift($parts), $cookie); foreach ($parts as $part) { if (preg_match('/\s*(.*?)\s*=(.*)/', $part, $matches)) { $cookie[$matches[1]] = trim($matches[2]); } } return new SimpleCookie( $cookie[1], trim($cookie[2]), isset($cookie["path"]) ? $cookie["path"] : "", isset($cookie["expires"]) ? $cookie["expires"] : false); } } /** * Basic HTTP response. * @package SimpleTest * @subpackage WebTester */ class SimpleHttpResponse extends SimpleStickyError { var $_url; var $_encoding; var $_sent; var $_content; var $_headers; /** * Constructor. Reads and parses the incoming * content and headers. * @param SimpleSocket $socket Network connection to fetch * response text from. * @param SimpleUrl $url Resource name. * @param mixed $encoding Record of content sent. * @access public */ function SimpleHttpResponse(&$socket, $url, $encoding) { $this->SimpleStickyError(); $this->_url = $url; $this->_encoding = $encoding; $this->_sent = $socket->getSent(); $this->_content = false; $raw = $this->_readAll($socket); if ($socket->isError()) { $this->_setError('Error reading socket [' . $socket->getError() . ']'); return; } $this->_parse($raw); } /** * Splits up the headers and the rest of the content. * @param string $raw Content to parse. * @access private */ function _parse($raw) { if (! $raw) { $this->_setError('Nothing fetched'); $this->_headers = &new SimpleHttpHeaders(''); } elseif (! strstr($raw, "\r\n\r\n")) { $this->_setError('Could not split headers from content'); $this->_headers = &new SimpleHttpHeaders($raw); } else { list($headers, $this->_content) = split("\r\n\r\n", $raw, 2); $this->_headers = &new SimpleHttpHeaders($headers); } } /** * Original request method. * @return string GET, POST or HEAD. * @access public */ function getMethod() { return $this->_encoding->getMethod(); } /** * Resource name. * @return SimpleUrl Current url. * @access public */ function getUrl() { return $this->_url; } /** * Original request data. * @return mixed Sent content. * @access public */ function getRequestData() { return $this->_encoding; } /** * Raw request that was sent down the wire. * @return string Bytes actually sent. * @access public */ function getSent() { return $this->_sent; } /** * Accessor for the content after the last * header line. * @return string All content. * @access public */ function getContent() { return $this->_content; } /** * Accessor for header block. The response is the * combination of this and the content. * @return SimpleHeaders Wrapped header block. * @access public */ function getHeaders() { return $this->_headers; } /** * Accessor for any new cookies. * @return array List of new cookies. * @access public */ function getNewCookies() { return $this->_headers->getNewCookies(); } /** * Reads the whole of the socket output into a * single string. * @param SimpleSocket $socket Unread socket. * @return string Raw output if successful * else false. * @access private */ function _readAll(&$socket) { $all = ''; while (! $this->_isLastPacket($next = $socket->read())) { $all .= $next; } return $all; } /** * Test to see if the packet from the socket is the * last one. * @param string $packet Chunk to interpret. * @return boolean True if empty or EOF. * @access private */ function _isLastPacket($packet) { if (is_string($packet)) { return $packet === ''; } return ! $packet; } } ?>postfixadmin-2.3.7/tests/simpletest/extensions/0000775000175000017620000000000012301477470022016 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/extensions/phpunit_test_case.php0000664000175000017620000000612411157271050026245 0ustar davidpalepurpleSimpleTestCase($label); } /** * Sends pass if the test condition resolves true, * a fail otherwise. * @param $condition Condition to test true. * @param $message Message to display. * @public */ function assert($condition, $message = false) { parent::assert(new TrueExpectation(), $condition, $message); } /** * Will test straight equality if set to loose * typing, or identity if not. * @param $first First value. * @param $second Comparison value. * @param $message Message to display. * @public */ function assertEquals($first, $second, $message = false) { parent::assert(new EqualExpectation($first), $second, $message); } /** * Simple string equality. * @param $first First value. * @param $second Comparison value. * @param $message Message to display. * @public */ function assertEqualsMultilineStrings($first, $second, $message = false) { parent::assert(new EqualExpectation($first), $second, $message); } /** * Tests a regex match. * @param $pattern Regex to match. * @param $subject String to search in. * @param $message Message to display. * @public */ function assertRegexp($pattern, $subject, $message = false) { parent::assert(new PatternExpectation($pattern), $subject, $message); } /** * Sends an error which we interpret as a fail * with a different message for compatibility. * @param $message Message to display. * @public */ function error($message) { parent::fail("Error triggered [$message]"); } /** * Accessor for name. * @public */ function name() { return $this->getLabel(); } } ?> postfixadmin-2.3.7/tests/simpletest/extensions/pear_test_case.php0000664000175000017620000001564211157271050025512 0ustar davidpalepurpleSimpleTestCase($label); $this->_loosely_typed = false; } /** * Will test straight equality if set to loose * typing, or identity if not. * @param $first First value. * @param $second Comparison value. * @param $message Message to display. * @public */ function assertEquals($first, $second, $message = "%s", $delta = 0) { if ($this->_loosely_typed) { $expectation = &new EqualExpectation($first); } else { $expectation = &new IdenticalExpectation($first); } $this->assert($expectation, $second, $message); } /** * Passes if the value tested is not null. * @param $value Value to test against. * @param $message Message to display. * @public */ function assertNotNull($value, $message = "%s") { parent::assert(new TrueExpectation(), isset($value), $message); } /** * Passes if the value tested is null. * @param $value Value to test against. * @param $message Message to display. * @public */ function assertNull($value, $message = "%s") { parent::assert(new TrueExpectation(), !isset($value), $message); } /** * In PHP5 the identity test tests for the same * object. This is a reference test in PHP4. * @param $first First object handle. * @param $second Hopefully the same handle. * @param $message Message to display. * @public */ function assertSame(&$first, &$second, $message = "%s") { $dumper = &new SimpleDumper(); $message = sprintf( $message, "[" . $dumper->describeValue($first) . "] and [" . $dumper->describeValue($second) . "] should reference the same object"); return $this->assert( new TrueExpectation(), SimpleTestCompatibility::isReference($first, $second), $message); } /** * In PHP5 the identity test tests for the same * object. This is a reference test in PHP4. * @param $first First object handle. * @param $second Hopefully a different handle. * @param $message Message to display. * @public */ function assertNotSame(&$first, &$second, $message = "%s") { $dumper = &new SimpleDumper(); $message = sprintf( $message, "[" . $dumper->describeValue($first) . "] and [" . $dumper->describeValue($second) . "] should not be the same object"); return $this->assert( new falseExpectation(), SimpleTestCompatibility::isReference($first, $second), $message); } /** * Sends pass if the test condition resolves true, * a fail otherwise. * @param $condition Condition to test true. * @param $message Message to display. * @public */ function assertTrue($condition, $message = "%s") { parent::assert(new TrueExpectation(), $condition, $message); } /** * Sends pass if the test condition resolves false, * a fail otherwise. * @param $condition Condition to test false. * @param $message Message to display. * @public */ function assertFalse($condition, $message = "%s") { parent::assert(new FalseExpectation(), $condition, $message); } /** * Tests a regex match. Needs refactoring. * @param $pattern Regex to match. * @param $subject String to search in. * @param $message Message to display. * @public */ function assertRegExp($pattern, $subject, $message = "%s") { $this->assert(new PatternExpectation($pattern), $subject, $message); } /** * Tests the type of a value. * @param $value Value to take type of. * @param $type Hoped for type. * @param $message Message to display. * @public */ function assertType($value, $type, $message = "%s") { parent::assert(new TrueExpectation(), gettype($value) == strtolower($type), $message); } /** * Sets equality operation to act as a simple equal * comparison only, allowing a broader range of * matches. * @param $loosely_typed True for broader comparison. * @public */ function setLooselyTyped($loosely_typed) { $this->_loosely_typed = $loosely_typed; } /** * For progress indication during * a test amongst other things. * @return Usually one. * @public */ function countTestCases() { return $this->getSize(); } /** * Accessor for name, normally just the class * name. * @public */ function getName() { return $this->getLabel(); } /** * Does nothing. For compatibility only. * @param $name Dummy * @public */ function setName($name) { } } ?> postfixadmin-2.3.7/tests/simpletest/cookies.php0000664000175000017620000003200211157271050021753 0ustar davidpalepurple_host = false; $this->_name = $name; $this->_value = $value; $this->_path = ($path ? $this->_fixPath($path) : "/"); $this->_expiry = false; if (is_string($expiry)) { $this->_expiry = strtotime($expiry); } elseif (is_integer($expiry)) { $this->_expiry = $expiry; } $this->_is_secure = $is_secure; } /** * Sets the host. The cookie rules determine * that the first two parts are taken for * certain TLDs and three for others. If the * new host does not match these rules then the * call will fail. * @param string $host New hostname. * @return boolean True if hostname is valid. * @access public */ function setHost($host) { if ($host = $this->_truncateHost($host)) { $this->_host = $host; return true; } return false; } /** * Accessor for the truncated host to which this * cookie applies. * @return string Truncated hostname. * @access public */ function getHost() { return $this->_host; } /** * Test for a cookie being valid for a host name. * @param string $host Host to test against. * @return boolean True if the cookie would be valid * here. */ function isValidHost($host) { return ($this->_truncateHost($host) === $this->getHost()); } /** * Extracts just the domain part that determines a * cookie's host validity. * @param string $host Host name to truncate. * @return string Domain or false on a bad host. * @access private */ function _truncateHost($host) { $tlds = SimpleUrl::getAllTopLevelDomains(); if (preg_match('/[a-z\-]+\.(' . $tlds . ')$/i', $host, $matches)) { return $matches[0]; } elseif (preg_match('/[a-z\-]+\.[a-z\-]+\.[a-z\-]+$/i', $host, $matches)) { return $matches[0]; } return false; } /** * Accessor for name. * @return string Cookie key. * @access public */ function getName() { return $this->_name; } /** * Accessor for value. A deleted cookie will * have an empty string for this. * @return string Cookie value. * @access public */ function getValue() { return $this->_value; } /** * Accessor for path. * @return string Valid cookie path. * @access public */ function getPath() { return $this->_path; } /** * Tests a path to see if the cookie applies * there. The test path must be longer or * equal to the cookie path. * @param string $path Path to test against. * @return boolean True if cookie valid here. * @access public */ function isValidPath($path) { return (strncmp( $this->_fixPath($path), $this->getPath(), strlen($this->getPath())) == 0); } /** * Accessor for expiry. * @return string Expiry string. * @access public */ function getExpiry() { if (! $this->_expiry) { return false; } return gmdate("D, d M Y H:i:s", $this->_expiry) . " GMT"; } /** * Test to see if cookie is expired against * the cookie format time or timestamp. * Will give true for a session cookie. * @param integer/string $now Time to test against. Result * will be false if this time * is later than the cookie expiry. * Can be either a timestamp integer * or a cookie format date. * @access public */ function isExpired($now) { if (! $this->_expiry) { return true; } if (is_string($now)) { $now = strtotime($now); } return ($this->_expiry < $now); } /** * Ages the cookie by the specified number of * seconds. * @param integer $interval In seconds. * @public */ function agePrematurely($interval) { if ($this->_expiry) { $this->_expiry -= $interval; } } /** * Accessor for the secure flag. * @return boolean True if cookie needs SSL. * @access public */ function isSecure() { return $this->_is_secure; } /** * Adds a trailing and leading slash to the path * if missing. * @param string $path Path to fix. * @access private */ function _fixPath($path) { if (substr($path, 0, 1) != '/') { $path = '/' . $path; } if (substr($path, -1, 1) != '/') { $path .= '/'; } return $path; } } /** * Repository for cookies. This stuff is a * tiny bit browser dependent. * @package SimpleTest * @subpackage WebTester */ class SimpleCookieJar { var $_cookies; /** * Constructor. Jar starts empty. * @access public */ function SimpleCookieJar() { $this->_cookies = array(); } /** * Removes expired and temporary cookies as if * the browser was closed and re-opened. * @param string/integer $now Time to test expiry against. * @access public */ function restartSession($date = false) { $surviving_cookies = array(); for ($i = 0; $i < count($this->_cookies); $i++) { if (! $this->_cookies[$i]->getValue()) { continue; } if (! $this->_cookies[$i]->getExpiry()) { continue; } if ($date && $this->_cookies[$i]->isExpired($date)) { continue; } $surviving_cookies[] = $this->_cookies[$i]; } $this->_cookies = $surviving_cookies; } /** * Ages all cookies in the cookie jar. * @param integer $interval The old session is moved * into the past by this number * of seconds. Cookies now over * age will be removed. * @access public */ function agePrematurely($interval) { for ($i = 0; $i < count($this->_cookies); $i++) { $this->_cookies[$i]->agePrematurely($interval); } } /** * Sets an additional cookie. If a cookie has * the same name and path it is replaced. * @param string $name Cookie key. * @param string $value Value of cookie. * @param string $host Host upon which the cookie is valid. * @param string $path Cookie path if not host wide. * @param string $expiry Expiry date. * @access public */ function setCookie($name, $value, $host = false, $path = '/', $expiry = false) { $cookie = new SimpleCookie($name, $value, $path, $expiry); if ($host) { $cookie->setHost($host); } $this->_cookies[$this->_findFirstMatch($cookie)] = $cookie; } /** * Finds a matching cookie to write over or the * first empty slot if none. * @param SimpleCookie $cookie Cookie to write into jar. * @return integer Available slot. * @access private */ function _findFirstMatch($cookie) { for ($i = 0; $i < count($this->_cookies); $i++) { $is_match = $this->_isMatch( $cookie, $this->_cookies[$i]->getHost(), $this->_cookies[$i]->getPath(), $this->_cookies[$i]->getName()); if ($is_match) { return $i; } } return count($this->_cookies); } /** * Reads the most specific cookie value from the * browser cookies. Looks for the longest path that * matches. * @param string $host Host to search. * @param string $path Applicable path. * @param string $name Name of cookie to read. * @return string False if not present, else the * value as a string. * @access public */ function getCookieValue($host, $path, $name) { $longest_path = ''; foreach ($this->_cookies as $cookie) { if ($this->_isMatch($cookie, $host, $path, $name)) { if (strlen($cookie->getPath()) > strlen($longest_path)) { $value = $cookie->getValue(); $longest_path = $cookie->getPath(); } } } return (isset($value) ? $value : false); } /** * Tests cookie for matching against search * criteria. * @param SimpleTest $cookie Cookie to test. * @param string $host Host must match. * @param string $path Cookie path must be shorter than * this path. * @param string $name Name must match. * @return boolean True if matched. * @access private */ function _isMatch($cookie, $host, $path, $name) { if ($cookie->getName() != $name) { return false; } if ($host && $cookie->getHost() && ! $cookie->isValidHost($host)) { return false; } if (! $cookie->isValidPath($path)) { return false; } return true; } /** * Uses a URL to sift relevant cookies by host and * path. Results are list of strings of form "name=value". * @param SimpleUrl $url Url to select by. * @return array Valid name and value pairs. * @access public */ function selectAsPairs($url) { $pairs = array(); foreach ($this->_cookies as $cookie) { if ($this->_isMatch($cookie, $url->getHost(), $url->getPath(), $cookie->getName())) { $pairs[] = $cookie->getName() . '=' . $cookie->getValue(); } } return $pairs; } } ?>postfixadmin-2.3.7/tests/simpletest/docs/0000775000175000017620000000000012301477470020547 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/docs/en/0000775000175000017620000000000012301477470021151 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/docs/en/authentication_documentation.html0000664000175000017620000002753011157271050030010 0ustar davidpalepurple SimpleTest documentation for testing log-in and authentication

    Authentication documentation

    One of the trickiest, and yet most important, areas of testing web sites is the security. Testing these schemes is one of the core goals of the SimpleTest web tester.

    Basic HTTP authentication

    If you fetch a page protected by basic authentication then rather than receiving content, you will instead get a 401 header. We can illustrate this with this test...

    class AuthenticationTest extends WebTestCase {
        function test401Header() {
            $this->get('http://www.lastcraft.com/protected/');
            $this->showHeaders();
        }
    }
    
    This allows us to see the challenge header...

    File test

    HTTP/1.1 401 Authorization Required
    Date: Sat, 18 Sep 2004 19:25:18 GMT
    Server: Apache/1.3.29 (Unix) PHP/4.3.4
    WWW-Authenticate: Basic realm="SimpleTest basic authentication"
    Connection: close
    Content-Type: text/html; charset=iso-8859-1
    
    1/1 test cases complete. 0 passes, 0 fails and 0 exceptions.
    We are trying to get away from visual inspection though, and so SimpleTest allows to make automated assertions against the challenge. Here is a thorough test of our header...
    class AuthenticationTest extends WebTestCase {
        function test401Header() {
            $this->get('http://www.lastcraft.com/protected/');
            $this->assertAuthentication('Basic');
            $this->assertResponse(401);
            $this->assertRealm('SimpleTest basic authentication');
        }
    }
    
    Any one of these tests would normally do on it's own depending on the amount of detail you want to see.

    One theme that runs through SimpleTest is the ability to use SimpleExpectation objects wherever a simple match is not enough. If you want only an approximate match to the realm for example, you can do this...

    class AuthenticationTest extends WebTestCase {
        function test401Header() {
            $this->get('http://www.lastcraft.com/protected/');
            $this->assertRealm(new PatternExpectation('/simpletest/i'));
        }
    }
    
    Most of the time we are not interested in testing the authentication itself, but want to get past it to test the pages underneath. As soon as the challenge has been issued we can reply with an authentication response...
    class AuthenticationTest extends WebTestCase {
        function testCanAuthenticate() {
            $this->get('http://www.lastcraft.com/protected/');
            $this->authenticate('Me', 'Secret');
            $this->assertTitle(...);
        }
    }
    
    The username and password will now be sent with every subsequent request to that directory and subdirectories. You will have to authenticate again if you step outside the authenticated directory, but SimpleTest is smart enough to merge subdirectories into a common realm.

    You can shortcut this step further by encoding the log in details straight into the URL...

    class AuthenticationTest extends WebTestCase {
        function testCanReadAuthenticatedPages() {
            $this->get('http://Me:Secret@www.lastcraft.com/protected/');
            $this->assertTitle(...);
        }
    }
    
    If your username or password has special characters, then you will have to URL encode them or the request will not be parsed correctly. Also this header will not be sent on subsequent requests if you request a page with a fully qualified URL. If you navigate with relative URLs though, the authentication information will be preserved.

    Only basic authentication is currently supported and this is only really secure in tandem with HTTPS connections. This is usually enough to protect test server from prying eyes, however. Digest authentication and NTLM authentication may be added in the future.

    Cookies

    Basic authentication doesn't give enough control over the user interface for web developers. More likely this functionality will be coded directly into the web architecture using cookies and complicated timeouts.

    Starting with a simple log-in form...

    <form>
        Username:
        <input type="text" name="u" value="" /><br />
        Password:
        <input type="password" name="p" value="" /><br />
        <input type="submit" value="Log in" />
    </form>
    
    Which looks like...

    Username:
    Password:

    Let's suppose that in fetching this page a cookie has been set with a session ID. We are not going to fill the form in yet, just test that we are tracking the user. Here is the test...

    class LogInTest extends WebTestCase {
        function testSessionCookieSetBeforeForm() {
            $this->get('http://www.my-site.com/login.php');
            $this->assertCookie('SID');
        }
    }
    
    All we are doing is confirming that the cookie is set. As the value is likely to be rather cryptic it's not really worth testing this with...
    class LogInTest extends WebTestCase {
        function testSessionCookieIsCorrectPattern() {
            $this->get('http://www.my-site.com/login.php');
            $this->assertCookie('SID', new PatternExpectation('/[a-f0-9]{32}/i'));
        }
    }
    
    The rest of the test would be the same as any other form, but we might want to confirm that we still have the same cookie after log-in as before we entered. We wouldn't want to lose track of this after all. Here is a possible test for this...
    class LogInTest extends WebTestCase {
        ...
        function testSessionCookieSameAfterLogIn() {
            $this->get('http://www.my-site.com/login.php');
            $session = $this->getCookie('SID');
            $this->setField('u', 'Me');
            $this->setField('p', 'Secret');
            $this->click('Log in');
            $this->assertText('Welcome Me');
            $this->assertCookie('SID', $session);
        }
    }
    
    This confirms that the session identifier is maintained afer log-in.

    We could even attempt to spoof our own system by setting arbitrary cookies to gain access...

    class LogInTest extends WebTestCase {
        ...
        function testSessionCookieSameAfterLogIn() {
            $this->get('http://www.my-site.com/login.php');
            $this->setCookie('SID', 'Some other session');
            $this->get('http://www.my-site.com/restricted.php');
            $this->assertText('Access denied');
        }
    }
    
    Is your site protected from this attack?

    Browser sessions

    If you are testing an authentication system a critical piece of behaviour is what happens when a user logs back in. We would like to simulate closing and reopening a browser...

    class LogInTest extends WebTestCase {
        ...
        function testLoseAuthenticationAfterBrowserClose() {
            $this->get('http://www.my-site.com/login.php');
            $this->setField('u', 'Me');
            $this->setField('p', 'Secret');
            $this->click('Log in');
            $this->assertText('Welcome Me');
            
            $this->restart();
            $this->get('http://www.my-site.com/restricted.php');
            $this->assertText('Access denied');
        }
    }
    
    The WebTestCase::restart() method will preserve cookies that have unexpired timeouts, but throw away those that are temporary or expired. You can optionally specify the time and date that the restart happened.

    Expiring cookies can be a problem. After all, if you have a cookie that expires after an hour, you don't want to stall the test for an hour while the cookie passes it's timeout.

    To push the cookies over the hour limit you can age them before you restart the session...

    class LogInTest extends WebTestCase {
        ...
        function testLoseAuthenticationAfterOneHour() {
            $this->get('http://www.my-site.com/login.php');
            $this->setField('u', 'Me');
            $this->setField('p', 'Secret');
            $this->click('Log in');
            $this->assertText('Welcome Me');
            
            $this->ageCookies(3600);
            $this->restart();
            $this->get('http://www.my-site.com/restricted.php');
            $this->assertText('Access denied');
        }
    }
    
    After the restart it will appear that cookies are an hour older and any that pass their expiry will have disappeared.

    postfixadmin-2.3.7/tests/simpletest/docs/en/web_tester_documentation.html0000664000175000017620000004756311157271050027144 0ustar davidpalepurple Simple Test for PHP web script testing documentation

    Web tester documentation

    Fetching a page

    Testing classes is all very well, but PHP is predominately a language for creating functionality within web pages. How do we test the front end presentation role of our PHP applications? Well the web pages are just text, so we should be able to examine them just like any other test data.

    This leads to a tricky issue. If we test at too low a level, testing for matching tags in the page with pattern matching for example, our tests will be brittle. The slightest change in layout could break a large number of tests. If we test at too high a level, say using mock versions of a template engine, then we lose the ability to automate some classes of test. For example, the interaction of forms and navigation will have to be tested manually. These types of test are extremely repetitive and error prone.

    SimpleTest includes a special form of test case for the testing of web page actions. The WebTestCase includes facilities for navigation, content and cookie checks and form handling. Usage of these test cases is similar to the UnitTestCase...

    class TestOfLastcraft extends WebTestCase {
    }
    
    Here we are about to test the Last Craft site itself. If this test case is in a file called lastcraft_test.php then it can be loaded in a runner script just like unit tests...
    <?php
        require_once('simpletest/web_tester.php');
        require_once('simpletest/reporter.php');
        
        $test = &new GroupTest('Web site tests');
        $test->addTestFile('lastcraft_test.php');
        exit ($test->run(new TextReporter()) ? 0 : 1);
    ?>
    
    I am using the text reporter here to more clearly distinguish the web content from the test output.

    Nothing is being tested yet. We can fetch the home page by using the get() method...

    class TestOfLastcraft extends WebTestCase {
        
        function testHomepage() {
            $this->assertTrue($this->get('http://www.lastcraft.com/'));
        }
    }
    
    The get() method will return true only if page content was successfully loaded. It is a simple, but crude way to check that a web page was actually delivered by the web server. However that content may be a 404 response and yet our get() method will still return true.

    Assuming that the web server for the Last Craft site is up (sadly not always the case), we should see...

    Web site tests
    OK
    Test cases run: 1/1, Failures: 0, Exceptions: 0
    
    All we have really checked is that any kind of page was returned. We don't yet know if it was the right one.

    Testing page content

    To confirm that the page we think we are on is actually the page we are on, we need to verify the page content.

    class TestOfLastcraft extends WebTestCase {
        
        function testHomepage() {
            $this->get('http://www.lastcraft.com/');
            $this->assertTest('Why the last craft');
        }
    }
    
    The page from the last fetch is held in a buffer in the test case, so there is no need to refer to it directly. The pattern match is always made against the buffer.

    Here is the list of possible content assertions...
    assertTitle($title)Pass if title is an exact match
    assertPattern($pattern)A Perl pattern match against the page content
    assertNoPattern($pattern)A Perl pattern match to not find content
    assertText($text)Pass if matches visible and "alt" text
    assertNoText($text)Pass if doesn't match visible and "alt" text
    assertLink($label)Pass if a link with this text is present
    assertNoLink($label)Pass if no link with this text is present
    assertLinkById($id)Pass if a link with this id attribute is present
    assertNoLinkById($id)Pass if no link with this id attribute is present
    assertField($name, $value)Pass if an input tag with this name has this value
    assertFieldById($id, $value)Pass if an input tag with this id has this value
    assertResponse($codes)Pass if HTTP response matches this list
    assertMime($types)Pass if MIME type is in this list
    assertAuthentication($protocol)Pass if the current challenge is this protocol
    assertNoAuthentication()Pass if there is no current challenge
    assertRealm($name)Pass if the current challenge realm matches
    assertHeader($header, $content)Pass if a header was fetched matching this value
    assertNoHeader($header)Pass if a header was not fetched
    assertCookie($name, $value)Pass if there is currently a matching cookie
    assertNoCookie($name)Pass if there is currently no cookie of this name
    As usual with the SimpleTest assertions, they all return false on failure and true on pass. They also allow an optional test message and you can embed the original test message inside using "%s" inside your custom message.

    So now we could instead test against the title tag with...

    $this->assertTitle('The Last Craft? Web developer tutorials on PHP, Extreme programming and Object Oriented development');
    
    ...or, if that is too long and fragile...
    $this->assertTitle(new PatternExpectation('/The Last Craft/'));
    
    As well as the simple HTML content checks we can check that the MIME type is in a list of allowed types with...
    $this->assertMime(array('text/plain', 'text/html'));
    
    More interesting is checking the HTTP response code. Like the MIME type, we can assert that the response code is in a list of allowed values...
    class TestOfLastcraft extends WebTestCase {
        
        function testRedirects() {
            $this->get('http://www.lastcraft.com/test/redirect.php');
            $this->assertResponse(200);</strong>
        }
    }
    
    Here we are checking that the fetch is successful by allowing only a 200 HTTP response. This test will pass, but it is not actually correct to do so. There is no page, instead the server issues a redirect. The WebTestCase will automatically follow up to three such redirects. The tests are more robust this way and we are usually interested in the interaction with the pages rather than their delivery. If the redirects are of interest then this ability must be disabled...
    class TestOfLastcraft extends WebTestCase {
        
        function testHomepage() {
            $this->setMaximumRedirects(0);
            $this->get('http://www.lastcraft.com/test/redirect.php');
            $this->assertResponse(200);
        }
    }
    
    The assertion now fails as expected...
    Web site tests
    1) Expecting response in [200] got [302]
    	in testhomepage
    	in testoflastcraft
    	in lastcraft_test.php
    FAILURES!!!
    Test cases run: 1/1, Failures: 1, Exceptions: 0
    
    We can modify the test to correctly assert redirects with...
    class TestOfLastcraft extends WebTestCase {
        
        function testHomepage() {
            $this->setMaximumRedirects(0);
            $this->get('http://www.lastcraft.com/test/redirect.php');
            $this->assertResponse(array(301, 302, 303, 307));
        }
    }
    
    This now passes.

    Navigating a web site

    Users don't often navigate sites by typing in URLs, but by clicking links and buttons. Here we confirm that the contact details can be reached from the home page...

    class TestOfLastcraft extends WebTestCase {
        ...
        function testContact() {
            $this->get('http://www.lastcraft.com/');
            $this->clickLink('About');
            $this->assertTitle(new PatternExpectation('/About Last Craft/'));
        }
    }
    
    The parameter is the text of the link.

    If the target is a button rather than an anchor tag, then clickSubmit() can be used with the button title...

    $this->clickSubmit('Go!');
    
    If you are not sure or don't care, the usual case, then just use the click() method...
    $this->click('Go!');
    

    The list of navigation methods is...
    getUrl()The current location
    get($url, $parameters)Send a GET request with these parameters
    post($url, $parameters)Send a POST request with these parameters
    head($url, $parameters)Send a HEAD request without replacing the page content
    retry()Reload the last request
    back()Like the browser back button
    forward()Like the browser forward button
    authenticate($name, $password)Retry after a challenge
    restart()Restarts the browser as if a new session
    getCookie($name)Gets the cookie value for the current context
    ageCookies($interval)Ages current cookies prior to a restart
    clearFrameFocus()Go back to treating all frames as one page
    clickSubmit($label)Click the first button with this label
    clickSubmitByName($name)Click the button with this name attribute
    clickSubmitById($id)Click the button with this ID attribute
    clickImage($label, $x, $y)Click an input tag of type image by title or alt text
    clickImageByName($name, $x, $y)Click an input tag of type image by name
    clickImageById($id, $x, $y)Click an input tag of type image by ID attribute
    submitFormById($id)Submit a form without the submit value
    clickLink($label, $index)Click an anchor by the visible label text
    clickLinkById($id)Click an anchor by the ID attribute
    getFrameFocus()The name of the currently selected frame
    setFrameFocusByIndex($choice)Focus on a frame counting from 1
    setFrameFocus($name)Focus on a frame by name

    The parameters in the get(), post() or head() methods are optional. The HTTP HEAD fetch does not change the browser context, only loads cookies. This can be useful for when an image or stylesheet sets a cookie for crafty robot blocking.

    The retry(), back() and forward() commands work as they would on your web browser. They use the history to retry pages. This can be handy for checking the effect of hitting the back button on your forms.

    The frame methods need a little explanation. By default a framed page is treated just like any other. Content will be searced for throughout the entire frameset, so clicking a link will work no matter which frame the anchor tag is in. You can override this behaviour by focusing on a single frame. If you do that, all searches and actions will apply to that frame alone, such as authentication and retries. If a link or button is not in a focused frame then it cannot be clicked.

    Testing navigation on fixed pages only tells you when you have broken an entire script. For highly dynamic pages, such as for bulletin boards, this can be crucial for verifying the correctness of the application. For most applications though, the really tricky logic is usually in the handling of forms and sessions. Fortunately SimpleTest includes tools for testing web forms as well.

    Modifying the request

    Although SimpleTest does not have the goal of testing networking problems, it does include some methods to modify and debug the requests it makes. Here is another method list...
    getTransportError()The last socket error
    showRequest()Dump the outgoing request
    showHeaders()Dump the incoming headers
    showSource()Dump the raw HTML page content
    ignoreFrames()Do not load framesets
    setCookie($name, $value)Set a cookie from now on
    addHeader($header)Always add this header to the request
    setMaximumRedirects($max)Stop after this many redirects
    setConnectionTimeout($timeout)Kill the connection after this time between bytes
    useProxy($proxy, $name, $password)Make requests via this proxy URL
    These methods are principally for debugging.

    postfixadmin-2.3.7/tests/simpletest/docs/en/unit_test_documentation.html0000664000175000017620000003457611157271050027017 0ustar davidpalepurple SimpleTest for PHP regression test documentation

    PHP Unit Test documentation

    Unit test cases

    The core system is a regression testing framework built around test cases. A sample test case looks like this...

    class FileTestCase extends UnitTestCase {
    }
    
    If no test name is supplied when chaining the constructor then the class name will be taken instead. This will be the name displayed in the test results.

    Actual tests are added as methods in the test case whose names by default start with the string "test" and when the test case is invoked all such methods are run in the order that PHP introspection finds them. As many test methods can be added as needed. For example...

    require_once('../classes/writer.php');
    
    class FileTestCase extends UnitTestCase {
        function FileTestCase() {
            $this->UnitTestCase('File test');
        }
        
        function setUp() {
            @unlink('../temp/test.txt');
        }
        
        function tearDown() {
            @unlink('../temp/test.txt');
        }
        
        function testCreation() {
            $writer = &new FileWriter('../temp/test.txt');
            $writer->write('Hello');
            $this->assertTrue(file_exists('../temp/test.txt'), 'File created');
        }
    }
    
    The constructor is optional and usually omitted. Without a name, the class name is taken as the name of the test case.

    Our only test method at the moment is testCreation() where we check that a file has been created by our Writer object. We could have put the unlink() code into this method as well, but by placing it in setUp() and tearDown() we can use it with other test methods that we add.

    The setUp() method is run just before each and every test method. tearDown() is run just after each and every test method.

    You can place some test case set up into the constructor to be run once for all the methods in the test case, but you risk test inteference that way. This way is slightly slower, but it is safer. Note that if you come from a JUnit background this will not be the behaviour you are used to. JUnit surprisingly reinstantiates the test case for each test method to prevent such interference. SimpleTest requires the end user to use setUp(), but supplies additional hooks for library writers.

    The means of reporting test results (see below) are by a visiting display class that is notified by various assert...() methods. Here is the full list for the UnitTestCase class, the default for SimpleTest...
    assertTrue($x)Fail if $x is false
    assertFalse($x)Fail if $x is true
    assertNull($x)Fail if $x is set
    assertNotNull($x)Fail if $x not set
    assertIsA($x, $t)Fail if $x is not the class or type $t
    assertNotA($x, $t)Fail if $x is of the class or type $t
    assertEqual($x, $y)Fail if $x == $y is false
    assertNotEqual($x, $y)Fail if $x == $y is true
    assertWithinMargin($x, $y, $m)Fail if abs($x - $y) < $m is false
    assertOutsideMargin($x, $y, $m)Fail if abs($x - $y) < $m is true
    assertIdentical($x, $y)Fail if $x == $y is false or a type mismatch
    assertNotIdentical($x, $y)Fail if $x == $y is true and types match
    assertReference($x, $y)Fail unless $x and $y are the same variable
    assertCopy($x, $y)Fail if $x and $y are the same variable
    assertPattern($p, $x)Fail unless the regex $p matches $x
    assertNoPattern($p, $x)Fail if the regex $p matches $x
    assertNoErrors()Fail if any PHP error occoured
    assertError($x)Fail if no PHP error or incorrect message/expectation
    assertExpectation($e)Fail on failed expectation object
    All assertion methods can take an optional description to label the displayed result with. If omitted a default message is sent instead which is usually sufficient. This default message can still be embedded in your own message if you include "%s" within the string. All the assertions return true on a pass or false on failure.

    Some examples...

    $variable = null;
    $this->assertNull($variable, 'Should be cleared');
    
    ...will pass and normally show no message. If you have set up the tester to display passes as well then the message will be displayed as is.
    $this->assertIdentical(0, false, 'Zero is not false [%s]');
    
    This will fail as it performs a type check as well as a comparison between the two values. The "%s" part is replaced by the default error message that would have been shown if we had not supplied our own. This also allows us to nest test messages.
    $a = 1;
    $b = $a;
    $this->assertReference($a, $b);
    
    Will fail as the variable $a is a copy of $b.
    $this->assertPattern('/hello/i', 'Hello world');
    
    This will pass as using a case insensitive match the string hello is contained in Hello world.
    trigger_error('Disaster');
    trigger_error('Catastrophe');
    $this->assertError();
    $this->assertError('Catastrophe');
    $this->assertNoErrors();
    
    This one takes some explanation as in fact they all pass!

    PHP errors in SimpleTest are trapped and placed in a queue. Here the first error check catches the "Disaster" message without checking the text and passes. This removes the error from the queue. The next error check tests not only the existence of the error, but also the text which here matches so another pass. With the queue now empty the last test will pass as well. If any unchecked errors are left at the end of a test method then an exception will be reported in the test. Note that SimpleTest cannot catch compile time PHP errors.

    The test cases also have some convenience methods for debugging code or extending the suite...
    setUp()Runs this before each test method
    tearDown()Runs this after each test method
    pass()Sends a test pass
    fail()Sends a test failure
    error()Sends an exception event
    sendMessage()Sends a status message to those displays that support it
    signal($type, $payload)Sends a user defined message to the test reporter
    dump($var)Does a formatted print_r() for quick and dirty debugging
    swallowErrors()Clears the error queue

    Extending test cases

    Of course additional test methods can be added to create specific types of test case too so as to extend framework...

    require_once('simpletest/unit_tester.php');
    
    class FileTester extends UnitTestCase {
        function FileTester($name = false) {
            $this->UnitTestCase($name);
        }
        
        function assertFileExists($filename, $message = '%s') {
            $this->assertTrue(
                    file_exists($filename),
                    sprintf($message, 'File [$filename] existence check'));
        }
    }
    
    Here the SimpleTest library is held in a folder called simpletest that is local. Substitute your own path for this.

    This new case can be now be inherited just like a normal test case...

    class FileTestCase extends FileTester {
        
        function setUp() {
            @unlink('../temp/test.txt');
        }
        
        function tearDown() {
            @unlink('../temp/test.txt');
        }
        
        function testCreation() {
            $writer = &new FileWriter('../temp/test.txt');
            $writer->write('Hello');
            $this->assertFileExists('../temp/test.txt');
        }
    }
    

    If you want a test case that does not have all of the UnitTestCase assertions, only your own and assertTrue(), you need to extend the SimpleTestCase class instead. It is found in simple_test.php rather than unit_tester.php. See later if you want to incorporate other unit tester's test cases in your test suites.

    Running a single test case

    You won't often run single test cases except when bashing away at a module that is having difficulty and you don't want to upset the main test suite. Here is the scaffolding needed to run the a lone test case...

    <?php
        require_once('simpletest/unit_tester.php');
        require_once('simpletest/reporter.php');
        require_once('../classes/writer.php');
    
        class FileTestCase extends UnitTestCase {
            function FileTestCase() {
                $this->UnitTestCase('File test');
            }
        }
        
        $test = &new FileTestCase();
        $test->run(new HtmlReporter());
    ?>
    
    This script will run as is, but will output zero passes and zero failures until test methods are added.

    postfixadmin-2.3.7/tests/simpletest/docs/en/group_test_documentation.html0000664000175000017620000002772011157271050027165 0ustar davidpalepurple SimpleTest for PHP group test documentation

    Group Test documentation

    Grouping tests

    To run test cases as part of a group the test cases should really be placed in files without the runner code...

    <?php
        require_once('../classes/io.php');
    
        class FileTester extends UnitTestCase {
            ...
        }
    
        class SocketTester extends UnitTestCase {
            ...
        }
    ?>
    
    As many cases as needed can appear in a single file. They should include any code they need, such as the library being tested, but none of the simple test libraries.

    If you have extended any test cases, you can include them as well.

    <?php
        require_once('../classes/io.php');
    
        class MyFileTestCase extends UnitTestCase {
            ...
        }
        SimpleTest::ignore('MyFileTestCase');
    
        class FileTester extends MyFileTestCase {
            ...
        }
    
        class SocketTester extends UnitTestCase {
            ...
        }
    ?>
    
    The FileTester class does not contain any actual tests, but is a base class for other test cases. For this reason we use the SimpleTestOptions::ignore() directive to tell the upcoming group test to ignore it. This directive can appear anywhere in the file and works when a whole file of test cases is loaded (see below). We will call this sample file_test.php.

    Next we create a group test file, called say group_test.php. You will think of a better name I am sure. We will add the test file using a safe method...

    <?php
        require_once('simpletest/unit_tester.php');
        require_once('simpletest/reporter.php');
        require_once('file_test.php');
    
        $test = &new GroupTest('All file tests');
        $test->addTestCase(new FileTestCase());
        $test->run(new HtmlReporter());
    ?>
    
    This instantiates the test case before the test suite is run. This could get a little expensive with a large number of test cases, so another method is provided that will only instantiate the class when it is needed...
    <?php
        require_once('simpletest/unit_tester.php');
        require_once('simpletest/reporter.php');
        require_once('file_test.php');
    
        $test = &new GroupTest('All file tests');
        $test->addTestClass('FileTestCase');
        $test->run(new HtmlReporter());
    ?>
    
    The problem with this method is that for every test case that we add we will have to require_once() the test code file and manually instantiate each and every test case. We can save a lot of typing with...
    <?php
        require_once('simpletest/unit_tester.php');
        require_once('simpletest/reporter.php');
    
        $test = &new GroupTest('All file tests');
        $test->addTestFile('file_test.php');
        $test->run(new HtmlReporter());
    ?&gt;
    
    What happens here is that the GroupTest class has done the require_once() for us. It then checks to see if any new test case classes have been created by the new file and automatically adds them to the group test. Now all we have to do is add each new file.

    There are two things that could go wrong and which require care...

    1. The file could already have been parsed by PHP and so no new classes will have been added. You should make sure that the test cases are only included in this file and no others.
    2. New test case extension classes that get included will be placed in the group test and run also. You will need to add a SimpleTestOptions::ignore() directive for these classes or make sure that they are included before the GroupTest::addTestFile() line.

    Higher groupings

    The above method places all of the test cases into one large group. For larger projects though this may not be flexible enough; you may want to group the tests in all sorts of ways.

    To get a more flexible group test we can subclass GroupTest and then instantiate it as needed...

    <?php
        require_once('simpletest/unit_tester.php');
        require_once('simpletest/reporter.php');
        
        class FileGroupTest extends GroupTest {
            function FileGroupTest() {
                $this->GroupTest('All file tests');
                $this->addTestFile('file_test.php');
            }
        }
    ?>
    
    This effectively names the test in the constructor and then adds our test cases and a single group below. Of course we can add more than one group at this point. We can now invoke the tests from a separate runner file...
    <?php
        require_once('file_group_test.php');
        
        $test = &new FileGroupTest();
        $test->run(new HtmlReporter());
    ?>
    
    ...or we can group them into even larger group tests...
    <?php
        require_once('file_group_test.php');
        
        $test = &new BigGroupTest('Big group');
        $test->addTestCase(new FileGroupTest());
        $test->addTestCase(...);
        $test->run(new HtmlReporter());
    ?>
    
    If we still wish to run the original group test and we don't want all of these little runner files, we can put the test runner code around guard bars when we create each group.
    <?php
        class FileGroupTest extends GroupTest {
            function FileGroupTest() {
                $this->GroupTest('All file tests');
                $test->addTestFile('file_test.php');
            }
        }
        
        if (! defined('RUNNER')) {
            define('RUNNER', true);
            $test = &new FileGroupTest();
            $test->run(new HtmlReporter());
        }
    ?>
    
    This approach requires the guard to be set when including the group test file, but this is still less hassle than lots of separate runner files. You include the same guard on the top level tests to make sure that run() will run once only from the top level script that has been invoked.
    <?php
        define('RUNNER', true);
        require_once('file_group_test.php');
    
        $test = &new BigGroupTest('Big group');
        $test->addTestCase(new FileGroupTest());
        $test->addTestCase(...);
        $test->run(new HtmlReporter());
    ?>
    
    As with the normal test cases, a GroupTest can be loaded with the GroupTest::addTestFile() method.
    <?php
        define('RUNNER', true);
    
        $test = &new BigGroupTest('Big group');
        $test->addTestFile('file_group_test.php');
        $test->addTestFile(...);
        $test->run(new HtmlReporter());
    ?>
    

    Integrating legacy test cases

    If you already have unit tests for your code or are extending external classes that have tests, it is unlikely that all of the test cases are in SimpleTest format. Fortunately it is possible to incorporate test cases from other unit testers directly into SimpleTest group tests.

    Say we have the following PhpUnit test case in the file config_test.php...

    class ConfigFileTest extends TestCase {
        function ConfigFileTest() {
            $this->TestCase('Config file test');
        }
        
        function testContents() {
            $config = new ConfigFile('test.conf');
            $this->assertRegexp('/me/', $config->getValue('username'));
        }
    }
    
    The group test can recognise this as long as we include the appropriate adapter class before we add the test file...
    <?php
        require_once('simpletest/unit_tester.php');
        require_once('simpletest/reporter.php');
        require_once('simpletest/adapters/phpunit_test_case.php');
    
        $test = &new GroupTest('All file tests');
        $test->addTestFile('config_test.php');
        $test->run(new HtmlReporter());
    ?>
    
    There are only two adapters, the other is for the PEAR 1.0 unit tester...
    <?php
        require_once('simpletest/unit_tester.php');
        require_once('simpletest/reporter.php');
        require_once('simpletest/adapters/pear_test_case.php');
    
        $test = &new GroupTest('All file tests');
        $test->addTestFile('some_pear_test_cases.php');
        $test->run(new HtmlReporter());
    ?>
    
    The PEAR test cases can be freely mixed with SimpleTest ones even in the same test file, but you cannot use SimpleTest assertions in the legacy test case versions. This is done as a check that you are not accidently making your test cases completely dependent on SimpleTest. You may want to do a PEAR release of your library for example which would mean shipping it with valid PEAR::PhpUnit test cases.

    postfixadmin-2.3.7/tests/simpletest/docs/en/form_testing_documentation.html0000664000175000017620000002435611157271050027474 0ustar davidpalepurple Simple Test documentation for testing HTML forms

    Form testing documentation

    Submitting a simple form

    When a page is fetched by the WebTestCase using get() or post() the page content is automatically parsed. This results in any form controls that are inside <form> tags being available from within the test case. For example, if we have this snippet of HTML...

    <form>
        <input type="text" name="a" value="A default" />
        <input type="submit" value="Go" />
    </form>
    
    Which looks like this...

    We can navigate to this code, via the LastCraft site, with the following test...

    class SimpleFormTests extends WebTestCase {
        
        function testDefaultValue() {
            $this->get('http://www.lastcraft.com/form_testing_documentation.php');
            $this->assertField('a', 'A default');
        }
    }
    
    Immediately after loading the page all of the HTML controls are set at their default values just as they would appear in the web browser. The assertion tests that a HTML widget exists in the page with the name "a" and that it is currently set to the value "A default". As usual, we could use a pattern expectation instead if a fixed string.

    We could submit the form straight away, but first we'll change the value of the text field and only then submit it...

    class SimpleFormTests extends WebTestCase {
    
        function testDefaultValue() {
            $this->get('http://www.my-site.com/');
            $this->assertField('a', 'A default');
            $this->setField('a', 'New value');
            $this->click('Go');
        }
    }
    
    Because we didn't specify a method attribute on the form tag, and didn't specify an action either, the test case will follow the usual browser behaviour of submitting the form data as a GET request back to the same location. SimpleTest tries to emulate typical browser behaviour as much as possible, rather than attempting to catch missing attributes on tags. This is because the target of the testing framework is the PHP application logic, not syntax or other errors in the HTML code. For HTML errors, other tools such as HTMLTidy should be used.

    If a field is not present in any form, or if an option is unavailable, then WebTestCase::setField() will return false. For example, suppose we wish to verify that a "Superuser" option is not present in this form...

    <strong>Select type of user to add:</strong>
    <select name="type">
        <option>Subscriber</option>
        <option>Author</option>
        <option>Administrator</option>
    </select>
    
    Which looks like...

    Select type of user to add:

    The following test will confirm it...

    class SimpleFormTests extends WebTestCase {
        ...
        function testNoSuperuserChoiceAvailable() {
            $this->get('http://www.lastcraft.com/form_testing_documentation.php');
            $this->assertFalse($this->setField('type', 'Superuser'));
        }
    }
    
    The selection will not be changed on a failure to set a widget value.

    Here is the full list of widgets currently supported...

    • Text fields, including hidden and password fields.
    • Submit buttons including the button tag, although not yet reset buttons
    • Text area. This includes text wrapping behaviour.
    • Checkboxes, including multiple checkboxes in the same form.
    • Drop down selections, including multiple selects.
    • Radio buttons.
    • Images.

    Although most standard HTML widgets are catered for by SimpleTest's built in parser, it is unlikely that JavaScript will be implemented anytime soon.

    Fields with multiple values

    SimpleTest can cope with two types of multivalue controls: Multiple selection drop downs, and multiple checkboxes with the same name within a form. The multivalue nature of these means that setting and testing are slightly different. Using checkboxes as an example...

    <form class="demo">
        <strong>Create privileges allowed:</strong>
        <input type="checkbox" name="crud" value="c" checked><br>
        <strong>Retrieve privileges allowed:</strong>
        <input type="checkbox" name="crud" value="r" checked><br>
        <strong>Update privileges allowed:</strong>
        <input type="checkbox" name="crud" value="u" checked><br>
        <strong>Destroy privileges allowed:</strong>
        <input type="checkbox" name="crud" value="d" checked><br>
        <input type="submit" value="Enable Privileges">
    </form>
    
    Which renders as...

    Create privileges allowed:
    Retrieve privileges allowed:
    Update privileges allowed:
    Destroy privileges allowed:

    If we wish to disable all but the retrieval privileges and submit this information we can do it like this...

    class SimpleFormTests extends WebTestCase {
        ...
        function testDisableNastyPrivileges() {
            $this->get('http://www.lastcraft.com/form_testing_documentation.php');
            $this->assertField('crud', array('c', 'r', 'u', 'd'));
            $this->setField('crud', array('r'));
            $this->click('Enable Privileges');
        }
    }
    
    Instead of setting the field to a single value, we give it a list of values. We do the same when testing expected values. We can then write other test code to confirm the effect of this, perhaps by logging in as that user and attempting an update.

    Raw posting

    If you want to test a form handler, but have not yet written or do not have access to the form itself, you can create a form submission by hand.

    class SimpleFormTests extends WebTestCase {
        ...    
        function testAttemptedHack() {
            $this->post(
                    'http://www.my-site.com/add_user.php',
                    array('type' => 'superuser'));
            $this->assertNoText('user created');
        }
    }
    
    By adding data to the WebTestCase::post() method, we are attempting to fetch the page as a form submission.

    postfixadmin-2.3.7/tests/simpletest/docs/en/partial_mocks_documentation.html0000664000175000017620000003435211157271050027621 0ustar davidpalepurple SimpleTest for PHP partial mocks documentation

    Partial mock objects documentation

    A partial mock is simply a pattern to alleviate a specific problem in testing with mock objects, that of getting mock objects into tight corners. It's quite a limited tool and possibly not even a good idea. It is included with SimpleTest because I have found it useful on more than one occasion and has saved a lot of work at that point.

    The mock injection problem

    When one object uses another it is very simple to just pass a mock version in already set up with its expectations. Things are rather tricker if one object creates another and the creator is the one you want to test. This means that the created object should be mocked, but we can hardly tell our class under test to create a mock instead. The tested class doesn't even know it is running inside a test after all.

    For example, suppose we are building a telnet client and it needs to create a network socket to pass its messages. The connection method might look something like...

    <?php
        require_once('socket.php');
        
        class Telnet {
            ...
            function &connect($ip, $port, $username, $password) {
                $socket = &new Socket($ip, $port);
                $socket->read( ... );
                ...
            }
        }
    ?>
    
    We would really like to have a mock object version of the socket here, what can we do?

    The first solution is to pass the socket in as a parameter, forcing the creation up a level. Having the client handle this is actually a very good approach if you can manage it and should lead to factoring the creation from the doing. In fact, this is one way in which testing with mock objects actually forces you to code more tightly focused solutions. They improve your programming.

    Here this would be...

    <?php
        require_once('socket.php');
        
        class Telnet {
            ...
            function &connect(&$socket, $username, $password) {
                $socket->read( ... );
                ...
            }
        }
    ?>
    
    This means that the test code is typical for a test involving mock objects.
    class TelnetTest extends UnitTestCase {
        ...
        function testConnection() {
            $socket = &new MockSocket($this);
            ...
            $telnet = &new Telnet();
            $telnet->connect($socket, 'Me', 'Secret');
            ...
        }
    }
    
    It is pretty obvious though that one level is all you can go. You would hardly want your top level application creating every low level file, socket and database connection ever needed. It wouldn't know the constructor parameters anyway.

    The next simplest compromise is to have the created object passed in as an optional parameter...

    <?php
        require_once('socket.php');
        
        class Telnet {
            ...
            function &connect($ip, $port, $username, $password, $socket = false) {
                if (!$socket) {
                    $socket = &new Socket($ip, $port);
                }
                $socket->read( ... );
                ...
                return $socket;
            }
        }
    ?>
    
    For a quick solution this is usually good enough. The test now looks almost the same as if the parameter was formally passed...
    class TelnetTest extends UnitTestCase {
        ...
        function testConnection() {
            $socket = &new MockSocket($this);
            ...
            $telnet = &new Telnet();
            $telnet->connect('127.0.0.1', 21, 'Me', 'Secret', &$socket);
            ...
        }
    }
    
    The problem with this approach is its untidiness. There is test code in the main class and parameters passed in the test case that are never used. This is a quick and dirty approach, but nevertheless effective in most situations.

    The next method is to pass in a factory object to do the creation...

    <?php
        require_once('socket.php');
        
        class Telnet {
            function Telnet(&$network) {
                $this->_network = &$network;
            }
            ...
            function &connect($ip, $port, $username, $password) {
                $socket = &$this->_network->createSocket($ip, $port);
                $socket->read( ... );
                ...
                return $socket;
            }
        }
    ?>
    
    This is probably the most highly factored answer as creation is now moved into a small specialist class. The networking factory can now be tested separately, but mocked easily when we are testing the telnet class...
    class TelnetTest extends UnitTestCase {
        ...
        function testConnection() {
            $socket = &new MockSocket($this);
            ...
            $network = &new MockNetwork($this);
            $network->setReturnReference('createSocket', $socket);
            $telnet = &new Telnet($network);
            $telnet->connect('127.0.0.1', 21, 'Me', 'Secret');
            ...
        }
    }
    
    The downside is that we are adding a lot more classes to the library. Also we are passing a lot of factories around which will make the code a little less intuitive. The most flexible solution, but the most complex.

    Is there a middle ground?

    Protected factory method

    There is a way we can circumvent the problem without creating any new application classes, but it involves creating a subclass when we do the actual testing. Firstly we move the socket creation into its own method...

    <?php
        require_once('socket.php');
        
        class Telnet {
            ...
            function &connect($ip, $port, $username, $password) {
                $socket = &$this->_createSocket($ip, $port);
                $socket->read( ... );
                ...
            }
            
            function &_createSocket($ip, $port) {
                return new Socket($ip, $port);
            }
        }
    ?>
    
    This is the only change we make to the application code.

    For the test case we have to create a subclass so that we can intercept the socket creation...

    class TelnetTestVersion extends Telnet {
        var $_mock;
        
        function TelnetTestVersion(&$mock) {
            $this->_mock = &$mock;
            $this->Telnet();
        }
        
        function &_createSocket() {
            return $this->_mock;
        }
    }
    
    Here I have passed the mock in the constructor, but a setter would have done just as well. Note that the mock was set into the object variable before the constructor was chained. This is necessary in case the constructor calls connect(). Otherwise it could get a null value from _createSocket().

    After the completion of all of this extra work the actual test case is fairly easy. We just test our new class instead...

    class TelnetTest extends UnitTestCase {
        ...
        function testConnection() {
            $socket = &new MockSocket($this);
            ...
            $telnet = &new TelnetTestVersion($socket);
            $telnet->connect('127.0.0.1', 21, 'Me', 'Secret');
            ...
        }
    }
    
    The new class is very simple of course. It just sets up a return value, rather like a mock. It would be nice if it also checked the incoming parameters as well. Just like a mock. It seems we are likely to do this often, can we automate the subclass creation?

    A partial mock

    Of course the answer is "yes" or I would have stopped writing this by now! The previous test case was a lot of work, but we can generate the subclass using a similar approach to the mock objects.

    Here is the partial mock version of the test...

    Mock::generatePartial(
            'Telnet',
            'TelnetTestVersion',
            array('_createSocket'));
    
    class TelnetTest extends UnitTestCase {
        ...
        function testConnection() {
            $socket = &new MockSocket($this);
            ...
            $telnet = &new TelnetTestVersion($this);
            $telnet->setReturnReference('_createSocket', $socket);
            $telnet->Telnet();
            $telnet->connect('127.0.0.1', 21, 'Me', 'Secret');
            ...
        }
    }
    
    The partial mock is a subclass of the original with selected methods "knocked out" with test versions. The generatePartial() call takes three parameters: the class to be subclassed, the new test class name and a list of methods to mock.

    Instantiating the resulting objects is slightly tricky. The only constructor parameter of a partial mock is the unit tester reference. As with the normal mock objects this is needed for sending test results in response to checked expectations.

    The original constructor is not run yet. This is necessary in case the constructor is going to make use of the as yet unset mocked methods. We set any return values at this point and then run the constructor with its normal parameters. This three step construction of "new", followed by setting up the methods, followed by running the constructor proper is what distinguishes the partial mock code.

    Apart from construction, all of the mocked methods have the same features as mock objects and all of the unmocked methods behave as before. We can set expectations very easily...

    class TelnetTest extends UnitTestCase {
        ...
        function testConnection() {
            $socket = &new MockSocket($this);
            ...
            $telnet = &new TelnetTestVersion($this);
            $telnet->setReturnReference('_createSocket', $socket);
            $telnet->expectOnce('_createSocket', array('127.0.0.1', 21));
            $telnet->Telnet();
            $telnet->connect('127.0.0.1', 21, 'Me', 'Secret');
            ...
            $telnet->tally();
        }
    }
    

    Testing less than a class

    The mocked out methods don't have to be factory methods, they could be any sort of method. In this way partial mocks allow us to take control of any part of a class except the constructor. We could even go as far as to mock every method except one we actually want to test.

    This last situation is all rather hypothetical, as I haven't tried it. I am open to the possibility, but a little worried that forcing object granularity may be better for the code quality. I personally use partial mocks as a way of overriding creation or for occasional testing of the TemplateMethod pattern.

    It's all going to come down to the coding standards of your project to decide which mechanism you use.

    postfixadmin-2.3.7/tests/simpletest/docs/en/mock_objects_documentation.html0000664000175000017620000007351511157271050027437 0ustar davidpalepurple SimpleTest for PHP mock objects documentation

    Mock objects documentation

    What are mock objects?

    Mock objects have two roles during a test case: actor and critic.

    The actor behaviour is to simulate objects that are difficult to set up or time consuming to set up for a test. The classic example is a database connection. Setting up a test database at the start of each test would slow testing to a crawl and would require the installation of the database engine and test data on the test machine. If we can simulate the connection and return data of our choosing we not only win on the pragmatics of testing, but can also feed our code spurious data to see how it responds. We can simulate databases being down or other extremes without having to create a broken database for real. In other words, we get greater control of the test environment.

    If mock objects only behaved as actors they would simply be known as server stubs. This was originally a pattern named by Robert Binder (Testing object-oriented systems: models, patterns, and tools, Addison-Wesley) in 1999.

    A server stub is a simulation of an object or component. It should exactly replace a component in a system for test or prototyping purposes, but remain lightweight. This allows tests to run more quickly, or if the simulated class has not been written, to run at all.

    However, the mock objects not only play a part (by supplying chosen return values on demand) they are also sensitive to the messages sent to them (via expectations). By setting expected parameters for a method call they act as a guard that the calls upon them are made correctly. If expectations are not met they save us the effort of writing a failed test assertion by performing that duty on our behalf.

    In the case of an imaginary database connection they can test that the query, say SQL, was correctly formed by the object that is using the connection. Set them up with fairly tight expectations and you will hardly need manual assertions at all.

    Creating mock objects

    In the same way that we create server stubs, all we need is an existing class, say a database connection that looks like this...

    class DatabaseConnection {
        function DatabaseConnection() {
        }
        
        function query() {
        }
        
        function selectQuery() {
        }
    }
    
    The class does not need to have been implemented yet. To create a mock version of the class we need to include the mock object library and run the generator...
    require_once('simpletest/unit_tester.php');
    require_once('simpletest/mock_objects.php');
    require_once('database_connection.php');
    
    Mock::generate('DatabaseConnection');
    
    This generates a clone class called MockDatabaseConnection. We can now create instances of the new class within our test case...
    require_once('simpletest/unit_tester.php');
    require_once('simpletest/mock_objects.php');
    require_once('database_connection.php');
    
    Mock::generate('DatabaseConnection');
    
    class MyTestCase extends UnitTestCase {
        
        function testSomething() {
            $connection = &new MockDatabaseConnection();
        }
    }
    
    Unlike the generated stubs the mock constructor needs a reference to the test case so that it can dispatch passes and failures while checking its expectations. This means that mock objects can only be used within test cases. Despite this their extra power means that stubs are hardly ever used if mocks are available.

    Mocks as actors

    The mock version of a class has all the methods of the original, so that operations like $connection->query() are still legal. The return value will be null, but we can change that with...

    $connection->setReturnValue('query', 37)
    
    Now every time we call $connection->query() we get the result of 37. We can set the return value to anything, say a hash of imaginary database results or a list of persistent objects. Parameters are irrelevant here, we always get the same values back each time once they have been set up this way. That may not sound like a convincing replica of a database connection, but for the half a dozen lines of a test method it is usually all you need.

    We can also add extra methods to the mock when generating it and choose our own class name...

    Mock::generate('DatabaseConnection', 'MyMockDatabaseConnection', array('setOptions'));
    
    Here the mock will behave as if the setOptions() existed in the original class. This is handy if a class has used the PHP overload() mechanism to add dynamic methods. You can create a special mock to simulate this situation.

    Things aren't always that simple though. One common problem is iterators, where constantly returning the same value could cause an endless loop in the object being tested. For these we need to set up sequences of values. Let's say we have a simple iterator that looks like this...

    class Iterator {
        function Iterator() {
        }
        
        function next() {
        }
    }
    
    This is about the simplest iterator you could have. Assuming that this iterator only returns text until it reaches the end, when it returns false, we can simulate it with...
    Mock::generate('Iterator');
    
    class IteratorTest extends UnitTestCase() {
        
        function testASequence() {
            $iterator = &new MockIterator();
            $iterator->setReturnValue('next', false);
            $iterator->setReturnValueAt(0, 'next', 'First string');
            $iterator->setReturnValueAt(1, 'next', 'Second string');
            ...
        }
    }
    
    When next() is called on the mock iterator it will first return "First string", on the second call "Second string" will be returned and on any other call false will be returned. The sequenced return values take precedence over the constant return value. The constant one is a kind of default if you like.

    Another tricky situation is an overloaded get() operation. An example of this is an information holder with name/value pairs. Say we have a configuration class like...

    class Configuration {
        function Configuration() {
        }
        
        function getValue($key) {
        }
    }
    
    This is a classic situation for using mock objects as actual configuration will vary from machine to machine, hardly helping the reliability of our tests if we use it directly. The problem though is that all the data comes through the getValue() method and yet we want different results for different keys. Luckily the mocks have a filter system...
    $config = &new MockConfiguration();
    $config->setReturnValue('getValue', 'primary', array('db_host'));
    $config->setReturnValue('getValue', 'admin', array('db_user'));
    $config->setReturnValue('getValue', 'secret', array('db_password'));
    
    The extra parameter is a list of arguments to attempt to match. In this case we are trying to match only one argument which is the look up key. Now when the mock object has the getValue() method invoked like this...
    $config->getValue('db_user')
    
    ...it will return "admin". It finds this by attempting to match the calling arguments to its list of returns one after another until a complete match is found.

    You can set a default argument argument like so...

    
    $config->setReturnValue('getValue', false, array('*'));
    
    This is not the same as setting the return value without any argument requirements like this...
    
    $config->setReturnValue('getValue', false);
    
    In the first case it will accept any single argument, but exactly one is required. In the second case any number of arguments will do and it acts as a catchall after all other matches. Note that if we add further single parameter options after the wildcard in the first case, they will be ignored as the wildcard will match first. With complex parameter lists the ordering could be important or else desired matches could be masked by earlier wildcard ones. Declare the most specific matches first if you are not sure.

    There are times when you want a specific object to be dished out by the mock rather than a copy. The PHP4 copy semantics force us to use a different method for this. You might be simulating a container for example...

    class Thing {
    }
    
    class Vector {
        function Vector() {
        }
        
        function get($index) {
        }
    }
    
    In this case you can set a reference into the mock's return list...
    $thing = &new Thing();
    $vector = &new MockVector();
    $vector->setReturnReference('get', $thing, array(12));
    
    With this arrangement you know that every time $vector->get(12) is called it will return the same $thing each time. This is compatible with PHP5 as well.

    These three factors, timing, parameters and whether to copy, can be combined orthogonally. For example...

    $complex = &new MockComplexThing();
    $stuff = &new Stuff();
    $complex->setReturnReferenceAt(3, 'get', $stuff, array('*', 1));
    
    This will return the $stuff only on the third call and only if two parameters were set the second of which must be the integer 1. That should cover most simple prototyping situations.

    A final tricky case is one object creating another, known as a factory pattern. Suppose that on a successful query to our imaginary database, a result set is returned as an iterator with each call to next() giving one row until false. This sounds like a simulation nightmare, but in fact it can all be mocked using the mechanics above.

    Here's how...

    Mock::generate('DatabaseConnection');
    Mock::generate('ResultIterator');
    
    class DatabaseTest extends UnitTestCase {
        
        function testUserFinder() {
            $result = &new MockResultIterator();
            $result->setReturnValue('next', false);
            $result->setReturnValueAt(0, 'next', array(1, 'tom'));
            $result->setReturnValueAt(1, 'next', array(3, 'dick'));
            $result->setReturnValueAt(2, 'next', array(6, 'harry'));
            
            $connection = &new MockDatabaseConnection();
            $connection->setReturnValue('query', false);
            $connection->setReturnReference(
                    'query',
                    $result,
                    array('select id, name from users'));
                    
            $finder = &new UserFinder($connection);
            $this->assertIdentical(
                    $finder->findNames(),
                    array('tom', 'dick', 'harry'));
        }
    }
    
    Now only if our $connection is called with the correct query() will the $result be returned that is itself exhausted after the third call to next(). This should be enough information for our UserFinder class, the class actually being tested here, to come up with goods. A very precise test and not a real database in sight.

    Mocks as critics

    Although the server stubs approach insulates your tests from real world disruption, it is only half the benefit. You can have the class under test receiving the required messages, but is your new class sending correct ones? Testing this can get messy without a mock objects library.

    By way of example, suppose we have a SessionPool class that we want to add logging to. Rather than grow the original class into something more complicated, we want to add this behaviour with a decorator (GOF). The SessionPool code currently looks like this...

    class SessionPool {
        function SessionPool() {
            ...
        }
        
        function &findSession($cookie) {
            ...
        }
        ...
    }
    
    class Session {
        ...
    }
    </php>
                    While our logging code looks like this...
    <php>
    class Log {
        function Log() {
            ...
        }
        
        function message() {
            ...
        }
    }
    
    class LoggingSessionPool {
        function LoggingSessionPool(&$session_pool, &$log) {
            ...
        }
        
        function &findSession(\$cookie) {
            ...
        }
        ...
    }
    
    Out of all of this, the only class we want to test here is the LoggingSessionPool. In particular we would like to check that the findSession() method is called with the correct session ID in the cookie and that it sent the message "Starting session $cookie" to the logger.

    Despite the fact that we are testing only a few lines of production code, here is what we would have to do in a conventional test case:

    1. Create a log object.
    2. Set a directory to place the log file.
    3. Set the directory permissions so we can write the log.
    4. Create a SessionPool object.
    5. Hand start a session, which probably does lot's of things.
    6. Invoke findSession().
    7. Read the new Session ID (hope there is an accessor!).
    8. Raise a test assertion to confirm that the ID matches the cookie.
    9. Read the last line of the log file.
    10. Pattern match out the extra logging timestamps, etc.
    11. Assert that the session message is contained in the text.
    It is hardly surprising that developers hate writing tests when they are this much drudgery. To make things worse, every time the logging format changes or the method of creating new sessions changes, we have to rewrite parts of this test even though this test does not officially test those parts of the system. We are creating headaches for the writers of these other classes.

    Instead, here is the complete test method using mock object magic...

    Mock::generate('Session');
    Mock::generate('SessionPool');
    Mock::generate('Log');
    
    class LoggingSessionPoolTest extends UnitTestCase {
        ...
        function testFindSessionLogging() {
            $session = &new MockSession();
            $pool = &new MockSessionPool();
            $pool->setReturnReference('findSession', $session);
            $pool->expectOnce('findSession', array('abc'));
            
            $log = &new MockLog();
            $log->expectOnce('message', array('Starting session abc'));
            
            $logging_pool = &new LoggingSessionPool($pool, $log);
            $this->assertReference($logging_pool->findSession('abc'), $session);
        }
    }
    
    We start by creating a dummy session. We don't have to be too fussy about this as the check for which session we want is done elsewhere. We only need to check that it was the same one that came from the session pool.

    findSession() is a factory method the simulation of which is described above. The point of departure comes with the first expectOnce() call. This line states that whenever findSession() is invoked on the mock, it will test the incoming arguments. If it receives the single argument of a string "abc" then a test pass is sent to the unit tester, otherwise a fail is generated. This was the part where we checked that the right session was asked for. The argument list follows the same format as the one for setting return values. You can have wildcards and sequences and the order of evaluation is the same.

    We use the same pattern to set up the mock logger. We tell it that it should have message() invoked once only with the argument "Starting session abc". By testing the calling arguments, rather than the logger output, we insulate the test from any display changes in the logger.

    We start to run our tests when we create the new LoggingSessionPool and feed it our preset mock objects. Everything is now under our control.

    This is still quite a bit of test code, but the code is very strict. If it still seems rather daunting there is a lot less of it than if we tried this without mocks and this particular test, interactions rather than output, is always more work to set up. More often you will be testing more complex situations without needing this level or precision. Also some of this can be refactored into a test case setUp() method.

    Here is the full list of expectations you can set on a mock object in SimpleTest...
    ExpectationNeeds tally()
    expect($method, $args) No
    expectAt($timing, $method, $args) No
    expectCallCount($method, $count) Yes
    expectMaximumCallCount($method, $count) No
    expectMinimumCallCount($method, $count) Yes
    expectNever($method) No
    expectOnce($method, $args) Yes
    expectAtLeastOnce($method, $args) Yes
    Where the parameters are...

    $method
    The method name, as a string, to apply the condition to.
    $args
    The arguments as a list. Wildcards can be included in the same manner as for setReturn(). This argument is optional for expectOnce() and expectAtLeastOnce().
    $timing
    The only point in time to test the condition. The first call starts at zero.
    $count
    The number of calls expected.
    The method expectMaximumCallCount() is slightly different in that it will only ever generate a failure. It is silent if the limit is never reached.

    Like the assertions within test cases, all of the expectations can take a message override as an extra parameter. Also the original failure message can be embedded in the output as "%s".

    Other approaches

    There are three approaches to creating mocks including the one that SimpleTest employs. Coding them by hand using a base class, generating them to a file and dynamically generating them on the fly.

    Mock objects generated with SimpleTest are dynamic. They are created at run time in memory, using eval(), rather than written out to a file. This makes the mocks easy to create, a one liner, especially compared with hand crafting them in a parallel class hierarchy. The problem is that the behaviour is usually set up in the tests themselves. If the original objects change the mock versions that the tests rely on can get out of sync. This can happen with the parallel hierarchy approach as well, but is far more quickly detected.

    The solution, of course, is to add some real integration tests. You don't need very many and the convenience gained from the mocks more than outweighs the small amount of extra testing. You cannot trust code that was only tested with mocks.

    If you are still determined to build static libraries of mocks because you want to simulate very specific behaviour, you can achieve the same effect using the SimpleTest class generator. In your library file, say mocks/connection.php for a database connection, create a mock and inherit to override special methods or add presets...

    <?php
        require_once('simpletest/mock_objects.php');
        require_once('../classes/connection.php');
    
        Mock::generate('Connection', 'BasicMockConnection');
        class MockConnection extends BasicMockConnection {
            function MockConnection() {
                $this->BasicMockConnection();
                $this->setReturn('query', false);
            }
        }
    ?>
    
    The generate call tells the class generator to create a class called BasicMockConnection rather than the usual MockConnection. We then inherit from this to get our version of MockConnection. By intercepting in this way we can add behaviour, here setting the default value of query() to be false. By using the default name we make sure that the mock class generator will not recreate a different one when invoked elsewhere in the tests. It never creates a class if it already exists. As long as the above file is included first then all tests that generated MockConnection should now be using our one instead. If we don't get the order right and the mock library creates one first then the class creation will simply fail.

    Use this trick if you find you have a lot of common mock behaviour or you are getting frequent integration problems at later stages of testing.

    postfixadmin-2.3.7/tests/simpletest/docs/en/expectation_documentation.html0000664000175000017620000003152011157271050027306 0ustar davidpalepurple Extending the SimpleTest unit tester with additional expectation classes

    Expectation documentation

    More control over mock objects

    The default behaviour of the mock objects in SimpleTest is either an identical match on the argument or to allow any argument at all. For almost all tests this is sufficient. Sometimes, though, you want to weaken a test case.

    One place where a test can be too tightly coupled is with text matching. Suppose we have a component that outputs a helpful error message when something goes wrong. You want to test that the correct error was sent, but the actual text may be rather long. If you test for the text exactly, then every time the exact wording of the message changes, you will have to go back and edit the test suite.

    For example, suppose we have a news service that has failed to connect to its remote source.

    class NewsService {
        ...
        function publish(&$writer) {
            if (! $this->isConnected()) {
                $writer->write('Cannot connect to news service "' .
                        $this->_name . '" at this time. ' .
                        'Please try again later.');
            }
            ...
        }
    }
    
    Here it is sending its content to a Writer class. We could test this behaviour with a MockWriter like so...
    class TestOfNewsService extends UnitTestCase {
        ...
        function testConnectionFailure() {<strong>
            $writer = &new MockWriter();
            $writer->expectOnce('write', array(
                    'Cannot connect to news service ' .
                    '"BBC News" at this time. ' .
                    'Please try again later.'));
            
            $service = &new NewsService('BBC News');
            $service->publish($writer);
        }
    }
    
    This is a good example of a brittle test. If we decide to add additional instructions, such as suggesting an alternative news source, we will break our tests even though no underlying functionality has been altered.

    To get around this, we would like to do a regular expression test rather than an exact match. We can actually do this with...

    class TestOfNewsService extends UnitTestCase {
        ...
        function testConnectionFailure() {
            $writer = &new MockWriter();
            $writer->expectOnce(
                    'write',
                    array(new PatternExpectation('/cannot connect/i')));
            
            $service = &new NewsService('BBC News');
            $service->publish($writer);
        }
    }
    
    Instead of passing in the expected parameter to the MockWriter we pass an expectation class called WantedPatternExpectation. The mock object is smart enough to recognise this as special and to treat it differently. Rather than simply comparing the incoming argument to this object, it uses the expectation object itself to perform the test.

    The WantedPatternExpectation takes the regular expression to match in its constructor. Whenever a comparison is made by the MockWriter against this expectation class, it will do a preg_match() with this pattern. With our test case above, as long as "cannot connect" appears in the text of the string, the mock will issue a pass to the unit tester. The rest of the text does not matter.

    The possible expectation classes are...
    EqualExpectationAn equality, rather than the stronger identity comparison
    NotEqualExpectationAn inequality comparison
    IndenticalExpectationThe default mock object check which must match exactly
    NotIndenticalExpectationInverts the mock object logic
    PatternExpectationUses a Perl Regex to match a string
    NoPatternExpectationPasses only if failing a Perl Regex
    IsAExpectationChecks the type or class name only
    NotAExpectationOpposite of the IsAExpectation
    MethodExistsExpectationChecks a method is available on an object
    Most take the expected value in the constructor. The exceptions are the pattern matchers, which take a regular expression, and the IsAExpectation and NotAExpectation which takes a type or class name as a string.

    Using expectations to control stubs

    The expectation classes can be used not just for sending assertions from mock objects, but also for selecting behaviour for the mock objects. Anywhere a list of arguments is given, a list of expectation objects can be inserted instead.

    Suppose we want an authorisation server mock to simulate a successful login only if it receives a valid session object. We can do this as follows...

    Mock::generate('Authorisation');
    
    $authorisation = new MockAuthorisation();
    $authorisation->setReturnValue(
            'isAllowed',
            true,
            array(new IsAExpectation('Session', 'Must be a session')));
    $authorisation->setReturnValue('isAllowed', false);
    
    We have set the default mock behaviour to return false when isAllowed is called. When we call the method with a single parameter that is a Session object, it will return true. We have also added a second parameter as a message. This will be displayed as part of the mock object failure message if this expectation is the cause of a failure.

    This kind of sophistication is rarely useful, but is included for completeness.

    Creating your own expectations

    The expectation classes have a very simple structure. So simple that it is easy to create your own versions for commonly used test logic.

    As an example here is the creation of a class to test for valid IP addresses. In order to work correctly with the stubs and mocks the new expectation class should extend SimpleExpectation...

    class ValidIp extends SimpleExpectation {
        
        function test($ip) {
            return (ip2long($ip) != -1);
        }
        
        function testMessage($ip) {
            return "Address [$ip] should be a valid IP address";
        }
    }
    
    There are only two methods to implement. The test() method should evaluate to true if the expectation is to pass, and false otherwise. The testMessage() method should simply return some helpful text explaining the test that was carried out.

    This class can now be used in place of the earlier expectation classes.

    Under the bonnet of the unit tester

    The SimpleTest unit testing framework also uses the expectation classes internally for the UnitTestCase class. We can also take advantage of these mechanisms to reuse our homebrew expectation classes within the test suites directly.

    The most crude way of doing this is to use the SimpleTest::assert() method to test against it directly...

    class TestOfNetworking extends UnitTestCase {
        ...
        function testGetValidIp() {
            $server = &new Server();
            $this->assert(
                    new ValidIp(),
                    $server->getIp(),
                    'Server IP address->%s');
        }
    }
    
    This is a little untidy compared with our usual assert...() syntax.

    For such a simple case we would normally create a separate assertion method on our test case rather than bother using the expectation class. If we pretend that our expectation is a little more complicated for a moment, so that we want to reuse it, we get...

    class TestOfNetworking extends UnitTestCase {
        ...
        function assertValidIp($ip, $message = '%s') {
            $this->assert(new ValidIp(), $ip, $message);
        }
        
        function testGetValidIp() {
            $server = &new Server();
            $this->assertValidIp(
                    $server->getIp(),
                    'Server IP address->%s');
        }
    }
    
    It is unlikely we would ever need this degree of control over the testing machinery. It is rare to need the expectations for more than pattern matching. Also, complex expectation classes could make the tests harder to read and debug. These mechanisms are really of most use to authors of systems that will extend the test framework to create their own tool set.

    postfixadmin-2.3.7/tests/simpletest/docs/en/browser_documentation.html0000664000175000017620000003720611157271050026455 0ustar davidpalepurple SimpleTest documentation for the scriptable web browser component

    PHP Scriptable Web Browser

    SimpleTest's web browser component can be used not just outside of the WebTestCase class, but also independently of the SimpleTest framework itself.

    The Scriptable Browser

    You can use the web browser in PHP scripts to confirm services are up and running, or to extract information from them at a regular basis. For example, here is a small script to extract the current number of open PHP 5 bugs from the PHP web site...

    <?php
        require_once('simpletest/browser.php');
        
        $browser = &new SimpleBrowser();
        $browser->get('http://php.net/');
        $browser->click('reporting bugs');
        $browser->click('statistics');
        $page = $browser->click('PHP 5 bugs only');
        preg_match('/status=Open.*?by=Any.*?(\d+)<\/a>/', $page, $matches);
        print $matches[1];
    ?>
    
    There are simpler methods to do this particular example in PHP of course. For example you can just use the PHP file() command against what here is a pretty fixed page. However, using the web browser for scripts allows authentication, correct handling of cookies, automatic loading of frames, redirects, form submission and the ability to examine the page headers. Such methods are fragile against a site that is constantly evolving and you would want a more direct way of accessing data in a permanent set up, but for simple tasks this can provide a very rapid solution.

    All of the navigation methods used in the WebTestCase are present in the SimpleBrowser class, but the assertions are replaced with simpler accessors. Here is a full list of the page navigation methods...
    addHeader($header)Adds a header to every fetch
    useProxy($proxy, $username, $password)Use this proxy from now on
    head($url, $parameters)Perform a HEAD request
    get($url, $parameters)Fetch a page with GET
    post($url, $parameters)Fetch a page with POST
    clickLink($label)Follows a link by label
    isLink($label)See if a link is present by label
    clickLinkById($id)Follows a link by attribute
    isLinkById($id)See if a link is present by attribut
    getUrl()Current URL of page or frame
    getTitle()Page title
    getContent()Raw page or frame
    getContentAsText()HTML removed except for alt text
    retry()Repeat the last request
    back()Use the browser back button
    forward()Use the browser forward button
    authenticate($username, $password)Retry page or frame after a 401 response
    restart($date)Restarts the browser for a new session
    ageCookies($interval)Ages the cookies by the specified time
    setCookie($name, $value)Sets an additional cookie
    getCookieValue($host, $path, $name)Reads the most specific cookie
    getCurrentCookieValue($name)Reads cookie for the current context
    The methods SimpleBrowser::useProxy() and SimpleBrowser::addHeader() are special. Once called they continue to apply to all subsequent fetches.

    Navigating forms is similar to the WebTestCase form navigation...
    setField($name, $value)Sets all form fields with that name
    setFieldById($id, $value)Sets all form fields with that id
    getField($name)Accessor for a form element value
    getFieldById($id)Accessor for a form element value
    clickSubmit($label)Submits form by button label
    clickSubmitByName($name)Submits form by button attribute
    clickSubmitById($id)Submits form by button attribute
    clickImage($label, $x, $y)Clicks the image by alt text
    clickImageByName($name, $x, $y)Clicks the image by attribute
    clickImageById($id, $x, $y)Clicks the image by attribute
    submitFormById($id)Submits by the form tag attribute
    At the moment there aren't any methods to list available forms and fields. This will probably be added to later versions of SimpleTest.

    Within a page, individual frames can be selected. If no selection is made then all the frames are merged together in one large conceptual page. The content of the current page will be a concatenation of all of the frames in the order that they were specified in the "frameset" tags.
    getFrames()A dump of the current frame structure
    getFrameFocus()Current frame label or index
    setFrameFocusByIndex($choice)Select a frame numbered from 1
    setFrameFocus($name)Select frame by label
    clearFrameFocus()Treat all the frames as a single page
    When focused on a single frame, the content will come from that frame only. This includes links to click and forms to submit.

    What went wrong?

    All of this functionality is great when we actually manage to fetch pages, but that doesn't always happen. To help figure out what went wrong, the browser has some methods to aid in debugging...
    setConnectionTimeout($timeout)Close the socket on overrun
    getRequest()Raw request header of page or frame
    getHeaders()Raw response header of page or frame
    getTransportError()Any socket level errors in the last fetch
    getResponseCode()HTTP response of page or frame
    getMimeType()Mime type of page or frame
    getAuthentication()Authentication type in 401 challenge header
    getRealm()Authentication realm in 401 challenge header
    setMaximumRedirects($max)Number of redirects before page is loaded anyway
    setMaximumNestedFrames($max)Protection against recursive framesets
    ignoreFrames()Disables frames support
    useFrames()Enables frames support
    ignoreCookies()Disables sending and receiving of cookies
    useCookies()Enables cookie support
    The methods SimpleBrowser::setConnectionTimeout() SimpleBrowser::setMaximumRedirects(), SimpleBrowser::setMaximumNestedFrames(), SimpleBrowser::ignoreFrames(), SimpleBrowser::useFrames(), SimpleBrowser::ignoreCookies() and SimpleBrowser::useCokies() continue to apply to every subsequent request. The other methods are frames aware. This means that if you have an individual frame that is not loading, navigate to it using SimpleBrowser::setFrameFocus() and you can then use SimpleBrowser::getRequest(), etc to see what happened.

    Complex unit tests with multiple browsers

    Anything that could be done in a WebTestCase can now be done in a UnitTestCase. This means that we can freely mix domain object testing with the web interface...

    
    class TestOfRegistration extends UnitTestCase {
        function testNewUserAddedToAuthenticator() {
            $browser = &new SimpleBrowser();
            $browser->get('http://my-site.com/register.php');
            $browser->setField('email', 'me@here');
            $browser->setField('password', 'Secret');
            $browser->click('Register');
            
            $authenticator = &new Authenticator();
            $member = &$authenticator->findByEmail('me@here');
            $this->assertEqual($member->getPassword(), 'Secret');
        }
    }
    
    While this may be a useful temporary expediency, I am not a fan of this type of testing. The testing has cut across application layers, make it twice as likely it will need refactoring when the code changes.

    A more useful case of where using the browser directly can be helpful is where the WebTestCase cannot cope. An example is where two browsers are needed at the same time.

    For example, say we want to disallow multiple simultaneous usage of a site with the same username. This test case will do the job...

    class TestOfSecurity extends UnitTestCase {
        function testNoMultipleLoginsFromSameUser() {
            $first = &new SimpleBrowser();
            $first->get('http://my-site.com/login.php');
            $first->setField('name', 'Me');
            $first->setField('password', 'Secret');
            $first->click('Enter');
            $this->assertEqual($first->getTitle(), 'Welcome');
            
            $second = &new SimpleBrowser();
            $second->get('http://my-site.com/login.php');
            $second->setField('name', 'Me');
            $second->setField('password', 'Secret');
            $second->click('Enter');
            $this->assertEqual($second->getTitle(), 'Access Denied');
        }
    }
    
    You can also use the SimpleBrowser class directly when you want to write test cases using a different test tool than SimpleTest.

    postfixadmin-2.3.7/tests/simpletest/docs/en/overview.html0000664000175000017620000004355711157271050023715 0ustar davidpalepurple Overview and feature list for the SimpleTest PHP unit tester and web tester

    Overview of SimpleTest

    What is SimpleTest?

    The heart of SimpleTest is a testing framework built around test case classes. These are written as extensions of base test case classes, each extended with methods that actually contain test code. Top level test scripts then invoke the run() methods on every one of these test cases in order. Each test method is written to invoke various assertions that the developer expects to be true such as assertEqual(). If the expectation is correct, then a successful result is dispatched to the observing test reporter, but any failure triggers an alert and a description of the mismatch.

    A test case looks like this...

    <?php
    class MyTestCase extends UnitTestCase {
        
        function testLog() {
            $log = &new Log('my.log');
            $log->message('Hello');
            $this->assertTrue(file_exists('my.log'));
        }
    }
    ?>
    

    These tools are designed for the developer. Tests are written in the PHP language itself more or less as the application itself is built. The advantage of using PHP itself as the testing language is that there are no new languages to learn, testing can start straight away, and the developer can test any part of the code. Basically, all parts that can be accessed by the application code can also be accessed by the test code if they are in the same language.

    The simplest type of test case is the UnitTestCase. This class of test case includes standard tests for equality, references and pattern matching. All these test the typical expectations of what you would expect the result of a function or method to be. This is by far the most common type of test in the daily routine of development, making up about 95% of test cases.

    The top level task of a web application though is not to produce correct output from its methods and objects, but to generate web pages. The WebTestCase class tests web pages. It simulates a web browser requesting a page, complete with cookies, proxies, secure connections, authentication, forms, frames and most navigation elements. With this type of test case, the developer can assert that information is present in the page and that forms and sessions are handled correctly.

    A WebTestCase looks like this...

    <?php
    class MySiteTest extends WebTestCase {
        
        function testHomePage() {
            $this->get('http://www.my-site.com/index.php');
            $this->assertTitle('My Home Page');
            $this->clickLink('Contact');
            $this->assertTitle('Contact me');
            $this->assertWantedPattern('/Email me at/');
        }
    }
    ?>
    

    Feature list

    The following is a very rough outline of past and future features and their expected point of release. I am afraid it is liable to change without warning as meeting the milestones rather depends on time available. Green stuff has been coded, but not necessarily released yet. If you have a pressing need for a green but unreleased feature then you should check-out the code from Sourceforge CVS directly.
    FeatureDescriptionRelease
    Unit test case Core test case class and assertions 1.0
    Html display Simplest possible display 1.0
    Autoloading of test cases Reading a file with test cases and loading them into a group test automatically 1.0
    Mock objects Objects capable of simulating other objects removing test dependencies 1.0
    Web test case Allows link following and title tag matching 1.0
    Partial mocks Mocking parts of a class for testing less than a class or for complex simulations 1.0
    Web cookie handling Correct handling of cookies when fetching pages 1.0
    Following redirects Page fetching automatically follows 300 redirects 1.0
    Form parsing Ability to submit simple forms and read default form values 1.0
    Command line interface Test display without the need of a web browser 1.0
    Exposure of expectation classes Can create precise tests with mocks as well as test cases 1.0
    XML output and parsing Allows multi host testing and the integration of acceptance testing extensions 1.0
    Browser component Exposure of lower level web browser interface for more detailed test cases 1.0
    HTTP authentication Fetching protected web pages with basic authentication only 1.0
    SSL support Can connect to https: pages 1.0
    Proxy support Can connect via. common proxies 1.0
    Frames support Handling of frames in web test cases 1.0
    File upload testing Can simulate the input type file tag 1.0.1
    Mocking interfaces Can generate mock objects to interfaces as well as classes and class interfaces are carried for type hints 1.0.1
    Reporting machinery enhancements Improved message passing for better cooperation with IDEs 1.1
    Localisation Messages abstracted and code generated from XML 1.1
    Testing exceptions Similar to testing PHP errors 1.1
    IFrame support Reads IFrame content that can be refreshed 1.1
    Improved mock interface More compact way of expressing mocks 2.0
    HTML table assertions Can match table elements to numerical assertions 2.0
    XPath searching of HTML elements More flexible content matching 2.0
    Alternate HTML parsers Can detect compiled parsers for performance improvements 2.0
    Javascript suport Use of PECL module to add Javascript 3.0
    PHP5 migraton will start straight after the version 1.0.1 series, whereupon PHP4 will no longer be supported. SimpleTest is currently compatible with PHP5, but will not make use of all of the new features until version 2.

    Web resources for testing

    Process is at least as important as tools. The type of process that makes the heaviest use of a developer's testing tool is of course Extreme Programming. This is one of the Agile Methodologies which combine various practices to "flatten the cost curve" of software development. More extreme still is Test Driven Development, where you very strictly adhere to the rule of no coding until you have a test. If you're more of a planner or believe that experience trumps evolution, you may prefer the RUP approach. I haven't tried it, but even I can see that you will need test tools (see figure 9).

    Most unit testers clone JUnit to some degree, as far as the interface at least. There is a wealth of information on the JUnit site including the FAQ which contains plenty of general advice on testing. Once you get bitten by the bug you will certainly appreciate the phrase test infected coined by Eric Gamma. If you are still reviewing which unit tester to use the main choices are PHPUnit and Pear PHP::PHPUnit. They currently lack a lot of features found in SimpleTest, but the PEAR version at least has been upgraded for PHP5 and is recommended if you are porting existing JUnit test cases.

    There is currently a sad lack of material on mock objects, which is a shame as unit testing without them is a lot more work. The original mock objects paper is very Java focused, but still worth a read. As a new technology there are plenty of discussions and debate on how to use mocks, often on Wikis such as Extreme Tuesday or www.mockobjects.com or the original C2 Wiki. Injecting mocks into a class is the main area of debate for which this paper on IBM makes a good starting point.

    There are plenty of web testing tools, but the scriptable ones are mostly are written in Java and tutorials and advice are rather thin on the ground. The only hope is to look at the documentation for HTTPUnit, HTMLUnit or JWebUnit and hope for clues. There are some XML driven test frameworks, but again most require Java to run.

    A new generation of tools that run directly in the web browser are now available. These include Selenium and Watir. As SimpleTest does not support JavaScript you would probably have to look at these tools anyway if you have highly dynamic pages.

    postfixadmin-2.3.7/tests/simpletest/docs/en/docs.css0000664000175000017620000000407711157271050022615 0ustar davidpalepurplebody { padding-left: 3%; padding-right: 3%; } h1, h2, h3 { font-family: sans-serif; } h1 { text-align: center; } pre { font-family: courier, typewriter, monospace; font-size: 90%; border: 1px solid; border-color: #999966; background-color: #ffffcc; padding: 5px; margin-left: 20px; margin-right: 40px; } .code, .new_code, pre.new_code { font-family: courier, typewriter, monospace; font-weight: bold; } div.copyright { font-size: 80%; color: gray; } div.copyright a { margin-top: 1em; color: gray; } ul.api { border: 2px outset; border-color: gray; background-color: white; margin: 5px; margin-left: 5%; margin-right: 5%; } ul.api li { margin-top: 0.2em; margin-bottom: 0.2em; list-style: none; text-indent: -3em; padding-left: 1em; } div.demo { border: 4px ridge; border-color: gray; padding: 10px; margin: 5px; margin-left: 20px; margin-right: 40px; background-color: white; } div.demo span.fail { color: red; } div.demo span.pass { color: green; } div.demo h1 { font-size: 12pt; text-align: left; font-weight: bold; } div.menu { text-align: center; } table { border: 2px outset; border-color: gray; background-color: white; margin: 5px; margin-left: 5%; margin-right: 5%; } td { font-size: 90%; } .shell { color: white; } pre.shell { border: 4px ridge; border-color: gray; padding: 10px; margin: 5px; margin-left: 20px; margin-right: 40px; background-color: #000100; color: #99ff99; font-size: 90%; } pre.file { color: black; border: 1px solid; border-color: black; padding: 10px; margin: 5px; margin-left: 20px; margin-right: 40px; background-color: white; font-size: 90%; } form.demo { background-color: lightgray; border: 4px outset; border-color: lightgray; padding: 10px; margin-right: 40%; } dl, dd { margin: 10px; margin-left: 30px; } em { font-weight: bold; font-family: courier, typewriter, monospace; } postfixadmin-2.3.7/tests/simpletest/docs/en/reporter_documentation.html0000664000175000017620000005037411157271050026635 0ustar davidpalepurple SimpleTest for PHP test runner and display documentation

    Test reporter documentation

    SimpleTest pretty much follows the MVC pattern (Model-View-Controller). The reporter classes are the view and the model is your test cases and their hiearchy. The controller is mostly hidden from the user of SimpleTest unless you want to change how the test cases are actually run, in which case it is possible to override the runner objects from within the test case. As usual with MVC, the controller is mostly undefined and there are other places to control the test run.

    Reporting results in HTML

    The default test display is minimal in the extreme. It reports success and failure with the conventional red and green bars and shows a breadcrumb trail of test groups for every failed assertion. Here's a fail...

    File test

    Fail: createnewfile->True assertion failed.
    1/1 test cases complete. 0 passes, 1 fails and 0 exceptions.
    And here all tests passed...

    File test

    1/1 test cases complete. 1 passes, 0 fails and 0 exceptions.
    The good news is that there are several points in the display hiearchy for subclassing.

    For web page based displays there is the HtmlReporter class with the following signature...

    class HtmlReporter extends SimpleReporter {
        public HtmlReporter($encoding) { ... }
        public makeDry(boolean $is_dry) { ... }
        public void paintHeader(string $test_name) { ... }
        public void sendNoCacheHeaders() { ... }
        public void paintFooter(string $test_name) { ... }
        public void paintGroupStart(string $test_name, integer $size) { ... }
        public void paintGroupEnd(string $test_name) { ... }
        public void paintCaseStart(string $test_name) { ... }
        public void paintCaseEnd(string $test_name) { ... }
        public void paintMethodStart(string $test_name) { ... }
        public void paintMethodEnd(string $test_name) { ... }
        public void paintFail(string $message) { ... }
        public void paintPass(string $message) { ... }
        public void paintError(string $message) { ... }
        public void paintException(string $message) { ... }
        public void paintMessage(string $message) { ... }
        public void paintFormattedMessage(string $message) { ... }
        protected string _getCss() { ... }
        public array getTestList() { ... }
        public integer getPassCount() { ... }
        public integer getFailCount() { ... }
        public integer getExceptionCount() { ... }
        public integer getTestCaseCount() { ... }
        public integer getTestCaseProgress() { ... }
    }
    
    Here is what some of these methods mean. First the display methods that you will probably want to override...
    • HtmlReporter(string $encoding)
      is the constructor. Note that the unit test sets up the link to the display rather than the other way around. The display is a mostly passive receiver of test events. This allows easy adaption of the display for other test systems beside unit tests, such as monitoring servers. The encoding is the character encoding you wish to display the test output in. In order to correctly render debug output when using the web tester, this should match the encoding of the site you are trying to test. The available character set strings are described in the PHP html_entities() function.
    • void paintHeader(string $test_name)
      is called once at the very start of the test when the first start event arrives. The first start event is usually delivered by the top level group test and so this is where $test_name comes from. It paints the page titles, CSS, body tag, etc. It returns nothing (void).
    • void paintFooter(string $test_name)
      Called at the very end of the test to close any tags opened by the page header. By default it also displays the red/green bar and the final count of results. Actually the end of the test happens when a test end event comes in with the same name as the one that started it all at the same level. The tests nest you see. Closing the last test finishes the display.
    • void paintMethodStart(string $test_name)
      is called at the start of each test method. The name normally comes from method name. The other test start events behave the same way except that the group test one tells the reporter how large it is in number of held test cases. This is so that the reporter can display a progress bar as the runner churns through the test cases.
    • void paintMethodEnd(string $test_name)
      backs out of the test started with the same name.
    • void paintFail(string $message)
      paints a failure. By default it just displays the word fail, a breadcrumbs trail showing the current test nesting and the message issued by the assertion.
    • void paintPass(string $message)
      by default does nothing.
    • string _getCss()
      Returns the CSS styles as a string for the page header method. Additional styles have to be appended here if you are not overriding the page header. You will want to use this method in an overriden page header if you want to include the original CSS.
    There are also some accessors to get information on the current state of the test suite. Use these to enrich the display...
    • array getTestList()
      is the first convenience method for subclasses. Lists the current nesting of the tests as a list of test names. The first, most deeply nested test, is first in the list and the current test method will be last.
    • integer getPassCount()
      returns the number of passes chalked up so far. Needed for the display at the end.
    • integer getFailCount()
      is likewise the number of fails so far.
    • integer getExceptionCount()
      is likewise the number of errors so far.
    • integer getTestCaseCount()
      is the total number of test cases in the test run. This includes the grouping tests themselves.
    • integer getTestCaseProgress()
      is the number of test cases completed so far.
    One simple modification is to get the HtmlReporter to display the passes as well as the failures and errors...
    class ShowPasses extends HtmlReporter {
        
        function paintPass($message) {
            parent::paintPass($message);
            print "&<span class=\"pass\">Pass</span>: ";
            $breadcrumb = $this->getTestList();
            array_shift($breadcrumb);
            print implode("-&gt;", $breadcrumb);
            print "-&gt;$message<br />\n";
        }
        
        function _getCss() {
            return parent::_getCss() . ' .pass { color: green; }';
        }
    }
    

    One method that was glossed over was the makeDry() method. If you run this method, with no parameters, on the reporter before the test suite is run no actual test methods will be called. You will still get the events of entering and leaving the test methods and test cases, but no passes or failures etc, because the test code will not actually be executed.

    The reason for this is to allow for more sophistcated GUI displays that allow the selection of individual test cases. In order to build a list of possible tests they need a report on the test structure for drawing, say a tree view of the test suite. With a reporter set to dry run that just sends drawing events this is easily accomplished.

    Extending the reporter

    Rather than simply modifying the existing display, you might want to produce a whole new HTML look, or even generate text or XML. Rather than override every method in HtmlReporter we can take one step up the class hiearchy to SimpleReporter in the simple_test.php source file.

    A do nothing display, a blank canvas for your own creation, would be...

    require_once('simpletest/simple_test.php');
    
    class MyDisplay extends SimpleReporter {
        
        function paintHeader($test_name) {
        }
        
        function paintFooter($test_name) {
        }
        
        function paintStart($test_name, $size) {
            parent::paintStart($test_name, $size);
        }
        
        function paintEnd($test_name, $size) {
            parent::paintEnd($test_name, $size);
        }
        
        function paintPass($message) {
            parent::paintPass($message);
        }
        
        function paintFail($message) {
            parent::paintFail($message);
        }
    }
    
    No output would come from this class until you add it.

    The command line reporter

    SimpleTest also ships with a minimal command line reporter. The interface mimics JUnit to some extent, but paints the failure messages as they arrive. To use the command line reporter simply substitute it for the HTML version...

    <?php
        require_once('simpletest/unit_tester.php');
        require_once('simpletest/reporter.php');
    
        $test = &new GroupTest('File test');
        $test->addTestFile('tests/file_test.php');
        $test->run(new TextReporter());
    ?>
    
    Then invoke the test suite from the command line...
    php file_test.php
    
    You will need the command line version of PHP installed of course. A passing test suite looks like this...
    File test
    OK
    Test cases run: 1/1, Failures: 0, Exceptions: 0
    
    A failure triggers a display like this...
    File test
    1) True assertion failed.
    	in createnewfile
    FAILURES!!!
    Test cases run: 1/1, Failures: 1, Exceptions: 0
    

    One of the main reasons for using a command line driven test suite is of using the tester as part of some automated process. To function properly in shell scripts the test script should return a non-zero exit code on failure. If a test suite fails the value false is returned from the SimpleTest::run() method. We can use that result to exit the script with the desired return code...

    <?php
        require_once('simpletest/unit_tester.php');
        require_once('simpletest/reporter.php');
    
        $test = &new GroupTest('File test');
        $test->addTestFile('tests/file_test.php');
        exit ($test->run(new TextReporter()) ? 0 : 1);
    ?>
    
    Of course we don't really want to create two test scripts, a command line one and a web browser one, for each test suite. The command line reporter includes a method to sniff out the run time environment...
    <?php
        require_once('simpletest/unit_tester.php');
        require_once('simpletest/reporter.php');
    
        $test = &new GroupTest('File test');
        $test->addTestFile('tests/file_test.php');
        if (TextReporter::inCli()) {
            exit ($test->run(new TextReporter()) ? 0 : 1);
        }
        $test->run(new HtmlReporter());
    ?>
    
    This is the form used within SimpleTest itself.

    Remote testing

    SimpleTest ships with an XmlReporter class used for internal communication. When run the output looks like...

    <?xml version="1.0"?>
    <run>
      <group size="4">
        <name>Remote tests</name>
        <group size="4">
          <name>Visual test with 48 passes, 48 fails and 4 exceptions</name>
          <case>
            <name>testofunittestcaseoutput</name>
            <test>
              <name>testofresults</name>
              <pass>This assertion passed</pass>
              <fail>This assertion failed</fail>
            </test>
            <test>
              ...
            </test>
          </case>
        </group>
      </group>
    </run>
    
    You can make use of this format with the parser supplied as part of SimpleTest itself. This is called SimpleTestXmlParser and resides in xml.php within the SimpleTest package...
    <?php
        require_once('simpletest/xml.php');
        
        ...
        $parser = &new SimpleTestXmlParser(new HtmlReporter());
        $parser->parse($test_output);
    ?>
    
    The $test_output should be the XML format from the XML reporter, and could come from say a command line run of a test case. The parser sends events to the reporter just like any other test run. There are some odd occasions where this is actually useful.

    A problem with large test suites is thet they can exhaust the default 8Mb memory limit on a PHP process. By having the test groups output in XML and run in separate processes, the output can be reparsed to aggregate the results into a much smaller footprint top level test.

    Because the XML output can come from anywhere, this opens up the possibility of aggregating test runs from remote servers. A test case already exists to do this within the SimpleTest framework, but it is currently experimental...

    <?php
        require_once('../remote.php');
        require_once('../reporter.php');
        
        $test_url = ...;
        $dry_url = ...;
        
        $test = &new GroupTest('Remote tests');
        $test->addTestCase(new RemoteTestCase($test_url, $dry_url));
        $test->run(new HtmlReporter());
    ?>
    
    The RemoteTestCase takes the actual location of the test runner, basically a web page in XML format. It also takes the URL of a reporter set to do a dry run. This is so that progress can be reported upward correctly. The RemoteTestCase can be added to test suites just like any other group test.

    postfixadmin-2.3.7/tests/simpletest/docs/en/index.html0000664000175000017620000004242111157271050023143 0ustar davidpalepurple Download the Simple Test testing framework - Unit tests and mock objects for PHP

    Simple Test for PHP

    The following assumes that you are familiar with the concept of unit testing as well as the PHP web development language. It is a guide for the impatient new user of SimpleTest. For fuller documentation, especially if you are new to unit testing see the ongoing documentation, and for example test cases see the unit testing tutorial.

    Using the tester quickly

    Amongst software testing tools, a unit tester is the one closest to the developer. In the context of agile development the test code sits right next to the source code as both are written simultaneously. In this context SimpleTest aims to be a complete PHP developer test solution and is called "Simple" because it should be easy to use and extend. It wasn't a good choice of name really. It includes all of the typical functions you would expect from JUnit and the PHPUnit ports, but also adds mock objects. It has some JWebUnit functionality as well. This includes web page navigation, cookie testing and form submission.

    The quickest way to demonstrate is with an example.

    Let us suppose we are testing a simple file logging class called Log in classes/log.php. We start by creating a test script which we will call tests/log_test.php and populate it as follows...

    <?php
    require_once('simpletest/unit_tester.php');
    require_once('simpletest/reporter.php');
    require_once('../classes/log.php');
    
    class TestOfLogging extends UnitTestCase {
    }
    ?>
    
    Here the simpletest folder is either local or in the path. You would have to edit these locations depending on where you placed the toolset. The TestOfLogging is our frst test case and it's currently empty.

    Now we have five lines of scaffolding code and still no tests. However from this part on we get return on our investment very quickly. We'll assume that the Log class takes the file name to write to in the constructor and we have a temporary folder in which to place this file...

    <?php
    require_once('simpletest/unit_tester.php');
    require_once('simpletest/reporter.php');
    require_once('../classes/log.php');
    
    class TestOfLogging extends UnitTestCase {
        
        function testCreatingNewFile() {
            @unlink('/temp/test.log');
            $log = new Log('/temp/test.log');
            $this->assertFalse(file_exists('/temp/test.log'));
            $log->message('Should write this to a file');
            $this->assertTrue(file_exists('/temp/test.log'));
        }
    }
    ?>
    
    When a test case runs it will search for any method that starts with the string test and execute that method. We would normally have more than one test method of course. Assertions within the test methods trigger messages to the test framework which displays the result immediately. This immediate response is important, not just in the event of the code causing a crash, but also so that print statements can display their content right next to the test case concerned.

    To see these results we have to actually run the tests. If this is the only test case we wish to run we can achieve it with...

    <?php
    require_once('simpletest/unit_tester.php');
    require_once('simpletest/reporter.php');
    require_once('../classes/log.php');
    
    class TestOfLogging extends UnitTestCase {
        
        function testCreatingNewFile() {
            @unlink('/temp/test.log');
            $log = new Log('/temp/test.log');
            $this->assertFalse(file_exists('/temp/test.log'));
            $log->message('Should write this to a file');
            $this->assertTrue(file_exists('/temp/test.log'));
        }
    }
    
    $test = &new TestOfLogging();
    $test->run(new HtmlReporter());
    ?>
    

    On failure the display looks like this...

    testoflogging

    Fail: testcreatingnewfile->True assertion failed.
    1/1 test cases complete. 1 passes and 1 fails.
    ...and if it passes like this...

    testoflogging

    1/1 test cases complete. 2 passes and 0 fails.
    And if you get this...
    Fatal error: Failed opening required '../classes/log.php' (include_path='') in /home/marcus/projects/lastcraft/tutorial_tests/Log/tests/log_test.php on line 7
    it means you're missing the classes/Log.php file that could look like...
    <?php
    class Log {
        
            function Log($file_path) {
            }
    
    		function message() {
    		}
    }
    ?>;
    

    Building group tests

    It is unlikely in a real application that we will only ever run one test case. This means that we need a way of grouping cases into a test script that can, if need be, run every test in the application.

    Our first step is to strip the includes and to undo our previous hack...

    <?php
    require_once('../classes/log.php');
    
    class TestOfLogging extends UnitTestCase {
        
        function testCreatingNewFile() {
            @unlink('/temp/test.log');
            $log = new Log('/temp/test.log');
            $this->assertFalse(file_exists('/temp/test.log'));
            $log->message('Should write this to a file');
            $this->assertTrue(file_exists('/temp/test.log'));
        }
    }
    ?>
    
    Next we create a new file called tests/all_tests.php and insert the following code...
    <?php
    require_once('simpletest/unit_tester.php');
    require_once('simpletest/reporter.php');
    
    $test = &new GroupTest('All tests');
    $test->addTestFile('log_test.php');
    $test->run(new HtmlReporter());
    ?>
    
    The method GroupTest::addTestFile() will include the test case file and read any new classes created that are descended from SimpleTestCase, of which UnitTestCase is one example. Just the class names are stored for now, so that the test runner can instantiate the class when it works its way through your test suite.

    For this to work properly the test case file should not blindly include any other test case extensions that do not actually run tests. This could result in extra test cases being counted during the test run. Hardly a major problem, but to avoid this inconvenience simply add a SimpleTestOptions::ignore() directive somewhere in the test case file. Also the test case file should not have been included elsewhere or no cases will be added to this group test. This would be a more serious error as if the test case classes are already loaded by PHP the GroupTest::addTestFile() method will not detect them.

    To display the results it is necessary only to invoke tests/all_tests.php from the web server.

    Using mock objects

    Let's move further into the future.

    Assume that our logging class is tested and completed. Assume also that we are testing another class that is required to write log messages, say a SessionPool. We want to test a method that will probably end up looking like this...

    
    class SessionPool {
        ...
        function logIn($username) {
            ...
            $this->_log->message("User $username logged in.");
            ...
        }
        ...
    }
    
    
    In the spirit of reuse we are using our Log class. A conventional test case might look like this...
    
    <?php
    require_once('../classes/log.php');
    require_once('../classes/session_pool.php');
    
    class TestOfSessionLogging extends UnitTestCase {
        
        function setUp() {
            @unlink('/temp/test.log');
        }
        
        function tearDown() {
            @unlink('/temp/test.log');
        }
        
        function testLogInIsLogged() {
            $log = new Log('/temp/test.log');
            $session_pool = &new SessionPool($log);
            $session_pool->logIn('fred');
            $messages = file('/temp/test.log');
            $this->assertEqual($messages[0], "User fred logged in.\n");
        }
    }
    ?>
    
    This test case design is not all bad, but it could be improved. We are spending time fiddling with log files which are not part of our test. Worse, we have created close ties with the Log class and this test. What if we don't use files any more, but use ths syslog library instead? Did you notice the extra carriage return in the message? Was that added by the logger? What if it also added a time stamp or other data?

    The only part that we really want to test is that a particular message was sent to the logger. We reduce coupling if we can pass in a fake logging class that simply records the message calls for testing, but takes no action. It would have to look exactly like our original though.

    If the fake object doesn't write to a file then we save on deleting the file before and after each test. We could save even more test code if the fake object would kindly run the assertion for us.

    Too good to be true? Luckily we can create such an object easily...
    <?php
    require_once('../classes/log.php');
    require_once('../classes/session_pool.php');
    Mock::generate('Log');
    
    class TestOfSessionLogging extends UnitTestCase {
        
        function testLogInIsLogged() {
            $log = &new MockLog();
            $log->expectOnce('message', array('User fred logged in.'));
            $session_pool = &new SessionPool($log);
            $session_pool->logIn('fred');
        }
    }
    ?>
    
    The test will be triggered when the call to message() is invoked on the MockLog object. The mock call will trigger a parameter comparison and then send the resulting pass or fail event to the test display. Wildcards can be included here too so as to prevent tests becoming too specific.

    If the mock reaches the end of the test case without the method being called, the expectOnce() expectation will trigger a test failure. In other words the mocks can detect the absence of behaviour as well as the presence.

    The mock objects in the SimpleTest suite can have arbitrary return values set, sequences of returns, return values selected according to the incoming arguments, sequences of parameter expectations and limits on the number of times a method is to be invoked.

    For this test to run the mock objects library must have been included in the test suite, say in all_tests.php.

    Web page testing

    One of the requirements of web sites is that they produce web pages. If you are building a project top-down and you want to fully integrate testing along the way then you will want a way of automatically navigating a site and examining output for correctness. This is the job of a web tester.

    The web testing in SimpleTest is fairly primitive, there is no JavaScript for example. To give an idea here is a trivial example where a home page is fetched, from which we navigate to an "about" page and then test some client determined content.

    <?php
    require_once('simpletest/web_tester.php');
    require_once('simpletest/reporter.php');
    
    class TestOfAbout extends WebTestCase {
        
        function setUp() {
            $this->get('http://test-server/index.php');
            $this->click('About');
        }
        
        function testSearchEngineOptimisations() {
            $this->assertTitle('A long title about us for search engines');
            $this->assertPattern('/a popular keyphrase/i');
        }
    }
    $test = &new TestOfAbout();
    $test->run(new HtmlReporter());
    ?>
    
    With this code as an acceptance test you can ensure that the content always meets the specifications of both the developers and the other project stakeholders.

    SourceForge.net Logo

    postfixadmin-2.3.7/tests/simpletest/docs/onpk/0000775000175000017620000000000012301477470021516 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/docs/onpk/README0000664000175000017620000000012311157271050022364 0ustar davidpalepurpleRpertoire utilis pour l'extraction de la documentation au format du site onpk.netpostfixadmin-2.3.7/tests/simpletest/docs/pkg/0000775000175000017620000000000012301477470021330 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/docs/pkg/README0000664000175000017620000000006111157271050022177 0ustar davidpalepurpleFiles here are generated from make_phpdoc_docs.shpostfixadmin-2.3.7/tests/simpletest/docs/source/0000775000175000017620000000000012301477470022047 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/docs/source/en/0000775000175000017620000000000012301477470022451 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/docs/source/en/download_website.xml0000664000175000017620000000611611157271050026522 0ustar davidpalepurple Downloading SimpleTest

    The current release is : SimpleTest v1.0.1beta.

    You can download this version from SourceForget.net and your local mirror. You may also want to look at the current changelog.

    By the way, don't be scared away by the beta tag : quite a few users actually use SimpleTest straight from CVS.

    If eclipse is your IDE / editor of choice, you might consider the Eclipse plugin.

    For automatic "find and install", the URL is :

    http://simpletest.org/eclipse/

    SimpleTest has been packaged by the community to different flavours.

    Note : careful, some versions are not always up-to-date.

    The source code is hosted on Sourceforge as well : you can browse the CVS repository there.

    Current release Eclipse release Packages Source Older stable releases SimpleTest, download, source code, stable release, eclipse release, eclipse plugin, debian package, drupal module, pear channel, pearified package
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/index.xml0000664000175000017620000002424611157271050024304 0ustar davidpalepurple The Last Craft? Web developer tutorials on PHP, Extreme programming and Object Oriented development

    This site focuses mostly on developing with lightweight web technologies such as PHP, especially when applied with agile methodologies such as XP. No guarantee of quality is given or even intended. It is hoped only that what you find gives you ideas and enthusiasm from a fellow computer programmer.

    I've been a little busy of late with children (two versions). They take quite a chunk of your professional life and 100% of what's left! Hopefully the projects below should start to get back on track.

    My latest project is Cgreen. It's a C unit tester. There are a couple of C unit testing tools out there already of course. What makes Cgreen different is that it is pure C99, includes a tutorial right here and has facilities for creating mock functions. Mock functions should lead to more decoupled C code if Mock objects are anything to go by. It's alpha status right now until I get feedback from other users. So if you want to be influential, try it out right now. The project has been mostly funded by Wordtracker, for which I am very grateful.

    Along with Jon Ramsey, I am a founder of PHP London, a PHP user group not surprisingly based in London. It's going well. The networking meetings take place on the first Thursday of every month at a pub.

    In addition the group organises other events that include the 2nd London UK PHP Conference. This is a one day event on Friday the 23rd of February 2007 and costs only fifty quid.

    The SimpleTest PHP unit tester is available for download from your nearest SourceForge. It is a PHP unit test and web test framework. Users of JUnit will be familiar with most of the interface. The JWebUnit style functionality is more complete now. It has support for SSL, forms, frames, proxies and basic authentication. The current CVS code should become the 1.0.1 release real soon now and includes file upload and many small improvements. The idea is that common but fiddly PHP tasks, such as logging into a site, can be tested easily.

    My most neglected project right now is a requirents testing and sign-off tool called Arbiter. It's actually best described in this Sitepoint thread, but basically think of it as a document driven FIT for small web projects only. The project is currently stalled due the birth of children and writing projects.

    Also on the subject of open source, Wordtracker have kindly agreed to publish some of their in house tools. A Wordtracker spin off is fakeMail. Testing applications that send e-mails can be a right royal pain because of all of the infrastructure involved. You will likely need an SMPT gateway that talks to a POP client that you can read the queue from. That's a lot of set up. Fakemail acts as an SMTP gateway on any port you define. When you send it a mail it simply copies that mail to the local file system in whatever directory you want. You then just have to look at the local file. It means that you must be able to configure your application to use a port other than 25, but that's not usualy difficult.

    A craft is defined as...

    Art or skill; dexterity in particular manual employment; hence, the occupation or employment itself; manual art; a trade.

    If you lose a screw or clasp from a hand made jewellery box it is hopeless to try to find a replacement. Nothing else is quite the same and the mechanism will fail to work. It may even cause more damage when applied. You need to find the original maker or someone of the same skill to make you another. Sound like software? Yet mechanical parts today are interchangeable.

    Writing software has resisted mass production. As soon as a part of it becomes routine it can be automated. Once it is you don't need a programmer any more. Routine programming jobs no longer exist. All that is left is the unsolved problems that require a higher level of skill in constructing their solutions.

    This dependency on the ability of the artisan, combined with nothing quite fitting together properly, is what gives software the pre-industrial feel.

    The panel at the top is supposed to resemble a standard office index card. The way it is marked out is called a CRC card. It stands for Classes, Responsibilities and Collaborations and is the cheapest software development tool you can find. You really do buy a pack of cards.

    The role is written at the top and would often be just a class name. The left side is the object's responsibilities and on the right collaborations (within the page I have treated these as internal links and external links repectively). A group of developers can point at, discuss and discard cards in the heat of design session. It makes it especially difficult for only one person to take charge of a discussion in the way you can with a UML tool or notepad. Try scribbling out five cards before someone gets a look in.

    Now nothing beats a whiteboard for collaboration, but if the level of detail is getting too high and you want a temporary record, give the CRC cards a try.

    Projects under development. All free and open source software. Why Last Craft? Odd name isn't it? Why this index card at the top? SimpleTest is a PHP unit test framework. My article on TDD My article on the Registry Pattern. Site E-mail is SpamCop filtered which I cannot recommend enough. software development, computer programmer, php programming, programming php, software development tools, software development company, php tutorial, free php scripts, bespoke software development uk, corporate web development, architecture, php resources, wordtracker, xslt, java, bug tracker, bug reporting, unit test, php testing, test cases tutorial, explain unit test case, unit test example, xml A web site of software development tutorials and examples with an emphasis on web programming, testing, agile methodology and PHP development
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/books_website.xml0000664000175000017620000000702711157271050026032 0ustar davidpalepurple Books in and around SimpleTest

    From time to time a book is recommanded on the mailing-list, you can find it here with the original comments !

    Domain-Driven Design: Tackling Complexity in the Heart of Software

    TDD is a lot about the mechanics of coding, but it says you are done when there is no duplication. DDD considers the code in constant churn, always renaming as the domain becomes clear and also feeding terms back into the domain as the code evolves.

    Anyways, it's a great book :) [source]

    Two of SimpleTest contributors have written books about PHP. Both have a lot of examples with the SimpleTest Unit testing framework.

    PHP|Architect's Guide to PHP Design Patterns
    PHP|Architect's Guide to PHP Design Patterns
    by Jason E. Sweat
    (get it from : PHP|Architect | Amazon )

    The PHP Anthology: Object Oriented PHP Solutions
    The PHP Anthology: Object Oriented PHP Solutions
    by Harry Fuecks
    (get it from : SitePoint | Amazon | review on Slashdot )

    One way to help the team of contributors is to buy books from this page through Amazon (with the simpletest-21 tag). We all love reading stuff that's both interesting and challenging.

    Latest recommandation Books by contributors Buying books
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/mock_objects_tutorial.xml0000664000175000017620000003366211157271050027564 0ustar davidpalepurple PHP unit testing tutorial - Using mock objects in PHP

    Refactoring the tests again

    Before more functionality is added there is some refactoring to do. We are going to do some timing tests and so the TimeTestCase class definitely needs its own file. Let's say tests/time_test_case.php... UnitTestCase($test_name); } function assertSameTime($time1, $time2, $message = '') { if (! $message) { $message = "Time [$time1] should match time [$time2]"; } $this->assertTrue( ($time1 == $time2) || ($time1 + 1 == $time2), $message); } } ?> ]]> We can then require() this file into the all_tests.php script.

    Adding a timestamp to the Log

    I don't know quite what the format of the log message should be for the test, so to check for a timestamp we could do the simplest possible thing, which is to look for a sequence of digits. require_once('../classes/clock.php'); class TestOfLogging extends TimeTestCase { function TestOfLogging() { $this->TimeTestCase('Log class test'); } function setUp() { @unlink('../temp/test.log'); } function tearDown() { @unlink('../temp/test.log'); } function getFileLine($filename, $index) { $messages = file($filename); return $messages[$index]; } function testCreatingNewFile() { ... } function testAppendingToFile() { ... } function testTimestamps() { $log = new Log('../temp/test.log'); $log->message('Test line'); $this->assertTrue( preg_match('/(\d+)/', $this->getFileLine('../temp/test.log', 0), $matches), 'Found timestamp'); $clock = new clock(); $this->assertSameTime((integer)$matches[1], $clock->now(), 'Correct time'); } } ?> ]]> The test case creates a new Log object and writes a message. We look for a digit sequence and then test it against the current time using our Clock object. Of course it doesn't work until we write the code.

    All tests

    Pass: log_test.php->Log class test->testappendingtofile->Expecting [/Test line 1/] in [Test line 1]
    Pass: log_test.php->Log class test->testappendingtofile->Expecting [/Test line 2/] in [Test line 2]
    Pass: log_test.php->Log class test->testcreatingnewfile->Created before message
    Pass: log_test.php->Log class test->testcreatingnewfile->File created
    Fail: log_test.php->Log class test->testtimestamps->Found timestamp

    Notice: Undefined offset: 1 in /home/marcus/projects/lastcraft/tutorial_tests/tests/log_test.php on line 44
    Fail: log_test.php->Log class test->testtimestamps->Correct time
    Pass: clock_test.php->Clock class test->testclockadvance->Advancement
    Pass: clock_test.php->Clock class test->testclocktellstime->Now is the right time
    3/3 test cases complete. 6 passes and 2 fails.
    The test suite is still showing the passes from our earlier modification.

    We can get the tests to pass simply by adding a timestamp when writing out to the file. Yes, of course all of this is trivial and I would not normally test this fanatically, but it is going to illustrate a more general problem. The log.php file becomes... require_once('../classes/clock.php'); class Log { var $_file_path; function Log($file_path) { $this->_file_path = $file_path; } function message($message) { $clock = new Clock(); $file = fopen($this->_file_path, 'a'); fwrite($file, "[" . $clock->now() . "] $message\n"); fclose($file); } } ?> ]]> The tests should now pass.

    Our new test is full of problems, though. What if our time format changes to something else? Things are going to be a lot more complicated to test if this happens. It also means that any changes to the clock class time format will cause our logging tests to fail also. This means that our log tests are tangled up with the clock tests and extremely fragile. It lacks cohesion, which is the same as saying it is not tightly focused, testing facets of the clock as well as the log. Our problems are caused in part because the clock output is unpredictable when all we really want to test is that the logging message contains the output of Clock::now(). We don't really care about the contents of that method call.

    Can we make that call predictable? We could if we could get the log to use a dummy version of the clock for the duration of the test. The dummy clock class would have to behave the same way as the Clock class except for the fixed output from the now() method. Hey, that would even free us from using the TimeTestCase class!

    We could write such a class pretty easily although it is rather tedious work. We just create another clock class with same interface except that the now() method returns a value that we can change with some other setter method. That is quite a lot of work for a pretty minor test.

    Except that it is really no work at all.

    A mock clock

    To reach instant testing clock nirvana we need only three extra lines of code... This includes the mock generator code. It is simplest to place this in the all_tests.php script as it gets used rather a lot. This is the line that does the work. The code generator scans the class for all of its methods, creates code to generate an identically interfaced class, but with the name "Mock" added, and then eval()s the new code to create the new class. This line can be added to any test method we are interested in. It creates the dummy clock ready to receive our instructions.

    Our test case is on the first steps of a radical clean up... Mock::generate('Clock'); class TestOfLogging extends UnitTestCase { function TestOfLogging() { $this->UnitTestCase('Log class test'); } function setUp() { @unlink('../temp/test.log'); } function tearDown() { @unlink('../temp/test.log'); } function getFileLine($filename, $index) { $messages = file($filename); return $messages[$index]; } function testCreatingNewFile() { ... } function testAppendingToFile() { ... } function testTimestamps() { $clock = &new MockClock($this); $clock->setReturnValue('now', 'Timestamp'); $log = new Log('../temp/test.log'); $log->message('Test line', &$clock); $this->assertWantedPattern( '/Timestamp/', $this->getFileLine('../temp/test.log', 0), 'Found timestamp'); } } ?> ]]> This test method creates a MockClock object and then sets the return value of the now() method to be the string "Timestamp". Every time we call $clock->now() it will return this string. This should be easy to spot.

    Next we create our log and send a message. We pass into the message() call the clock we would like to use. This means that we will have to add an optional parameter to the logging class to make testing possible... _file_path = $file_path; } function message($message, $clock = false) { if (!is_object($clock)) { $clock = new Clock(); } $file = fopen($this->_file_path, 'a'); fwrite($file, "[" . $clock->now() . "] $message\n"); fclose($file); } } ]]> All of the tests now pass and they test only the logging code. We can breathe easy again.

    Does that extra parameter in the Log class bother you? We have changed the interface just to facilitate testing after all. Are not interfaces the most important thing? Have we sullied our class with test code?

    Possibly, but consider this. Next chance you get, look at a circuit board, perhaps the motherboard of the computer you are looking at right now. On most boards you will find the odd empty hole, or solder joint with nothing attached or perhaps a pin or socket that has no obvious function. Chances are that some of these are for expansion and variations, but most of the remainder will be for testing.

    Think about that. The factories making the boards many times over wasting material on parts that do not add to the final function. If hardware engineers can make this sacrifice of elegance I am sure we can too. Our sacrifice wastes no materials after all.

    Still bother you? Actually it bothers me too, but not so much here. The number one priority is code that works, not prizes for minimalism. If it really bothers you, then move the creation of the clock into another protected factory method. Then subclass the clock for testing and override the factory method with one that returns the mock. Your tests are clumsier, but your interface is intact.

    Again I leave the decision to you.

    Refactoring the tests so we can reuse our new time test. Adding Log timestamps. Mocking the clock to make the test cohesive. This follows the unit test tutorial. Next is distilling boundary classes. You will need the SimpleTest tool to run the examples. Mock objects papers. software development, php programming, programming php, software development tools, php tutorial, free php scripts, architecture, php resources, mock objects, junit, php testing, unit test, php testing
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/about.xml0000664000175000017620000001101711157271050024277 0ustar davidpalepurple About Last Craft

    At the moment this site is maintained by myself, Marcus Baker and I am an Object Oriented web developer and father of two. I am currently a freelancer working as a senior developer for Wordtracker and as a consultant to various smaller companies. Wordtracker is an internet statistics company with a huge database of search engine keyword popularity. The company software development is eXtreme Programming based.

    My wife Aviva Racher is a microbiologist and Mother of the same two.

    Bryn was born on the 30th of July 2004. He is doing very well.

    Read the interview Who's really being protected? on the O'Reilly network if you have an interest in software patents.

    Besides working for Wordtracker, I also act as an independent consultant. Usually in relation to bringing agile development practices into an organisation. Clients include Waterscape and Amnesty International.

    I did a quick site for a graphic designer and illustrator friend of mine, Dylan Beck. He has a very unique style.

    The Ambassadors of Om are a Jazz-Funk fusion (?) band with an internet presence going back over five years. Site includes samples, videos and links. The band is managed by guitarist and lead singer Paul Grimes who is a friend of ours.

    Mark Eichner is Aviva's uncle and run's the Leisure Pursuits off-road driving school. Lots of wheels and mud!

    Last Craft people Myself and friends and relations. Issues that I care about. Associated companies and people. Extreme Tuesday Club is an informal meeting in London to promote Extreme programming. PHPLondon is a user group that meets the first thursday of every month. Wordtracker crunches internet search data for web marketing. software development, computer programmer, php programming, programming php, software development company, software development uk, php tutorial, bespoke software development uk, corporate web development, architecture, freelancer, php resources, wordtracker, web marketing, serach engines, web positioning, internet marketing
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/form_testing_documentation.xml0000664000175000017620000002456611157271050030633 0ustar davidpalepurple Simple Test documentation for testing HTML forms

    When a page is fetched by the WebTestCase using get() or post() the page content is automatically parsed. This results in any form controls that are inside <form> tags being available from within the test case. For example, if we have this snippet of HTML...

    
        
        
    
    ]]>
    Which looks like this...

    We can navigate to this code, via the LastCraft site, with the following test... function testDefaultValue() { $this->get('http://www.lastcraft.com/form_testing_documentation.php'); $this->assertField('a', 'A default'); } } ]]> Immediately after loading the page all of the HTML controls are set at their default values just as they would appear in the web browser. The assertion tests that a HTML widget exists in the page with the name "a" and that it is currently set to the value "A default". As usual, we could use a pattern expectation instead if a fixed string.

    We could submit the form straight away, but first we'll change the value of the text field and only then submit it... get('http://www.my-site.com/'); $this->assertField('a', 'A default'); $this->setField('a', 'New value'); $this->click('Go'); } } ]]> Because we didn't specify a method attribute on the form tag, and didn't specify an action either, the test case will follow the usual browser behaviour of submitting the form data as a GET request back to the same location. SimpleTest tries to emulate typical browser behaviour as much as possible, rather than attempting to catch missing attributes on tags. This is because the target of the testing framework is the PHP application logic, not syntax or other errors in the HTML code. For HTML errors, other tools such as HTMLTidy should be used.

    If a field is not present in any form, or if an option is unavailable, then WebTestCase::setField() will return false. For example, suppose we wish to verify that a "Superuser" option is not present in this form...

    Select type of user to add:
    
    ]]>
    Which looks like...

    Select type of user to add:

    The following test will confirm it... $this->get('http://www.lastcraft.com/form_testing_documentation.php'); $this->assertFalse($this->setField('type', 'Superuser')); } } ]]> The selection will not be changed on a failure to set a widget value.

    Here is the full list of widgets currently supported...

    • Text fields, including hidden and password fields.
    • Submit buttons including the button tag, although not yet reset buttons
    • Text area. This includes text wrapping behaviour.
    • Checkboxes, including multiple checkboxes in the same form.
    • Drop down selections, including multiple selects.
    • Radio buttons.
    • Images.

    Although most standard HTML widgets are catered for by SimpleTest's built in parser, it is unlikely that JavaScript will be implemented anytime soon.

    SimpleTest can cope with two types of multivalue controls: Multiple selection drop downs, and multiple checkboxes with the same name within a form. The multivalue nature of these means that setting and testing are slightly different. Using checkboxes as an example...

    
        Create privileges allowed:
        
    Retrieve privileges allowed:
    Update privileges allowed:
    Destroy privileges allowed:
    ]]>
    Which renders as...

    Create privileges allowed:
    Retrieve privileges allowed:
    Update privileges allowed:
    Destroy privileges allowed:

    If we wish to disable all but the retrieval privileges and submit this information we can do it like this... function testDisableNastyPrivileges() { $this->get('http://www.lastcraft.com/form_testing_documentation.php'); $this->assertField('crud', array('c', 'r', 'u', 'd')); $this->setField('crud', array('r')); $this->click('Enable Privileges'); } } ]]> Instead of setting the field to a single value, we give it a list of values. We do the same when testing expected values. We can then write other test code to confirm the effect of this, perhaps by logging in as that user and attempting an update.

    Raw posting

    If you want to test a form handler, but have not yet written or do not have access to the form itself, you can create a form submission by hand. function testAttemptedHack() { $this->post( 'http://www.my-site.com/add_user.php', array('type' => 'superuser')); $this->assertNoText('user created'); } } ]]> By adding data to the WebTestCase::post() method, we are attempting to fetch the page as a form submission.

    Changing form values and successfully Submitting a simple form Handling widgets with multiple values by setting lists. Raw posting when you don't have a button to click. SimpleTest project page on SourceForge. SimpleTest download page on LastCraft. The developer's API for SimpleTest gives full detail on the classes and assertions available. software development, php programming for clients, customer focused php, software development tools, acceptance testing framework, free php scripts, architecture, php resources, HTMLUnit, JWebUnit, php testing, unit test resource, web testing
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/unit_test_documentation.xml0000664000175000017620000003236111157271050030141 0ustar davidpalepurple SimpleTest for PHP regression test documentation

    The core system is a regression testing framework built around test cases. A sample test case looks like this... class FileTestCase extends UnitTestCase { } ]]> Actual tests are added as methods in the test case whose names by default start with the string "test" and when the test case is invoked all such methods are run in the order that PHP introspection finds them. As many test methods can be added as needed.

    For example... UnitTestCase('File test'); } function setUp() { @unlink('../temp/test.txt'); } function tearDown() { @unlink('../temp/test.txt'); } function testCreation() { $writer = &new FileWriter('../temp/test.txt'); $writer->write('Hello'); $this->assertTrue(file_exists('../temp/test.txt'), 'File created'); } } ]]> The constructor is optional and usually omitted. Without a name, the class name is taken as the name of the test case.

    Our only test method at the moment is testCreation() where we check that a file has been created by our Writer object. We could have put the unlink() code into this method as well, but by placing it in setUp() and tearDown() we can use it with other test methods that we add.

    The setUp() method is run just before each and every test method. tearDown() is run just after each and every test method.

    You can place some test case set up into the constructor to be run once for all the methods in the test case, but you risk test inteference that way. This way is slightly slower, but it is safer. Note that if you come from a JUnit background this will not be the behaviour you are used to. JUnit surprisingly reinstantiates the test case for each test method to prevent such interference. SimpleTest requires the end user to use setUp(), but supplies additional hooks for library writers.

    The means of reporting test results (see below) are by a visiting display class that is notified by various assert...() methods. Here is the full list for the UnitTestCase class, the default for SimpleTest...
    assertTrue($x)Fail if $x is false
    assertFalse($x)Fail if $x is true
    assertNull($x)Fail if $x is set
    assertNotNull($x)Fail if $x not set
    assertIsA($x, $t)Fail if $x is not the class or type $t
    assertNotA($x, $t)Fail if $x is of the class or type $t
    assertEqual($x, $y)Fail if $x == $y is false
    assertNotEqual($x, $y)Fail if $x == $y is true
    assertWithinMargin($x, $y, $m)Fail if abs($x - $y) < $m is false
    assertOutsideMargin($x, $y, $m)Fail if abs($x - $y) < $m is true
    assertIdentical($x, $y)Fail if $x == $y is false or a type mismatch
    assertNotIdentical($x, $y)Fail if $x == $y is true and types match
    assertReference($x, $y)Fail unless $x and $y are the same variable
    assertClone($x, $y)Fail unless $x and $y are identical copies
    assertPattern($p, $x)Fail unless the regex $p matches $x
    assertNoPattern($p, $x)Fail if the regex $p matches $x
    expectError($x)Swallows any upcoming matching error
    assert($e)Fail on failed expectation object $e
    All assertion methods can take an optional description as a last parameter. This is to label the displayed result with. If omitted a default message is sent instead, which is usually sufficient. This default message can still be embedded in your own message if you include "%s" within the string. All the assertions return true on a pass or false on failure.

    Some examples... $this->assertNull($variable, 'Should be cleared'); ]]> ...will pass and normally show no message. If you have set up the tester to display passes as well then the message will be displayed as is. $this->assertIdentical(0, false, 'Zero is not false [%s]'); ]]> This will fail as it performs a type check, as well as a comparison, between the two values. The "%s" part is replaced by the default error message that would have been shown if we had not supplied our own. $this->assertReference($a, $b); ]]> Will fail as the variable $a is a copy of $b. $this->assertPattern('/hello/i', 'Hello world'); ]]> This will pass as using a case insensitive match the string hello is contained in Hello world. $this->expectError(); trigger_error('Catastrophe'); ]]> Here the check catches the "Catastrophe" message without checking the text and passes. This removes the error from the queue. $this->expectError('Catastrophe'); trigger_error('Catastrophe'); ]]> The next error check tests not only the existence of the error, but also the text which, here matches so another pass. If any unchecked errors are left at the end of a test method then an exception will be reported in the test.

    Note that SimpleTest cannot catch compile time PHP errors.

    The test cases also have some convenience methods for debugging code or extending the suite...
    setUp()Runs this before each test method
    tearDown()Runs this after each test method
    pass()Sends a test pass
    fail()Sends a test failure
    error()Sends an exception event
    signal($type, $payload)Sends a user defined message to the test reporter
    dump($var)Does a formatted print_r() for quick and dirty debugging

    Of course additional test methods can be added to create specific types of test case, so as to extend framework... class FileTester extends UnitTestCase { function FileTester($name = false) { $this->UnitTestCase($name); } function assertFileExists($filename, $message = '%s') { $this->assertTrue( file_exists($filename), sprintf($message, 'File [$filename] existence check')); } } ]]> Here the SimpleTest library is held in a folder called simpletest that is local. Substitute your own path for this.

    To prevent this test case being run accidently, it is advisable to mark it as abstract.

    This new case can be now be inherited just like a normal test case... FileTester { function setUp() { @unlink('../temp/test.txt'); } function tearDown() { @unlink('../temp/test.txt'); } function testCreation() { $writer = &new FileWriter('../temp/test.txt'); $writer->write('Hello'); $this->assertFileExists('../temp/test.txt'); } } ]]>

    If you want a test case that does not have all of the UnitTestCase assertions, only your own and a few basics, you need to extend the SimpleTestCase class instead. It is found in simple_test.php rather than unit_tester.php. See later if you want to incorporate other unit tester's test cases in your test suites.

    You won't often run single test cases except when bashing away at a module that is having difficulty, and you don't want to upset the main test suite. Here is the scaffolding needed to run a lone test case... require_once('simpletest/reporter.php'); require_once('../classes/writer.php'); class FileTestCase extends UnitTestCase { function FileTestCase() { $this->UnitTestCase('File test'); } } $test = &new FileTestCase(); $test->run(new HtmlReporter()); ?> ]]> This script will run as is, but of course will output zero passes and zero failures until test methods are added.

    Unit test cases and basic assertions. Extending test cases to customise them for your own project. Running a single case as a single script. SimpleTest project page on SourceForge. SimpleTest download page on LastCraft. Full API for SimpleTest from the PHPDoc. php unit testing, test integration, documentation, marcus baker, simple test, simpletest documentation, phpunit, junit, xunit, agile web development, eXtreme Programming, Test Driven, TDD
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/web_tester_documentation.xml0000664000175000017620000004605711157271050030275 0ustar davidpalepurple Simple Test for PHP web script testing documentation

    Testing classes is all very well, but PHP is predominately a language for creating functionality within web pages. How do we test the front end presentation role of our PHP applications? Well the web pages are just text, so we should be able to examine them just like any other test data.

    This leads to a tricky issue. If we test at too low a level, testing for matching tags in the page with pattern matching for example, our tests will be brittle. The slightest change in layout could break a large number of tests. If we test at too high a level, say using mock versions of a template engine, then we lose the ability to automate some classes of test. For example, the interaction of forms and navigation will have to be tested manually. These types of test are extremely repetitive and error prone.

    SimpleTest includes a special form of test case for the testing of web page actions. The WebTestCase includes facilities for navigation, content and cookie checks and form handling. Usage of these test cases is similar to the UnitTestCase... class TestOfLastcraft extends WebTestCase { } ]]> Here we are about to test the Last Craft site itself. If this test case is in a file called lastcraft_test.php then it can be loaded in a runner script just like unit tests... require_once('simpletest/web_tester.php'); require_once('simpletest/reporter.php'); $test = &new TestSuite('Web site tests'); $test->addTestFile('lastcraft_test.php'); exit ($test->run(new TextReporter()) ? 0 : 1); ?> ]]> I am using the text reporter here to more clearly distinguish the web content from the test output.

    Nothing is being tested yet. We can fetch the home page by using the get() method... function testHomepage() { $this->assertTrue($this->get('http://www.lastcraft.com/')); } } ]]> The get() method will return true only if page content was successfully loaded. It is a simple, but crude way to check that a web page was actually delivered by the web server. However that content may be a 404 response and yet our get() method will still return true.

    Assuming that the web server for the Last Craft site is up (sadly not always the case), we should see...

    Web site tests
    OK
    Test cases run: 1/1, Failures: 0, Exceptions: 0
    
    All we have really checked is that any kind of page was returned. We don't yet know if it was the right one.

    To confirm that the page we think we are on is actually the page we are on, we need to verify the page content. $this->get('http://www.lastcraft.com/'); $this->assertText('Why the last craft'); } } ]]> The page from the last fetch is held in a buffer in the test case, so there is no need to refer to it directly. The pattern match is always made against the buffer.

    Here is the list of possible content assertions...
    assertTitle($title)Pass if title is an exact match
    assertText($text)Pass if matches visible and "alt" text
    assertNoText($text)Pass if doesn't match visible and "alt" text
    assertPattern($pattern)A Perl pattern match against the page content
    assertNoPattern($pattern)A Perl pattern match to not find content
    assertLink($label)Pass if a link with this text is present
    assertNoLink($label)Pass if no link with this text is present
    assertLinkById($id)Pass if a link with this id attribute is present
    assertNoLinkById($id)Pass if no link with this id attribute is present
    assertField($name, $value)Pass if an input tag with this name has this value
    assertFieldById($id, $value)Pass if an input tag with this id has this value
    assertResponse($codes)Pass if HTTP response matches this list
    assertMime($types)Pass if MIME type is in this list
    assertAuthentication($protocol)Pass if the current challenge is this protocol
    assertNoAuthentication()Pass if there is no current challenge
    assertRealm($name)Pass if the current challenge realm matches
    assertHeader($header, $content)Pass if a header was fetched matching this value
    assertNoHeader($header)Pass if a header was not fetched
    assertCookie($name, $value)Pass if there is currently a matching cookie
    assertNoCookie($name)Pass if there is currently no cookie of this name
    As usual with the SimpleTest assertions, they all return false on failure and true on pass. They also allow an optional test message and you can embed the original test message inside using "%s" inside your custom message.

    So now we could instead test against the title tag with... $this->assertTitle('The Last Craft? Web developer tutorials on PHP, Extreme programming and Object Oriented development'); ]]> ...or, if that is too long and fragile... $this->assertTitle(new PatternExpectation('/The Last Craft/')); ]]> As well as the simple HTML content checks we can check that the MIME type is in a list of allowed types with... $this->assertMime(array('text/plain', 'text/html')); ]]> More interesting is checking the HTTP response code. Like the MIME type, we can assert that the response code is in a list of allowed values... get('http://www.lastcraft.com/test/redirect.php'); $this->assertResponse(200); } } ]]> Here we are checking that the fetch is successful by allowing only a 200 HTTP response. This test will pass, but it is not actually correct to do so. There is no page, instead the server issues a redirect. The WebTestCase will automatically follow up to three such redirects. The tests are more robust this way and we are usually interested in the interaction with the pages rather than their delivery. If the redirects are of interest then this ability must be disabled... $this->setMaximumRedirects(0); $this->get('http://www.lastcraft.com/test/redirect.php'); $this->assertResponse(200); } } ]]> The assertion now fails as expected...

    Web site tests
    1) Expecting response in [200] got [302]
    	in testhomepage
    	in testoflastcraft
    	in lastcraft_test.php
    FAILURES!!!
    Test cases run: 1/1, Failures: 1, Exceptions: 0
    
    We can modify the test to correctly assert redirects with... setMaximumRedirects(0); $this->get('http://www.lastcraft.com/test/redirect.php'); $this->assertResponse(array(301, 302, 303, 307)); } } ]]> This now passes.

    Users don't often navigate sites by typing in URLs, but by clicking links and buttons. Here we confirm that the contact details can be reached from the home page... get('http://www.lastcraft.com/'); $this->clickLink('About'); $this->assertTitle(new PatternExpectation('/About Last Craft/')); } } ]]> The parameter is the text of the link.

    If the target is a button rather than an anchor tag, then clickSubmit() can be used with the button title... $this->clickSubmit('Go!'); ]]> If you are not sure or don't care, the usual case, then just use the click() method... $this->click('Go!'); ]]>

    The list of navigation methods is...
    getUrl()The current location
    get($url, $parameters)Send a GET request with these parameters
    post($url, $parameters)Send a POST request with these parameters
    head($url, $parameters)Send a HEAD request without replacing the page content
    retry()Reload the last request
    back()Like the browser back button
    forward()Like the browser forward button
    authenticate($name, $password)Retry after a challenge
    restart()Restarts the browser as if a new session
    getCookie($name)Gets the cookie value for the current context
    ageCookies($interval)Ages current cookies prior to a restart
    clearFrameFocus()Go back to treating all frames as one page
    clickSubmit($label)Click the first button with this label
    clickSubmitByName($name)Click the button with this name attribute
    clickSubmitById($id)Click the button with this ID attribute
    clickImage($label, $x, $y)Click an input tag of type image by title or alt text
    clickImageByName($name, $x, $y)Click an input tag of type image by name
    clickImageById($id, $x, $y)Click an input tag of type image by ID attribute
    submitFormById($id)Submit a form without the submit value
    clickLink($label, $index)Click an anchor by the visible label text
    clickLinkById($id)Click an anchor by the ID attribute
    getFrameFocus()The name of the currently selected frame
    setFrameFocusByIndex($choice)Focus on a frame counting from 1
    setFrameFocus($name)Focus on a frame by name

    The parameters in the get(), post() or head() methods are optional. The HTTP HEAD fetch does not change the browser context, only loads cookies. This can be useful for when an image or stylesheet sets a cookie for crafty robot blocking.

    The retry(), back() and forward() commands work as they would on your web browser. They use the history to retry pages. This can be handy for checking the effect of hitting the back button on your forms.

    The frame methods need a little explanation. By default a framed page is treated just like any other. Content will be searced for throughout the entire frameset, so clicking a link will work no matter which frame the anchor tag is in. You can override this behaviour by focusing on a single frame. If you do that, all searches and actions will apply to that frame alone, such as authentication and retries. If a link or button is not in a focused frame then it cannot be clicked.

    Testing navigation on fixed pages only tells you when you have broken an entire script. For highly dynamic pages, such as for bulletin boards, this can be crucial for verifying the correctness of the application. For most applications though, the really tricky logic is usually in the handling of forms and sessions. Fortunately SimpleTest includes tools for testing web forms as well.

    Although SimpleTest does not have the goal of testing networking problems, it does include some methods to modify and debug the requests it makes. Here is another method list...
    getTransportError()The last socket error
    showRequest()Dump the outgoing request
    showHeaders()Dump the incoming headers
    showSource()Dump the raw HTML page content
    ignoreFrames()Do not load framesets
    setCookie($name, $value)Set a cookie from now on
    addHeader($header)Always add this header to the request
    setMaximumRedirects($max)Stop after this many redirects
    setConnectionTimeout($timeout)Kill the connection after this time between bytes
    useProxy($proxy, $name, $password)Make requests via this proxy URL
    These methods are principally for debugging.

    Successfully fetching a web page Testing the page content Navigating a web site while testing Raw request modifications and debugging methods SimpleTest project page on SourceForge. SimpleTest download page on LastCraft. The developer's API for SimpleTest gives full detail on the classes and assertions available. software development, php programming for clients, customer focused php, software development tools, acceptance testing framework, free php scripts, architecture, php resources, HTMLUnit, JWebUnit, php testing, unit test resource, web testing
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/browser_documentation.xml0000664000175000017620000003550611157271050027612 0ustar davidpalepurple SimpleTest documentation for the scriptable web browser component

    SimpleTest's web browser component can be used not just outside of the WebTestCase class, but also independently of the SimpleTest framework itself.

    You can use the web browser in PHP scripts to confirm services are up and running, or to extract information from them at a regular basis. For example, here is a small script to extract the current number of open PHP 5 bugs from the PHP web site... get('http://php.net/'); $browser->click('reporting bugs'); $browser->click('statistics'); $page = $browser->click('PHP 5 bugs only'); preg_match('/status=Open.*?by=Any.*?(\d+)<\/a>/', $page, $matches); print $matches[1]; ?> ]]> There are simpler methods to do this particular example in PHP of course. For example you can just use the PHP file() command against what here is a pretty fixed page. However, using the web browser for scripts allows authentication, correct handling of cookies, automatic loading of frames, redirects, form submission and the ability to examine the page headers. Such methods are fragile against a site that is constantly evolving and you would want a more direct way of accessing data in a permanent set up, but for simple tasks this can provide a very rapid solution.

    All of the navigation methods used in the WebTestCase are present in the SimpleBrowser class, but the assertions are replaced with simpler accessors. Here is a full list of the page navigation methods...
    addHeader($header)Adds a header to every fetch
    useProxy($proxy, $username, $password)Use this proxy from now on
    head($url, $parameters)Perform a HEAD request
    get($url, $parameters)Fetch a page with GET
    post($url, $parameters)Fetch a page with POST
    clickLink($label)Follows a link by label
    isLink($label)See if a link is present by label
    clickLinkById($id)Follows a link by attribute
    isLinkById($id)See if a link is present by attribut
    getUrl()Current URL of page or frame
    getTitle()Page title
    getContent()Raw page or frame
    getContentAsText()HTML removed except for alt text
    retry()Repeat the last request
    back()Use the browser back button
    forward()Use the browser forward button
    authenticate($username, $password)Retry page or frame after a 401 response
    restart($date)Restarts the browser for a new session
    ageCookies($interval)Ages the cookies by the specified time
    setCookie($name, $value)Sets an additional cookie
    getCookieValue($host, $path, $name)Reads the most specific cookie
    getCurrentCookieValue($name)Reads cookie for the current context
    The methods SimpleBrowser::useProxy() and SimpleBrowser::addHeader() are special. Once called they continue to apply to all subsequent fetches.

    Navigating forms is similar to the WebTestCase form navigation...
    setField($name, $value)Sets all form fields with that name
    setFieldById($id, $value)Sets all form fields with that id
    getField($name)Accessor for a form element value
    getFieldById($id)Accessor for a form element value
    clickSubmit($label)Submits form by button label
    clickSubmitByName($name)Submits form by button attribute
    clickSubmitById($id)Submits form by button attribute
    clickImage($label, $x, $y)Clicks the image by alt text
    clickImageByName($name, $x, $y)Clicks the image by attribute
    clickImageById($id, $x, $y)Clicks the image by attribute
    submitFormById($id)Submits by the form tag attribute
    At the moment there aren't any methods to list available forms and fields. This will probably be added to later versions of SimpleTest.

    Within a page, individual frames can be selected. If no selection is made then all the frames are merged together in one large conceptual page. The content of the current page will be a concatenation of all of the frames in the order that they were specified in the "frameset" tags.
    getFrames()A dump of the current frame structure
    getFrameFocus()Current frame label or index
    setFrameFocusByIndex($choice)Select a frame numbered from 1
    setFrameFocus($name)Select frame by label
    clearFrameFocus()Treat all the frames as a single page
    When focused on a single frame, the content will come from that frame only. This includes links to click and forms to submit.

    All of this functionality is great when we actually manage to fetch pages, but that doesn't always happen. To help figure out what went wrong, the browser has some methods to aid in debugging...
    setConnectionTimeout($timeout)Close the socket on overrun
    getRequest()Raw request header of page or frame
    getHeaders()Raw response header of page or frame
    getTransportError()Any socket level errors in the last fetch
    getResponseCode()HTTP response of page or frame
    getMimeType()Mime type of page or frame
    getAuthentication()Authentication type in 401 challenge header
    getRealm()Authentication realm in 401 challenge header
    setMaximumRedirects($max)Number of redirects before page is loaded anyway
    setMaximumNestedFrames($max)Protection against recursive framesets
    ignoreFrames()Disables frames support
    useFrames()Enables frames support
    ignoreCookies()Disables sending and receiving of cookies
    useCookies()Enables cookie support
    The methods SimpleBrowser::setConnectionTimeout() SimpleBrowser::setMaximumRedirects(), SimpleBrowser::setMaximumNestedFrames(), SimpleBrowser::ignoreFrames(), SimpleBrowser::useFrames(), SimpleBrowser::ignoreCookies() and SimpleBrowser::useCokies() continue to apply to every subsequent request. The other methods are frames aware. This means that if you have an individual frame that is not loading, navigate to it using SimpleBrowser::setFrameFocus() and you can then use SimpleBrowser::getRequest(), etc to see what happened.

    Anything that could be done in a WebTestCase can now be done in a UnitTestCase. This means that we can freely mix domain object testing with the web interface... class TestOfRegistration extends UnitTestCase { function testNewUserAddedToAuthenticator() { $browser = &new SimpleBrowser(); $browser->get('http://my-site.com/register.php'); $browser->setField('email', 'me@here'); $browser->setField('password', 'Secret'); $browser->click('Register'); $authenticator = &new Authenticator(); $member = &$authenticator->findByEmail('me@here'); $this->assertEqual($member->getPassword(), 'Secret'); } } ]]> While this may be a useful temporary expediency, I am not a fan of this type of testing. The testing has cut across application layers, make it twice as likely it will need refactoring when the code changes.

    A more useful case of where using the browser directly can be helpful is where the WebTestCase cannot cope. An example is where two browsers are needed at the same time.

    For example, say we want to disallow multiple simultaneous usage of a site with the same username. This test case will do the job... $first = &new SimpleBrowser(); $first->get('http://my-site.com/login.php'); $first->setField('name', 'Me'); $first->setField('password', 'Secret'); $first->click('Enter'); $this->assertEqual($first->getTitle(), 'Welcome'); $second = &new SimpleBrowser(); $second->get('http://my-site.com/login.php'); $second->setField('name', 'Me'); $second->setField('password', 'Secret'); $second->click('Enter'); $this->assertEqual($second->getTitle(), 'Access Denied'); } } ]]> You can also use the SimpleBrowser class directly when you want to write test cases using a different test tool than SimpleTest.

    Using the bundled web browser in scripts Debugging failed pages Complex tests with multiple web browsers SimpleTest project page on SourceForge. SimpleTest download page on LastCraft. The developer's API for SimpleTest gives full detail on the classes and assertions available. user agent, web browser php, fetching pages, spider scripts, software development, php programming for clients, customer focused php, software development tools, acceptance testing framework, free php scripts, log in boxes, unit testing authentication systems, php resources, HTMLUnit, JWebUnit, php testing, unit test resource, web testing, HTTP authentication, testing log in, authentication testing, security tests
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/improving_design_tutorial.xml0000664000175000017620000001730011157271050030454 0ustar davidpalepurple PHP unit testing tutorial - Top down design test first with mock objects

    Mock now, code later

    I lied.

    I haven't created a writer test at all, only the FileWriter interface that I showed earlier. In fact I'll go one step further away from a finished article and assume only an abstract writer in classes/writer.php... Writer { function Writer() { } function write($message) { } } ?> ]]> The corresponding test changes are... Mock::generate('Writer'); class TestOfLogging extends UnitTestCase { function TestOfLogging() { $this->UnitTestCase('Log class test'); } function testWriting() { $clock = &new MockClock($this); $clock->setReturnValue('now', 'Timestamp'); $writer = &new MockWriter($this); $writer->expectOnce('write', array('[Timestamp] Test line')); $log = &new Log($writer); $log->message('Test line', &$clock); $writer->tally(); } } ?> ]]> In order to use the logging class we would need to code a file writer or other sort of writer, but at the moment we are only testing and so we do not yet need it. So, in other words, using mocks we can defer the creation of lower level objects until we feel like it. Not only can we design top down, but we can test top down too.

    Approaching the bridge

    Imagine for the moment that we had started the logging class from another direction. Pretend that we had coded just enough of the Log to realise we needed a Writer somehow. How would we have included it?

    Well, inheriting from the writer would not have allowed us to mock it from the testing point of view. From the design point of view we would have been restricted to just one writer without multiple inheritence.

    Creating the writer internally, rather than passing it in the constructor, by choosing a class name is possible, but we would have less control of the mock object set up. From the design point of view it would have been nearly impossible to pass parameters to the writer in all the different formats ever needed. You would have to have the writer restricted to say a hash or complicated string describing the target details. Needlessly complicated at best.

    Using a factory method to create the writer internally would be possible, but would mean subclassing it for testing so that the factory method could be replaced with one returning a mock. More work from the test point of view, although still possible. From the design point of view it would mean a new logger subclass for every type of writer that we want to use. This is called a parallel class hiearchy and obviously involves duplication. Yuk.

    At the other extreme, passing or creating the writer on every message would have been repetitive and reduced the Log class code to a single method, a sure sign that the whole class has become redundant.

    This tension between ease of testing and avoiding repetition has allowed us to find a flexible and clean design. Remember our brief yearning for multiple inheritence? We have replaced it with polymorphism (lots of writers) and separated the logging hierachy from the writing hierarchy. We connect the two through this simpler Log by aggregation. This trick is actually a design pattern called a "Bridge".

    So we have been pushed by test code (we haven't written much else yet) into a design pattern. Think about this for a second. Tests improve code quality, certainly in my case, but this is something far more profound and far more powerful.

    Testing has improved the design.

    Mock down design

    Creating a mock object is as easy as creating the interface in text form. If you have UML or other tools that create these interfaces for you, then you have an even more flexible route to quickly generate test objects. Even if you do not, you can switch from white board drawing, to writing a test case, to writing a mock, to generating an interface which takes us back to the whiteboard drawing again, fairly easily. Like refactoring, design, code and test become unified.

    Because mock objects work top down they can be bought into the design more quickly than normal refactoring, which requires at least partially working code before it kicks in. This means that the testing code interacts with the design faster and this means that the design quality goes up sooner.

    A unit tester is a coding tool. A unit tester with mock objects is a design tool.

    Mock now, code later. We derive the bridge pattern. Designing and testing hand in hand. This tutorial follows Boundary classes. You will need the SimpleTest testing framework to try these examples. For more mock object discussion see the Extreme Tuesday Wiki or the C2 Wiki software development, php programming tutorial, programming php test cases, software development tools, php tutorial, free php code, architecture, php examples, mock object examples, junit style testing, php testing frameworks, unit test, mock objects in PHP, php testing
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/boundary_classes_tutorial.xml0000664000175000017620000004071011157271050030452 0ustar davidpalepurple PHP unit testing tutorial - Organising unit tests and boundary class test cases

    You are probably thinking that we have well and truly exhausted the Log class by now and that there is really nothing more to add. Things are never that simple with object oriented programming, though. You think you understand a problem and then something comes a long that challenges your perspective and leads to an even deeper appreciation. I thought I understood the logging class and that only the first page of the tutorial would use it. After that I would move on to something more complicated. No one is more surprised than me that I still haven't got to the bottom of it. In fact I think I have only just figured out what a logger does.

    Log variations

    Supposing that we do not want to log to a file at all. Perhaps we want to print to the screen, write the messages to a socket or send them to the Unix(tm) syslog daemon for dispatching across the network. How do we incorporate this variation?

    Simplest is to subclass the Log overriding the message() method with new versions. This will work in the short term, but there is actually something subtle, but deeply wrong with this. Suppose we do subclass and have loggers that write to files, the screen and the network. Three classes , but that is OK. Now suppose that we want a new logging class that adds message filtering by priority, letting only certain types of messages through according to some configuration file.

    We are stuck. If we subclass again, we have to do it for all three classes, giving us six classes. The amount of duplication is horrible.

    So are you now wishing that PHP had multiple inheritence? Well, here that would reduce the short term workload, but complicate what should be a very simple class. Multiple inheritance, even when supported, should be used extremely carefully as all sorts of complicated entanglements can result. Treat it as a loaded gun. In fact, our sudden need for it is telling us something else - perhaps that we have gone wrong on the conceptual level.

    What does a logger do? Does it send messages to a file? Does it send messages to a network? Does it send messages to a screen? Nope. It just sends messages (full stop). The target of those messages can be chosen when setting up the log, but after that the logger should be left to combine and format the message elements as that is its real job. We restricted ourselves by assuming that target was a filename.

    Abstracting a file to a writer

    The solution to this plight is a real classic. First we encapsulate the variation in a class as this will add a level of indirection. Instead of passing in the file name as a string we will pass the "thing that we will write to" which we will call a Writer. Back to the tests... require_once('../classes/writer.php'); Mock::generate('Clock'); class TestOfLogging extends UnitTestCase { function TestOfLogging() { $this->UnitTestCase('Log class test'); } function setUp() { @unlink('../temp/test.log'); } function tearDown() { @unlink('../temp/test.log'); } function getFileLine($filename, $index) { $messages = file($filename); return $messages[$index]; } function testCreatingNewFile() { $log = new Log(new FileWriter('../temp/test.log')); $this->assertFalse(file_exists('../temp/test.log'), 'Created before message'); $log->message('Should write this to a file'); $this->assertTrue(file_exists('../temp/test.log'), 'File created'); } function testAppendingToFile() { $log = new Log(new FileWriter('../temp/test.log')); $log->message('Test line 1'); $this->assertWantedPattern( '/Test line 1/', $this->getFileLine('../temp/test.log', 0)); $log->message('Test line 2'); $this->assertWantedPattern( '/Test line 2/', $this->getFileLine('../temp/test.log', 1)); } function testTimestamps() { $clock = &new MockClock($this); $clock->setReturnValue('now', 'Timestamp'); $log = new Log(new FileWriter('../temp/test.log')); $log->message('Test line', &$clock); $this->assertWantedPattern( '/Timestamp/', $this->getFileLine('../temp/test.log', 0), 'Found timestamp'); } } ?> ]]> I am going to do this one step at a time so as not to get confused. I have replaced the file names with an imaginary FileWriter class from a file classes/writer.php. This will cause the tests to crash as we have not written the writer yet. Should we do that now?

    We could, but we don't have to. We do need to create the interface, though, or we won't be able to mock it. This makes classes/writer.php looks like... ]]> We need to modify the Log class as well... require_once('../classes/writer.php'); class Log { var $_writer; function Log(&$writer) { $this->_writer = &$writer; } function message($message, $clock = false) { if (! is_object($clock)) { $clock = new Clock(); } $this->_writer->write("[" . $clock->now() . "] $message"); } } ?> ]]> There is not much that hasn't changed in our now even smaller class. The tests run, but fail at this point unless we add code to the writer. What do we do now?

    We could start writing tests and code the FileWriter class alongside, but while we were doing this our Log tests would be failing and disturbing our focus. In fact we do not have to.

    Part of our plan is to free the logging class from the file system and there is a way to do this. First we add a tests/writer_test.php so that we have somewhere to place our test code from log_test.php that we are going to shuffle around. I won't yet add it to the all_tests.php file though as it is the logging aspect we are tackling right now.

    Now I have done that (honest) we remove any tests from log_test.php that are not strictly logging related and move them to writer_test.php for later. We will also mock the writer so that it does not write out to real files... Mock::generate('FileWriter'); class TestOfLogging extends UnitTestCase { function TestOfLogging() { $this->UnitTestCase('Log class test'); } function testWriting() { $clock = &new MockClock(); $clock->setReturnValue('now', 'Timestamp'); $writer = &new MockFileWriter($this); $writer->expectArguments('write', array('[Timestamp] Test line')); $writer->expectCallCount('write', 1); $log = &new Log(\$writer); $log->message('Test line', &$clock); } } ?> ]]> Yes that really is the whole test case and it really is that short. A lot has happened here...

    1. The requirement to create the file only when needed has moved to the FileWriter.
    2. As we are dealing with mocks, no files are actually created and so I moved the setUp() and tearDown() off into the writing tests.
    3. The test now consists of sending a sample message and testing the format.
    Hang on a minute, where are the assertions?

    The mock objects do much more than simply behave like other objects, they also run tests. The expectArguments() call told the mock to expect a single parameter of the string "[Timestamp] Test line" when the mock write() method is called. When that method is called the expected parameters are compared with this and either a pass or a fail is sent to the unit test as a result.

    The other expectation is that write() will be called only once. Simply setting this up is not enough. We can see all this in action by running the tests...

    All tests

    Pass: log_test.php->Log class test->testwriting->Arguments for [write] were [String: [Timestamp] Test line]
    Pass: log_test.php->Log class test->testwriting->Expected call count for [write] was [1], but got [1]
    Pass: clock_test.php->Clock class test->testclockadvance->Advancement
    Pass: clock_test.php->Clock class test->testclocktellstime->Now is the right time
    3/3 test cases complete. 4 passes and 0 fails.

    We can actually shorten our test slightly more. The mock object expectation expectOnce() can actually combine the two seperate expectations... setReturnValue('now', 'Timestamp'); $writer = &new MockFileWriter($this); $writer->expectOnce('write', array('[Timestamp] Test line')); $log = &new Log($writer); $log->message('Test line', &$clock); } ]]> This can be an effective shorthand.

    Boundary classes

    Something very nice has happened to the logger besides merely getting smaller.

    The only things it depends on now are classes that we have written ourselves and in the tests these are mocked and so there are no dependencies on anything other than our own PHP code. No writing to files or waiting for clocks to tick over. This means that the log_test.php test case will run as fast as the processor will carry it. By contrast the FileWriter and Clock classes are very close to the system. This makes them harder to test as real data must be moved around and painstakingly confirmed, often by ad hoc tricks.

    Our last refactoring has helped a lot. The hard to test classes on the boundary of the application and the system are now smaller as the I/O code has been further separated from the application logic. They are direct mappings to PHP operations: FileWriter::write() maps to PHP fwrite() with the file opened for appending and Clock::now() maps to PHP time(). This makes debugging easier. It also means that these classes will change less often.

    If they don't change a lot then there is no reason to keep running the tests for them. This means that tests for the boundary classes can be moved off into there own test suite leaving the other unit tests to run at full speed. In fact this is what I tend to do and the test cases in SimpleTest itself are divided this way.

    That may not sound like much with one unit test and two boundary tests, but typical applications can have twenty boundary classes and two hundred application classes. To keep these running at full speed you will want to keep them separate.

    Besides, separating off decisions of which system components to use is good development. Perhaps all this mocking is improving our design?

    Handling variation in our logger. Abstracting further with a mock Writer class. Separating Boundary class tests cleans things up. This tutorial follows the Mock objects introduction. Next is test driven design. You will need the SimpleTest testing framework to try these examples. software development, php programming, programming php, software development tools, php tutorial, free php scripts, organizing unit tests, testing tips, development tricks, software architecture for testing, php example code, mock objects, junit port, test case examples, php testing, unit test tool, php test suite
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/subclass_tutorial.xml0000664000175000017620000002257111157271050026736 0ustar davidpalepurple PHP unit testing tutorial - Subclassing a test case

    A timing insensitive assertion

    We left our clock test with a hole. If the PHP time() function rolled over during this comparison... assertEqual($clock->now(), time(), 'Now is the right time'); } ]]> ...our test would be out by one second and would cause a false failure. Erratic behaviour of our test suite is not what we want when we could be running it a hundred times a day.

    We could rewrite the test as... $time1 = $clock->now(); $time2 = time(); $this->assertTrue($time1 == $time2) || ($time1 + 1 == $time2), 'Now is the right time'); } ]]> This is hardly a clear design though and we will have to repeat this for every timing test that we do. Repetition is public enemy number one and so we'll use this as incentive to factor out the new test code. UnitTestCase('Clock class test'); } function assertSameTime($time1, $time2, $message) { $this->assertTrue( ($time1 == $time2) || ($time1 + 1 == $time2), $message); } function testClockTellsTime() { $clock = new Clock(); $this->assertSameTime($clock->now(), time(), 'Now is the right time'); } function testClockAdvance() { $clock = new Clock(); $clock->advance(10); $this->assertSameTime($clock->now(), time() + 10, 'Advancement'); } } ]]> Of course each time I make one of these changes I rerun the tests to make sure we are still OK. Refactor on green. It's a lot safer.

    Reusing our assertion

    It may be that we want more than one test case that is timing sensitive. Perhaps we are reading timestamps from database rows or other places that could allow an extra second to tick over. For these new test classes to take advantage of our new assertion we need to place it into a superclass.

    Here is the complete clock_test.php file after promoting our assertSameTime() method to its own superclass... class TimeTestCase extends UnitTestCase { function TimeTestCase($test_name) { $this->UnitTestCase($test_name); } function assertSameTime($time1, $time2, $message) { $this->assertTrue( ($time1 == $time2) || ($time1 + 1 == $time2), $message); } } class TestOfClock extends TimeTestCase { function TestOfClock() { $this->TimeTestCase('Clock class test'); } function testClockTellsTime() { $clock = new Clock(); $this->assertSameTime($clock->now(), time(), 'Now is the right time'); } function testClockAdvance() { $clock = new Clock(); $clock->advance(10); $this->assertSameTime($clock->now(), time() + 10, 'Advancement'); } } ?> ]]> Now we get the benefit of our new assertion every time we inherit from our own TimeTestCase class rather than the default UnitTestCase. This is very much how the JUnit tool was designed to be used and SimpleTest is a port of that interface. It is a testing framework from which your own test system can be grown.

    If we run the tests now we get a slight niggle...

    Warning: Missing argument 1 for timetestcase() in /home/marcus/projects/lastcraft/tutorial_tests/tests/clock_test.php on line 5

    All tests

    3/3 test cases complete. 6 passes and 0 fails.
    The reasons for this are quite tricky.

    Our subclass requires a constructor parameter that has not been supplied and yet it appears that we did supply it. When we inherited our new class we passed it in our own constructor. It's right here... TimeTestCase('Clock class test'); } ]]> In fact we are right, that is not the problem.

    Remember when we built our all_tests.php group test by using the addTestFile() method. This method looks for test case classes, instantiates them if they are new and then runs all of their tests. What's happened is that it has found our test case extension as well. This is harmless as there are no test methods within it, that is, method names that start with the string "test". No extra tests are run.

    The trouble is that it instantiates the class and does this without the $test_name parameter which is what causes our warning. This parameter is not normally required of a test case and not normally of its assertions either. To make our extended test case match the UnitTestCase interface we must make these optional... $test_name = false) { $this->UnitTestCase($test_name); } function assertSameTime($time1, $time2, $message = false) { if (! $message) { $message = "Time [$time1] should match time [$time2]"; } $this->assertTrue( ($time1 == $time2) || ($time1 + 1 == $time2), $message); } } ]]> Of course it should still bother you that this class is instantiated by the test suite unnecessarily. Here is a modification to prevent it running... SimpleTestOptions::ignore('TimeTestCase'); class TimeTestCase extends UnitTestCase { function TimeTestCase($test_name = false) { $this->UnitTestCase($test_name); } function assertSameTime($time1, $time2, $message = '') { if (!$message) { $message = "Time [$time1] should match time [$time2]"; } $this->assertTrue( ($time1 == $time2) || ($time1 + 1 == $time2), $message); } } ]]> This just tells SimpleTest to always ignore this class when building test suites. It can be included anywhere in the test case file.

    Six passes looks good, but does not tell the casual observer what has been tested. For that you have to look at the code. If that sounds like drudge to you and you would like this information displayed before you then we should go on to show the passes next.

    A timing insensitive assertion that allows a one second gain. Subclassing the test case so as to reuse the test method. The previous section was controlling test variables. The next tutorial section was changing the test display. You will need the SimpleTest test tool to run the sample code. software development, test case example, programming php, software development tools, php tutorial, creating subclass, free php scripts, architecture, php resources, junit, phpunit style testing, unit test, php testing
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/partial_mocks_documentation.xml0000664000175000017620000003506311157271050030755 0ustar davidpalepurple SimpleTest for PHP partial mocks documentation

    A partial mock is simply a pattern to alleviate a specific problem in testing with mock objects, that of getting mock objects into tight corners. It's quite a limited tool and possibly not even a good idea. It is included with SimpleTest because I have found it useful on more than one occasion and has saved a lot of work at that point.

    When one object uses another it is very simple to just pass a mock version in already set up with its expectations. Things are rather tricker if one object creates another and the creator is the one you want to test. This means that the created object should be mocked, but we can hardly tell our class under test to create a mock instead. The tested class doesn't even know it is running inside a test after all.

    For example, suppose we are building a telnet client and it needs to create a network socket to pass its messages. The connection method might look something like... read( ... ); ... } } ?> ]]> We would really like to have a mock object version of the socket here, what can we do?

    The first solution is to pass the socket in as a parameter, forcing the creation up a level. Having the client handle this is actually a very good approach if you can manage it and should lead to factoring the creation from the doing. In fact, this is one way in which testing with mock objects actually forces you to code more tightly focused solutions. They improve your programming.

    Here this would be... function &connect(&$socket, $username, $password) { $socket->read( ... ); ... } } ?> ]]> This means that the test code is typical for a test involving mock objects. $socket = &new MockSocket($this); ... $telnet = &new Telnet(); $telnet->connect($socket, 'Me', 'Secret'); ... } } ]]> It is pretty obvious though that one level is all you can go. You would hardly want your top level application creating every low level file, socket and database connection ever needed. It wouldn't know the constructor parameters anyway.

    The next simplest compromise is to have the created object passed in as an optional parameter... function &connect($ip, $port, $username, $password, $socket = false) { if (!$socket) { $socket = &new Socket($ip, $port); } $socket->read( ... ); ... return $socket; } } ?> ]]> For a quick solution this is usually good enough. The test now looks almost the same as if the parameter was formally passed... $socket = &new MockSocket($this); ... $telnet = &new Telnet(); $telnet->connect('127.0.0.1', 21, 'Me', 'Secret', &$socket); ... } } ]]> The problem with this approach is its untidiness. There is test code in the main class and parameters passed in the test case that are never used. This is a quick and dirty approach, but nevertheless effective in most situations.

    The next method is to pass in a factory object to do the creation... function Telnet(&$network) { $this->_network = &$network; } ... function &connect($ip, $port, $username, $password) { $socket = &$this->_network->createSocket($ip, $port); $socket->read( ... ); ... return $socket; } } ?> ]]> This is probably the most highly factored answer as creation is now moved into a small specialist class. The networking factory can now be tested separately, but mocked easily when we are testing the telnet class... $socket = &new MockSocket($this); ... $network = &new MockNetwork($this); $network->setReturnReference('createSocket', $socket); $telnet = &new Telnet($network); $telnet->connect('127.0.0.1', 21, 'Me', 'Secret'); ... } } ]]> The downside is that we are adding a lot more classes to the library. Also we are passing a lot of factories around which will make the code a little less intuitive. The most flexible solution, but the most complex.

    Is there a middle ground?

    There is a way we can circumvent the problem without creating any new application classes, but it involves creating a subclass when we do the actual testing. Firstly we move the socket creation into its own method... $socket = &$this->_createSocket($ip, $port); $socket->read( ... ); ... } function &_createSocket($ip, $port) { return new Socket($ip, $port); } } ?> ]]> This is the only change we make to the application code.

    For the test case we have to create a subclass so that we can intercept the socket creation... class TelnetTestVersion extends Telnet { var $_mock; function TelnetTestVersion(&$mock) { $this->_mock = &$mock; $this->Telnet(); } function &_createSocket() { return $this->_mock; } } ]]> Here I have passed the mock in the constructor, but a setter would have done just as well. Note that the mock was set into the object variable before the constructor was chained. This is necessary in case the constructor calls connect(). Otherwise it could get a null value from _createSocket().

    After the completion of all of this extra work the actual test case is fairly easy. We just test our new class instead... $socket = &new MockSocket($this); ... $telnet = &new TelnetTestVersion($socket); $telnet->connect('127.0.0.1', 21, 'Me', 'Secret'); ... } } ]]> The new class is very simple of course. It just sets up a return value, rather like a mock. It would be nice if it also checked the incoming parameters as well. Just like a mock. It seems we are likely to do this often, can we automate the subclass creation?

    Of course the answer is "yes" or I would have stopped writing this by now! The previous test case was a lot of work, but we can generate the subclass using a similar approach to the mock objects.

    Here is the partial mock version of the test... Mock::generatePartial( 'Telnet', 'TelnetTestVersion', array('_createSocket')); class TelnetTest extends UnitTestCase { ... function testConnection() { $socket = &new MockSocket($this); ... $telnet = &new TelnetTestVersion($this); $telnet->setReturnReference('_createSocket', $socket); $telnet->Telnet(); $telnet->connect('127.0.0.1', 21, 'Me', 'Secret'); ... } } ]]> The partial mock is a subclass of the original with selected methods "knocked out" with test versions. The generatePartial() call takes three parameters: the class to be subclassed, the new test class name and a list of methods to mock.

    Instantiating the resulting objects is slightly tricky. The only constructor parameter of a partial mock is the unit tester reference. As with the normal mock objects this is needed for sending test results in response to checked expectations.

    The original constructor is not run yet. This is necessary in case the constructor is going to make use of the as yet unset mocked methods. We set any return values at this point and then run the constructor with its normal parameters. This three step construction of "new", followed by setting up the methods, followed by running the constructor proper is what distinguishes the partial mock code.

    Apart from construction, all of the mocked methods have the same features as mock objects and all of the unmocked methods behave as before. We can set expectations very easily... setReturnReference('_createSocket', $socket); $telnet->expectOnce('_createSocket', array('127.0.0.1', 21)); $telnet->Telnet(); $telnet->connect('127.0.0.1', 21, 'Me', 'Secret'); ... $telnet->tally(); } } ]]>

    The mocked out methods don't have to be factory methods, they could be any sort of method. In this way partial mocks allow us to take control of any part of a class except the constructor. We could even go as far as to mock every method except one we actually want to test.

    This last situation is all rather hypothetical, as I haven't tried it. I am open to the possibility, but a little worried that forcing object granularity may be better for the code quality. I personally use partial mocks as a way of overriding creation or for occasional testing of the TemplateMethod pattern.

    It's all going to come down to the coding standards of your project to decide which mechanism you use.

    The mock injection problem. Moving creation to a protected factory method. Partial mocks generate subclasses. Partial mocks test less than a class. SimpleTest project page on SourceForge. Full API for SimpleTest from the PHPDoc. The protected factory is described in this paper from IBM. This is the only formal comment I have seen on this problem. php software development, php test case development, database programming php, software development tools, php advanced tutorial, phpunit style scripts, architecture, php resources, mock objects, junit, php test framework, unit test, php testing
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/gain_control_tutorial.xml0000664000175000017620000002642211157271050027574 0ustar davidpalepurple PHP unit testing tutorial - Isolating variables when testing

    In order to test a code module you need very tight control of its environment. If anything can vary behind the scenes, for example a configuration file, then this could cause the tests to fail unexpectedly. This would not be a fair test of the code and could cause you to spend fruitless hours examining code that is actually working, rather than dealing with the configuration issue that actually failed the test. At the very least your test cases get more complicated in taking account the possible variations.

    Controlling time

    There are often a lot of obvious variables that could affect a unit test case, especially in the web development environment in which PHP usually operates. These include database set up, file permissions, network resources and configuration amongst others. The failure or misinstall of one of these components will break the test suite. Do we add tests to confirm these components are installed? This is a good idea, but if you place them into code module tests you will start to clutter you test code with detail that is irrelavent to the immediate task. They should be placed in their own test group.

    Another problem, though, is that our development machines must have every system component installed to be able to run the test suite. Your tests run slower too.

    When faced with this while coding we will often create wrapper versions of classes that deal with these resources. Ugly details of these resources are then coded once only. I like to call these classes "boundary classes" as they exist at the edges of the application, the interface of your application with the rest of the system. These boundary classes are best simulated during testing by simulated versions. These run faster as well and are often called "Server Stubs" or in more generic form "Mock Objects". It is a great time saver to wrap and stub out every such resource.

    One often neglected factor is time. For example, to test a session time-out coders will often temporarily set the session time limit to a small value, say two seconds, and then do a sleep(3) and assert that the session is now invalid. That adds three seconds to your test suite and is usually a lot of extra code making your session classes that maleable. Far simpler is to have a way to suddenly advance the clock. To control time.

    A clock class

    Again we will design our clock wrapper by writing tests. Firstly we add a clock test case to our tests/all_tests.php test suite... require_once('clock_test.php'); $test = &new TestSuite('All tests'); $test->addTestCase(new TestOfLogging()); $test->addTestCase(new TestOfClock()); $test->run(new HtmlReporter()); ?> ]]> Then we create the test case in the new file tests/clock_test.php... UnitTestCase('Clock class test'); } function testClockTellsTime() { $clock = new Clock(); $this->assertEqual($clock->now(), time(), 'Now is the right time'); } function testClockAdvance() { } } ?> ]]> Our only test at the moment is that our new Clock class acts as a simple PHP time() function substitute. The other method is a place holder. It's our TODO item if you like. We haven't done a test for it yet because that would spoil our rhythm. We will write the time shift functionality once we are green. At the moment we are obviously not green...

    Fatal error: Failed opening required '../classes/clock.php' (include_path='') in /home/marcus/projects/lastcraft/tutorial_tests/tests/clock_test.php on line 2
    We create a classes/clock.php file like so... ]]> This regains our flow ready for coding.

    All tests

    Fail: Clock class test->testclocktellstime->[NULL: ] should be equal to [integer: 1050257362]
    3/3 test cases complete. 4 passes and 1 fails.
    This is now easy to fix... return time(); } } ]]> And now we are green...

    All tests

    3/3 test cases complete. 5 passes and 0 fails.
    There is still a problem. The clock could roll over during the assertion causing the result to be out by one second. The chances are small, but if there were a lot of timing tests you would end up with a test suite that is erratic, severely limiting its usefulness. We will tackle this shortly and for now just jot it onto our "to do" list.

    The advancement test looks like this... UnitTestCase('Clock class test'); } function testClockTellsTime() { $clock = new Clock(); $this->assertEqual($clock->now(), time(), 'Now is the right time'); } function testClockAdvance() { $clock = new Clock(); $clock->advance(10); $this->assertEqual($clock->now(), time() + 10, 'Advancement'); } } ]]> The code to get to green is straight forward and just involves adding a time offset. var $_offset; function Clock() { $this->_offset = 0; } function now() { return time() + $this->_offset; } function advance($offset) { $this->_offset += $offset; } } ]]>

    Group test tidy up

    Our all_tests.php file has some repetition we could do without. We have to manually add our test cases from each included file. It is possible to remove it, but use of the following requires care. The TestSuite class has a convenience method called addTestFile() that takes a PHP file as a parameter. This mechanism makes a note of all the classes, requires in the file and then has a look at any newly created classes. If they are descendents of TestCase they are added as a new group test.

    Here is our refactored test suite using this method... require_once(SIMPLE_TEST . 'unit_tester.php'); require_once(SIMPLE_TEST . 'reporter.php'); $test = &new TestSuite('All tests'); $test->addTestFile('log_test.php'); $test->addTestFile('clock_test.php'); $test->run(new HtmlReporter()); ?> ]]> The pitfalls of this are...

    1. If the test file has already been included, no new classes will be added to this group
    2. If the test file has other classes that are related to TestCase then these will be added to the group test as well.
    In our tests we have only test cases in the test files and we removed their inclusion from the all_tests.php script and so we are OK. This is the usual situation.

    We should really fix the glitch with the possible clock rollover so we'll do this next.

    Time is an often neglected variable in tests. A clock class allows us to alter time. Tidying the group test. The previous section is grouping unit tests. The next section is subclassing test cases. You will need the SimpleTest unit tester for the examples. software development, php programming, programming php, software development tools, php tutorial, free php scripts, architecture, php resources, mock objects, junit, php testing, unit test, php testing
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/overview.xml0000664000175000017620000004730011157271050025037 0ustar davidpalepurple Overview and feature list for the SimpleTest PHP unit tester and web tester

    The heart of SimpleTest is a testing framework built around test case classes. These are written as extensions of base test case classes, each extended with methods that actually contain test code. Top level test scripts then invoke the run() methods on every one of these test cases in order. Each test method is written to invoke various assertions that the developer expects to be true such as assertEqual(). If the expectation is correct, then a successful result is dispatched to the observing test reporter, but any failure triggers an alert and a description of the mismatch.

    A test case looks like this... MyTestCase extends UnitTestCase { function testLogWroteMessage() { $log = &new Log('my.log'); $log->message('Hello'); $this->assertTrue(file_exists('my.log')); } } ?> ]]>

    These tools are designed for the developer. Tests are written in the PHP language itself more or less as the application itself is built. The advantage of using PHP itself as the testing language is that there are no new languages to learn, testing can start straight away, and the developer can test any part of the code. Basically, all parts that can be accessed by the application code can also be accessed by the test code, if they are in the same programming language.

    The simplest type of test case is the UnitTestCase. This class of test case includes standard tests for equality, references and pattern matching. All these test the typical expectations of what you would expect the result of a function or method to be. This is by far the most common type of test in the daily routine of development, making up about 95% of test cases.

    The top level task of a web application though is not to produce correct output from its methods and objects, but to generate web pages. The WebTestCase class tests web pages. It simulates a web browser requesting a page, complete with cookies, proxies, secure connections, authentication, forms, frames and most navigation elements. With this type of test case, the developer can assert that information is present in the page and that forms and sessions are handled correctly.

    A WebTestCase looks like this... MySiteTest extends WebTestCase { function testHomePage() { $this->get('http://www.my-site.com/index.php'); $this->assertTitle('My Home Page'); $this->clickLink('Contact'); $this->assertTitle('Contact me'); $this->assertPattern('/Email me at/'); } } ?> ]]>

    The following is a very rough outline of past and future features and their expected point of release. I am afraid it is liable to change without warning as meeting the milestones rather depends on time available. Green stuff has been coded, but not necessarily released yet. If you have a pressing need for a green but unreleased feature then you should check-out the code from Sourceforge CVS directly.
    FeatureDescriptionRelease
    Unit test case Core test case class and assertions 1.0
    Html display Simplest possible display 1.0
    Autoloading of test cases Reading a file with test cases and loading them into a group test automatically 1.0
    Mock objects Objects capable of simulating other objects removing test dependencies 1.0
    Web test case Allows link following and title tag matching 1.0
    Partial mocks Mocking parts of a class for testing less than a class or for complex simulations 1.0
    Web cookie handling Correct handling of cookies when fetching pages 1.0
    Following redirects Page fetching automatically follows 300 redirects 1.0
    Form parsing Ability to submit simple forms and read default form values 1.0
    Command line interface Test display without the need of a web browser 1.0
    Exposure of expectation classes Can create precise tests with mocks as well as test cases 1.0
    XML output and parsing Allows multi host testing and the integration of acceptance testing extensions 1.0
    Browser component Exposure of lower level web browser interface for more detailed test cases 1.0
    HTTP authentication Fetching protected web pages with basic authentication only 1.0
    SSL support Can connect to https: pages 1.0
    Proxy support Can connect via. common proxies 1.0
    Frames support Handling of frames in web test cases 1.0
    File upload testing Can simulate the input type file tag 1.0.1
    Mocking interfaces Can generate mock objects to interfaces as well as classes and class interfaces are carried for type hints 1.0.1
    Testing exceptions Similar to testing PHP errors 1.0.1
    HTML label support Can access all controls using the visual label 1.0.1
    Code coverage Reports using the bundled SpikeSource coverage tool 1.0.1
    Reporting machinery enhancements Improved message passing for better cooperation with IDEs 1.1
    Localisation Messages abstracted and code generated from XML 1.1
    IFrame support Reads IFrame content that can be refreshed 1.1
    Improved mock interface More compact way of expressing mocks using fluent interfaces 2.0
    Assertion packs Can dynamically add assertions to test cases 2.0
    HTML table assertions Can match table elements to numerical assertions 2.0
    XPath searching of HTML elements More flexible content matching 2.0
    Alternate HTML parsers Can detect compiled parsers for performance improvements 2.0
    Javascript suport Use of PECL module to add Javascript 3.0
    PHP5 migraton will start straight after the version 1.0.1 series, whereupon only PHP 5.1+ will be supported. SimpleTest is currently compatible with PHP 5, but will not make use of all of the new features until version 2.

    Process is at least as important as tools. The type of process that makes the heaviest use of a developer's testing tool is of course Extreme Programming. This is one of the Agile Methodologies which combine various practices to "flatten the cost curve" of software development. More extreme still is Test Driven Development, where you very strictly adhere to the rule of no coding until you have a test. If you're more of a planner, or believe that experience trumps evolution, you may prefer the RUP approach. I haven't tried it, but even I can see that you will need test tools (see figure 9).

    Most unit testers clone JUnit to some degree, as far as the interface at least. There is a wealth of information on the JUnit site including the FAQ which contains plenty of general advice on testing. Once you get bitten by the bug you will certainly appreciate the phrase test infected coined by Eric Gamma. If you are still reviewing which unit tester to use the main choices are PHPUnit and Pear PHP::PHPUnit. They currently lack a lot of features found in SimpleTest, but the PEAR version at least has been upgraded for PHP5 and is recommended if you are porting existing JUnit test cases.

    There is currently a sad lack of material on mock objects, which is a shame as unit testing without them is a lot more work. The original mock objects paper is very Java focused, but still worth a read. As a new technology there are plenty of discussions and debate on how to use mocks, often on Wikis such as Extreme Tuesday or www.mockobjects.com or the original C2 Wiki. Injecting mocks into a class is the main area of debate for which this paper on IBM makes a good starting point.

    There are plenty of web testing tools, but the scriptable ones are mostly are written in Java and tutorials and advice are rather thin on the ground. The only hope is to look at the documentation for HTTPUnit, HTMLUnit or JWebUnit and hope for clues. There are some XML driven test frameworks, but again most require Java to run.

    A new generation of tools that run directly in the web browser are now available. These include Selenium and Watir. As SimpleTest does not support JavaScript you would probably have to look at these tools anyway if you have highly dynamic pages.

    Quick summary of the SimpleTest tool for PHP. List of features, both current ones and those planned. There are plenty of unit testing resources on the web. Documentation for SimpleTest. How to write PHP test cases is a fairly advanced tutorial. SimpleTest API from phpdoc. software development tools, php programming, programming php, software development tools, Tools for extreme programming, free php scripts, links of testing tools, php testing resources, mock objects, junit, jwebunit, htmlunit, itc, php testing links, unit test advice and documentation, extreme programming in php Marcus Baker Primary Developer{@link mailto:marcus@lastcraft.com marcus@lastcraft.com} Harry Fuecks Packager{@link mailto:harryf@users.sourceforge.net harryf@users.sourceforge.net} Jason Sweat Documentation{@link mailto:jsweat_php@yahoo.com jsweat_php@yahoo.com}
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/mock_objects_documentation.xml0000664000175000017620000007270011157271050030566 0ustar davidpalepurple SimpleTest for PHP mock objects documentation

    Mock objects have two roles during a test case: actor and critic.

    The actor behaviour is to simulate objects that are difficult to set up or time consuming to set up for a test. The classic example is a database connection. Setting up a test database at the start of each test would slow testing to a crawl and would require the installation of the database engine and test data on the test machine. If we can simulate the connection and return data of our choosing we not only win on the pragmatics of testing, but can also feed our code spurious data to see how it responds. We can simulate databases being down or other extremes without having to create a broken database for real. In other words, we get greater control of the test environment.

    If mock objects only behaved as actors they would simply be known as server stubs. This was originally a pattern named by Robert Binder (Testing object-oriented systems: models, patterns, and tools, Addison-Wesley) in 1999.

    A server stub is a simulation of an object or component. It should exactly replace a component in a system for test or prototyping purposes, but remain lightweight. This allows tests to run more quickly, or if the simulated class has not been written, to run at all.

    However, the mock objects not only play a part (by supplying chosen return values on demand) they are also sensitive to the messages sent to them (via expectations). By setting expected parameters for a method call they act as a guard that the calls upon them are made correctly. If expectations are not met they save us the effort of writing a failed test assertion by performing that duty on our behalf.

    In the case of an imaginary database connection they can test that the query, say SQL, was correctly formed by the object that is using the connection. Set them up with fairly tight expectations and you will hardly need manual assertions at all.

    In the same way that we create server stubs, all we need is an existing class, say a database connection that looks like this... class DatabaseConnection { function DatabaseConnection() { } function query() { } function selectQuery() { } } ]]> The class does not need to have been implemented yet. To create a mock version of the class we need to include the mock object library and run the generator... require_once('simpletest/unit_tester.php'); require_once('simpletest/mock_objects.php'); require_once('database_connection.php'); Mock::generate('DatabaseConnection'); ]]> This generates a clone class called MockDatabaseConnection. We can now create instances of the new class within our test case... class MyTestCase extends UnitTestCase { function testSomething() { $connection = &new MockDatabaseConnection(); } } ]]> Unlike the generated stubs the mock constructor needs a reference to the test case so that it can dispatch passes and failures while checking its expectations. This means that mock objects can only be used within test cases. Despite this their extra power means that stubs are hardly ever used if mocks are available.

    Mocks as actors

    The mock version of a class has all the methods of the original, so that operations like query()]]> are still legal. The return value will be null, but we can change that with... $connection->setReturnValue('query', 37) ]]> Now every time we call query()]]> we get the result of 37. We can set the return value to anything, say a hash of imaginary database results or a list of persistent objects. Parameters are irrelevant here, we always get the same values back each time once they have been set up this way. That may not sound like a convincing replica of a database connection, but for the half a dozen lines of a test method it is usually all you need.

    We can also add extra methods to the mock when generating it and choose our own class name... Mock::generate('DatabaseConnection', 'MyMockDatabaseConnection', array('setOptions')); ]]> Here the mock will behave as if the setOptions() existed in the original class. This is handy if a class has used the PHP overload() mechanism to add dynamic methods. You can create a special mock to simulate this situation.

    Things aren't always that simple though. One common problem is iterators, where constantly returning the same value could cause an endless loop in the object being tested. For these we need to set up sequences of values. Let's say we have a simple iterator that looks like this... This is about the simplest iterator you could have. Assuming that this iterator only returns text until it reaches the end, when it returns false, we can simulate it with... $iterator = &new MockIterator(); $iterator->setReturnValue('next', false); $iterator->setReturnValueAt(0, 'next', 'First string'); $iterator->setReturnValueAt(1, 'next', 'Second string'); ... } } ]]> When next() is called on the mock iterator it will first return "First string", on the second call "Second string" will be returned and on any other call false will be returned. The sequenced return values take precedence over the constant return value. The constant one is a kind of default if you like.

    Another tricky situation is an overloaded get() operation. An example of this is an information holder with name/value pairs. Say we have a configuration class like... This is a classic situation for using mock objects as actual configuration will vary from machine to machine, hardly helping the reliability of our tests if we use it directly. The problem though is that all the data comes through the getValue() method and yet we want different results for different keys. Luckily the mocks have a filter system... $config = &new MockConfiguration(); $config->setReturnValue('getValue', 'primary', array('db_host')); $config->setReturnValue('getValue', 'admin', array('db_user')); $config->setReturnValue('getValue', 'secret', array('db_password')); ]]> The extra parameter is a list of arguments to attempt to match. In this case we are trying to match only one argument which is the look up key. Now when the mock object has the getValue() method invoked like this... getValue('db_user') ]]> ...it will return "admin". It finds this by attempting to match the calling arguments to its list of returns one after another until a complete match is found.

    You can set a default argument argument like so... $config->setReturnValue('getValue', false, array('*')); ]]> This is not the same as setting the return value without any argument requirements like this... $config->setReturnValue('getValue', false); ]]> In the first case it will accept any single argument, but exactly one is required. In the second case any number of arguments will do and it acts as a catchall after all other matches. Note that if we add further single parameter options after the wildcard in the first case, they will be ignored as the wildcard will match first. With complex parameter lists the ordering could be important or else desired matches could be masked by earlier wildcard ones. Declare the most specific matches first if you are not sure.

    There are times when you want a specific object to be dished out by the mock rather than a copy. The PHP4 copy semantics force us to use a different method for this. You might be simulating a container for example... In this case you can set a reference into the mock's return list... $vector = &new MockVector(); $vector->setReturnReference('get', $thing, array(12)); ]]> With this arrangement you know that every time get(12)]]> is called it will return the same $thing each time. This is compatible with PHP5 as well.

    These three factors, timing, parameters and whether to copy, can be combined orthogonally. For example... $complex->setReturnReferenceAt(3, 'get', $stuff, array('*', 1)); ]]> This will return the $stuff only on the third call and only if two parameters were set the second of which must be the integer 1. That should cover most simple prototyping situations.

    A final tricky case is one object creating another, known as a factory pattern. Suppose that on a successful query to our imaginary database, a result set is returned as an iterator with each call to next() giving one row until false. This sounds like a simulation nightmare, but in fact it can all be mocked using the mechanics above.

    Here's how... $result = &new MockResultIterator(); $result->setReturnValue('next', false); $result->setReturnValueAt(0, 'next', array(1, 'tom')); $result->setReturnValueAt(1, 'next', array(3, 'dick')); $result->setReturnValueAt(2, 'next', array(6, 'harry')); $connection = &new MockDatabaseConnection(); $connection->setReturnValue('query', false); $connection->setReturnReference( 'query', $result, array('select id, name from users')); $finder = &new UserFinder($connection); $this->assertIdentical( $finder->findNames(), array('tom', 'dick', 'harry')); } } ]]> Now only if our $connection is called with the correct query() will the $result be returned that is itself exhausted after the third call to next(). This should be enough information for our UserFinder class, the class actually being tested here, to come up with goods. A very precise test and not a real database in sight.

    Although the server stubs approach insulates your tests from real world disruption, it is only half the benefit. You can have the class under test receiving the required messages, but is your new class sending correct ones? Testing this can get messy without a mock objects library.

    By way of example, suppose we have a SessionPool class that we want to add logging to. Rather than grow the original class into something more complicated, we want to add this behaviour with a decorator (GOF). The SessionPool code currently looks like this... class SessionPool { function SessionPool() { ... } function &findSession($cookie) { ... } ... } class Session { ... } While our logging code looks like this... class Log { function Log() { ... } function message() { ... } } class LoggingSessionPool { function LoggingSessionPool(&$session_pool, &$log) { ... } function &findSession(\$cookie) { ... } ... } ]]> Out of all of this, the only class we want to test here is the LoggingSessionPool. In particular we would like to check that the findSession() method is called with the correct session ID in the cookie and that it sent the message "Starting session $cookie" to the logger.

    Despite the fact that we are testing only a few lines of production code, here is what we would have to do in a conventional test case:

    1. Create a log object.
    2. Set a directory to place the log file.
    3. Set the directory permissions so we can write the log.
    4. Create a SessionPool object.
    5. Hand start a session, which probably does lot's of things.
    6. Invoke findSession().
    7. Read the new Session ID (hope there is an accessor!).
    8. Raise a test assertion to confirm that the ID matches the cookie.
    9. Read the last line of the log file.
    10. Pattern match out the extra logging timestamps, etc.
    11. Assert that the session message is contained in the text.
    It is hardly surprising that developers hate writing tests when they are this much drudgery. To make things worse, every time the logging format changes or the method of creating new sessions changes, we have to rewrite parts of this test even though this test does not officially test those parts of the system. We are creating headaches for the writers of these other classes.

    Instead, here is the complete test method using mock object magic... $session = &new MockSession(); $pool = &new MockSessionPool(); $pool->setReturnReference('findSession', $session); $pool->expectOnce('findSession', array('abc')); $log = &new MockLog(); $log->expectOnce('message', array('Starting session abc')); $logging_pool = &new LoggingSessionPool($pool, $log); $this->assertReference($logging_pool->findSession('abc'), $session); } } ]]> We start by creating a dummy session. We don't have to be too fussy about this as the check for which session we want is done elsewhere. We only need to check that it was the same one that came from the session pool.

    findSession() is a factory method the simulation of which is described above. The point of departure comes with the first expectOnce() call. This line states that whenever findSession() is invoked on the mock, it will test the incoming arguments. If it receives the single argument of a string "abc" then a test pass is sent to the unit tester, otherwise a fail is generated. This was the part where we checked that the right session was asked for. The argument list follows the same format as the one for setting return values. You can have wildcards and sequences and the order of evaluation is the same.

    We use the same pattern to set up the mock logger. We tell it that it should have message() invoked once only with the argument "Starting session abc". By testing the calling arguments, rather than the logger output, we insulate the test from any display changes in the logger.

    We start to run our tests when we create the new LoggingSessionPool and feed it our preset mock objects. Everything is now under our control.

    This is still quite a bit of test code, but the code is very strict. If it still seems rather daunting there is a lot less of it than if we tried this without mocks and this particular test, interactions rather than output, is always more work to set up. More often you will be testing more complex situations without needing this level or precision. Also some of this can be refactored into a test case setUp() method.

    Here is the full list of expectations you can set on a mock object in SimpleTest...
    ExpectationNeeds tally()
    expect($method, $args) No
    expectAt($timing, $method, $args) No
    expectCallCount($method, $count) Yes
    expectMaximumCallCount($method, $count) No
    expectMinimumCallCount($method, $count) Yes
    expectNever($method) No
    expectOnce($method, $args) Yes
    expectAtLeastOnce($method, $args) Yes
    Where the parameters are...

    $method
    The method name, as a string, to apply the condition to.
    $args
    The arguments as a list. Wildcards can be included in the same manner as for setReturn(). This argument is optional for expectOnce() and expectAtLeastOnce().
    $timing
    The only point in time to test the condition. The first call starts at zero.
    $count
    The number of calls expected.
    The method expectMaximumCallCount() is slightly different in that it will only ever generate a failure. It is silent if the limit is never reached.

    Like the assertions within test cases, all of the expectations can take a message override as an extra parameter. Also the original failure message can be embedded in the output as "%s".

    There are three approaches to creating mocks including the one that SimpleTest employs. Coding them by hand using a base class, generating them to a file and dynamically generating them on the fly.

    Mock objects generated with SimpleTest are dynamic. They are created at run time in memory, using eval(), rather than written out to a file. This makes the mocks easy to create, a one liner, especially compared with hand crafting them in a parallel class hierarchy. The problem is that the behaviour is usually set up in the tests themselves. If the original objects change the mock versions that the tests rely on can get out of sync. This can happen with the parallel hierarchy approach as well, but is far more quickly detected.

    The solution, of course, is to add some real integration tests. You don't need very many and the convenience gained from the mocks more than outweighs the small amount of extra testing. You cannot trust code that was only tested with mocks.

    If you are still determined to build static libraries of mocks because you want to simulate very specific behaviour, you can achieve the same effect using the SimpleTest class generator. In your library file, say mocks/connection.php for a database connection, create a mock and inherit to override special methods or add presets... Mock::generate('Connection', 'BasicMockConnection'); class MockConnection extends BasicMockConnection { function MockConnection() { $this->BasicMockConnection(); $this->setReturn('query', false); } } ?> ]]> The generate call tells the class generator to create a class called BasicMockConnection rather than the usual MockConnection. We then inherit from this to get our version of MockConnection. By intercepting in this way we can add behaviour, here setting the default value of query() to be false. By using the default name we make sure that the mock class generator will not recreate a different one when invoked elsewhere in the tests. It never creates a class if it already exists. As long as the above file is included first then all tests that generated MockConnection should now be using our one instead. If we don't get the order right and the mock library creates one first then the class creation will simply fail.

    Use this trick if you find you have a lot of common mock behaviour or you are getting frequent integration problems at later stages of testing.

    What are mock objects? Creating mock objects. Mocks as actors or stubs. Mocks as critics with expectations. Other approaches including mock libraries. The original Mock objects paper. SimpleTest project page on SourceForge. SimpleTest home page on LastCraft. software development, php programming, programming php, software development tools, php tutorial, free php scripts, architecture, php resources, mock objects, junit, php testing, unit test, php testing, jmock, nmock
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/group_test_tutorial.xml0000664000175000017620000002144711157271050027313 0ustar davidpalepurple PHP unit testing tutorial - Grouping together unit tests and examples of writing test cases

    Next up we will fill in some blanks and create a test suite.

    Another test

    Adding another test can be as simple as adding another method to a test case... UnitTestCase('Log class test'); } function testCreatingNewFile() { @unlink('../temp/test.log'); $log = new Log('../temp/test.log'); $this->assertFalse(file_exists('../temp/test.log'), 'Created before message'); $log->message('Should write this to a file'); $this->assertTrue(file_exists('../temp/test.log'), 'File created'); @unlink('../temp/test.log'); } function testAppendingToFile() { @unlink('../temp/test.log'); $log = new Log('../temp/test.log'); $log->message('Test line 1'); $messages = file('../temp/test.log'); $this->assertWantedPattern('/Test line 1/', $messages[0]); $log->message('Test line 2'); $messages = file('../temp/test.log'); $this->assertWantedPattern('/Test line 2/', $messages[1]); @unlink('../temp/test.log'); } } ]]> The assertWantedPattern() test case method uses Perl style regular expressions for matching.

    All we are doing in this new test method is writing a line to a file and reading it back twice over. We simply want to confirm that the logger appends the text rather than writing over the old file. A little pedantic, but hey, it's a tutorial!

    In fact this unit test actually passes straight away...

    Log class test

    1/1 test cases complete. 4 passes and 0 fails.
    The trouble is there is already a lot of repetition here, we have to delete the test file before and after every test. With outrageous plagarism from JUnit, SimpleTest has setUp() and tearDown() methods which are run before and after every test respectively. File deletion is common to all the test methods so we should move that operation there.

    Our tests are green so we can refactor... UnitTestCase('Log class test'); } function setUp() { @unlink('../temp/test.log'); } function tearDown() { @unlink('../temp/test.log'); } function testCreatingNewFile() { $log = new Log('../temp/test.log'); $this->assertFalse(file_exists('../temp/test.log'), 'Created before message'); $log->message('Should write this to a file'); $this->assertTrue(file_exists('../temp/test.log'), 'File created'); } function testAppendingToFile() { $log = new Log('../temp/test.log'); $log->message('Test line 1'); $messages = file('../temp/test.log'); $this->assertWantedPattern('/Test line 1/', $messages[0]); $log->message('Test line 2'); $messages = file('../temp/test.log'); $this->assertWantedPattern('/Test line 2/', $messages[1]); } } ]]> The test stays green. We can add non-test methods to the test case as long as the method name does not start with the string "test". Only the methods that start "test" are run. This allows further optional refactoring... UnitTestCase('Log class test'); } function setUp() { @unlink('../temp/test.log'); } function tearDown() { @unlink('../temp/test.log'); } function getFileLine($filename, $index) { $messages = file($filename); return $messages[$index]; } function testCreatingNewFile() { $log = new Log('../temp/test.log'); $this->assertFalse(file_exists('../temp/test.log'), 'Created before message'); $log->message('Should write this to a file'); $this->assertTrue(file_exists('../temp/test.log'), 'File created'); } function testAppendingToFile() { $log = new Log('../temp/test.log'); $log->message('Test line 1'); $this->assertWantedPattern('/Test line 1/', $this->getFileLine('../temp/test.log', 0)); $log->message('Test line 2'); $this->assertWantedPattern('/Test line 2/', $this->getFileLine('../temp/test.log', 1)); } } ]]> It is a matter of taste whether you prefer this version to the previous one. There is a little more code, but the logic of the test is clearer.

    A group test

    A test case does not function alone for very long. When coding for real we usually want to run as many tests as quickly and as often as we can. This means grouping them together into test suites that could easily include every test in the application.

    Firstly we have to clean out the test running code from our existing test case... require_once('../classes/log.php'); class TestOfLogging extends UnitTestCase { ... } ?> ]]> We no longer need the SIMPLE_TEST constant. Next we create a group test called all_tests.php in the tests folder... addTestCase(new TestOfLogging()); $test->run(new HtmlReporter()); ?> ]]> We hardly notice the difference when things work...

    All tests

    1/1 test cases complete. 4 passes and 0 fails.
    Group tests add to the test case count. Adding new test cases is very straight forward. Simply include the test cases file and add any contained test cases individually. You can also nest group tests within other group tests (although you should avoid loops).

    In the next page we will add these more quickly.

    Adding another test to the test case and refactoring. The crude way to group unit tests. Next is controlling how the class under test interacts with the rest of the system. Previous is the creation of a first test. You need SimpleTest to run these examples. software development, php programming, programming in php, test first, software development tools, php tutorial, free php scripts, architecture, php resources, mock objects, junit, php testing, unit test, phpunit, PHP unit testing
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/support_website.xml0000664000175000017620000000304311157271050026423 0ustar davidpalepurple Support mailing list

    The simpletest-support mailing-list is probably the most active area around SimpleTest : help, advice, bugs and workarounds tend to happen most of the time.

    It's really easy to subscribe and it's fully searchable too.

    At the last count, there were about 114 subscribers and 1908 message sent. That's anything between 1 and 4 messages per day on average.

    Current release Eclipse release Packages Source Older stable releases SimpleTest, download, source code, stable release, eclipse release, eclipse plugin, debian package, drupal module, pear channel, pearified package
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/reporter_documentation.xml0000664000175000017620000004746411157271050027777 0ustar davidpalepurple SimpleTest for PHP test runner and display documentation

    SimpleTest pretty much follows the MVC pattern (Model-View-Controller). The reporter classes are the view and the model is your test cases and their hiearchy. The controller is mostly hidden from the user of SimpleTest unless you want to change how the test cases are actually run, in which case it is possible to override the runner objects from within the test case. As usual with MVC, the controller is mostly undefined and there are other places to control the test run.

    The default test display is minimal in the extreme. It reports success and failure with the conventional red and green bars and shows a breadcrumb trail of test groups for every failed assertion. Here's a fail...

    File test

    Fail: createnewfile->True assertion failed.
    1/1 test cases complete. 0 passes, 1 fails and 0 exceptions.
    And here all tests passed...

    File test

    1/1 test cases complete. 1 passes, 0 fails and 0 exceptions.
    The good news is that there are several points in the display hiearchy for subclassing.

    For web page based displays there is the HtmlReporter class with the following signature... Here is what some of these methods mean. First the display methods that you will probably want to override...

    • HtmlReporter(string $encoding)
      is the constructor. Note that the unit test sets up the link to the display rather than the other way around. The display is a mostly passive receiver of test events. This allows easy adaption of the display for other test systems beside unit tests, such as monitoring servers. The encoding is the character encoding you wish to display the test output in. In order to correctly render debug output when using the web tester, this should match the encoding of the site you are trying to test. The available character set strings are described in the PHP html_entities() function.
    • void paintHeader(string $test_name)
      is called once at the very start of the test when the first start event arrives. The first start event is usually delivered by the top level group test and so this is where $test_name comes from. It paints the page titles, CSS, body tag, etc. It returns nothing (void).
    • void paintFooter(string $test_name)
      Called at the very end of the test to close any tags opened by the page header. By default it also displays the red/green bar and the final count of results. Actually the end of the test happens when a test end event comes in with the same name as the one that started it all at the same level. The tests nest you see. Closing the last test finishes the display.
    • void paintMethodStart(string $test_name)
      is called at the start of each test method. The name normally comes from method name. The other test start events behave the same way except that the group test one tells the reporter how large it is in number of held test cases. This is so that the reporter can display a progress bar as the runner churns through the test cases.
    • void paintMethodEnd(string $test_name)
      backs out of the test started with the same name.
    • void paintFail(string $message)
      paints a failure. By default it just displays the word fail, a breadcrumbs trail showing the current test nesting and the message issued by the assertion.
    • void paintPass(string $message)
      by default does nothing.
    • string _getCss()
      Returns the CSS styles as a string for the page header method. Additional styles have to be appended here if you are not overriding the page header. You will want to use this method in an overriden page header if you want to include the original CSS.
    There are also some accessors to get information on the current state of the test suite. Use these to enrich the display...
    • array getTestList()
      is the first convenience method for subclasses. Lists the current nesting of the tests as a list of test names. The first, most deeply nested test, is first in the list and the current test method will be last.
    • integer getPassCount()
      returns the number of passes chalked up so far. Needed for the display at the end.
    • integer getFailCount()
      is likewise the number of fails so far.
    • integer getExceptionCount()
      is likewise the number of errors so far.
    • integer getTestCaseCount()
      is the total number of test cases in the test run. This includes the grouping tests themselves.
    • integer getTestCaseProgress()
      is the number of test cases completed so far.
    One simple modification is to get the HtmlReporter to display the passes as well as the failures and errors... class ShowPasses extends HtmlReporter { function paintPass($message) { parent::paintPass($message); print "&Pass: "; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); print implode("->", $breadcrumb); print "->$message
    \n"; } function _getCss() { return parent::_getCss() . ' .pass { color: green; }'; } } ]]>

    One method that was glossed over was the makeDry() method. If you run this method, with no parameters, on the reporter before the test suite is run no actual test methods will be called. You will still get the events of entering and leaving the test methods and test cases, but no passes or failures etc, because the test code will not actually be executed.

    The reason for this is to allow for more sophistcated GUI displays that allow the selection of individual test cases. In order to build a list of possible tests they need a report on the test structure for drawing, say a tree view of the test suite. With a reporter set to dry run that just sends drawing events this is easily accomplished.

    Rather than simply modifying the existing display, you might want to produce a whole new HTML look, or even generate text or XML. Rather than override every method in HtmlReporter we can take one step up the class hiearchy to SimpleReporter in the simple_test.php source file.

    A do nothing display, a blank canvas for your own creation, would be... require_once('simpletest/simple_test.php'); class MyDisplay extends SimpleReporter { function paintHeader($test_name) { } function paintFooter($test_name) { } function paintStart($test_name, $size) { parent::paintStart($test_name, $size); } function paintEnd($test_name, $size) { parent::paintEnd($test_name, $size); } function paintPass($message) { parent::paintPass($message); } function paintFail($message) { parent::paintFail($message); } } ]]> No output would come from this class until you add it.

    SimpleTest also ships with a minimal command line reporter. The interface mimics JUnit to some extent, but paints the failure messages as they arrive. To use the command line reporter simply substitute it for the HTML version... addTestFile('tests/file_test.php'); $test->run(new TextReporter()); ?> ]]> Then invoke the test suite from the command line...

    php file_test.php
    
    You will need the command line version of PHP installed of course. A passing test suite looks like this...
    File test
    OK
    Test cases run: 1/1, Failures: 0, Exceptions: 0
    
    A failure triggers a display like this...
    File test
    1) True assertion failed.
    	in createnewfile
    FAILURES!!!
    Test cases run: 1/1, Failures: 1, Exceptions: 0
    

    One of the main reasons for using a command line driven test suite is of using the tester as part of some automated process. To function properly in shell scripts the test script should return a non-zero exit code on failure. If a test suite fails the value false is returned from the SimpleTest::run() method. We can use that result to exit the script with the desired return code... addTestFile('tests/file_test.php'); exit ($test->run(new TextReporter()) ? 0 : 1); ?> ]]> Of course we don't really want to create two test scripts, a command line one and a web browser one, for each test suite. The command line reporter includes a method to sniff out the run time environment... addTestFile('tests/file_test.php'); if (TextReporter::inCli()) { exit ($test->run(new TextReporter()) ? 0 : 1); } $test->run(new HtmlReporter()); ?> ]]> This is the form used within SimpleTest itself.

    SimpleTest ships with an XmlReporter class used for internal communication. When run the output looks like...

    
    
      
        Remote tests
        
          Visual test with 48 passes, 48 fails and 4 exceptions
          
            testofunittestcaseoutput
            
              testofresults
              This assertion passed
              This assertion failed
            
            
              ...
            
          
        
      
    
    ]]>
    You can make use of this format with the parser supplied as part of SimpleTest itself. This is called SimpleTestXmlParser and resides in xml.php within the SimpleTest package... parse($test_output); ?> ]]> The $test_output should be the XML format from the XML reporter, and could come from say a command line run of a test case. The parser sends events to the reporter just like any other test run. There are some odd occasions where this is actually useful.

    A problem with large test suites is thet they can exhaust the default 8Mb memory limit on a PHP process. By having the test groups output in XML and run in separate processes, the output can be reparsed to aggregate the results into a much smaller footprint top level test.

    Because the XML output can come from anywhere, this opens up the possibility of aggregating test runs from remote servers. A test case already exists to do this within the SimpleTest framework, but it is currently experimental... require_once('../remote.php'); require_once('../reporter.php'); $test_url = ...; $dry_url = ...; $test = &new TestSuite('Remote tests'); $test->addTestCase(new RemoteTestCase($test_url, $dry_url)); $test->run(new HtmlReporter()); ?> ]]> The RemoteTestCase takes the actual location of the test runner, basically a web page in XML format. It also takes the URL of a reporter set to do a dry run. This is so that progress can be reported upward correctly. The RemoteTestCase can be added to test suites just like any other group test.

    Displaying results in HTML Displaying and reporting results in other formats Using SimpleTest from the command line Using Using XML for remote testing SimpleTest project page on SourceForge. SimpleTest download page on LastCraft. The developer's API for SimpleTest gives full detail on the classes and assertions available. php unit testing, documentation, marcus baker, simple test, simpletest, remote testing, xml tests, automated testing
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/intro.xml0000664000175000017620000000357211157271050024327 0ustar davidpalepurple The Last Craft? Web developer tutorials on PHP, Extreme programming and Object Oriented development

    The SimpleTest PHP unit tester is in the 1.0.1 release cycle and is available for download from your nearest SourceForge.

    It is a PHP unit test, mock objects and web test framework. Users of JUnit will be familiar with most of the interface. JWebUnit style functionality is more complete now. It has support for SSL, frames, proxies, basic authentication and the standard HTML controls. The idea is that common but fiddly PHP tasks, such as logging into a site, can be tested easily.

    There is currently no support for JavaScript in the web tester. For testing these elements we recommend JSUnit or Selenium.

    software development, computer programmer, php programming, programming php, software development tools, software development company, php tutorial, free php scripts, bespoke software development uk, corporate web development, architecture, php resources, unit test, php testing, test cases tutorial, explain unit test case, unit test example, xml
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/display_subclass_tutorial.xml0000664000175000017620000002662611157271050030470 0ustar davidpalepurple PHP unit testing tutorial - Subclassing the test display

    The display component of SimpleTest is actually the part to be developed last. Some of the following section will change in the future and hopefully more sophisticated display components will be written, but in the meantime if a minimal display is not enough, here is how to roll your own.

    I want to see the passes!

    Oh all right then, here's how.

    We have to subclass the attached display, which in our case is currently HtmlReporter. The HtmlReporter class is in the file simpletest/reporter.php and currently has the following interface... Here is what the relevant methods mean. You can see the whole list here if you are interested.

    • HtmlReporter()
      is the constructor. Note that the unit test sets up the link to the display rather than the other way around. The display is a passive receiver of test events. This allows easy adaption of the display for other test systems beside unit tests, such as monitoring servers. It also means that the unit test can write to more than one display at a time.
    • void paintFail(string $message)
      paints a failure. See below.
    • void paintPass(string $message)
      by default does nothing. This is the method we will modify.
    • string _getCss()
      returns the CSS styles as a string for the page header method. Additional styles have to be appended here.
    • array getTestList()
      is a convenience method for subclasses. Lists the current nesting of the tests as a list of test names. The first, most deeply nested test, is first in the list and the current test method will be last.

    To show the passes we just need the paintPass() method to behave just like paintFail(). Of course we won't modify the original. We'll subclass.

    A display subclass

    Firstly we'll create a tests/show_passes.php file in our logging project and then place in it this empty class... HtmlReporter(); } } ?> ]]> A quick peruse of the SimpleTest code base shows the paintFail() implementation at the time of writing to look like this... Fail: "; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); print implode("->", $breadcrumb); print "->$message
    \n"; } ]]>
    Essentially it chains to the parent's version, which we have to do also to preserve house keeping, and then prints a breadcrumbs trail calculated from the current test list. It drops the top level tests name, though. As it is the same on every test that would be a little bit too much information. Transposing this to our new class... HtmlReporter(); } function paintPass($message) { parent::paintPass($message); print "Pass: "; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); print implode("->", $breadcrumb); print "->$message
    \n"; }
    } ]]>
    So far so good. Now to make use of our new class we have to modify our tests/all_tests.php file... require_once('show_passes.php'); $test = &new TestSuite('All tests'); $test->addTestFile('log_test.php'); $test->addTestFile('clock_test.php'); $test->run(new ShowPasses()); ?> ]]> We can run this to see the results of our handywork...

    All tests

    Pass: log_test.php->Log class test->testappendingtofile->Expecting [/Test line 1/] in [Test line 1]
    Pass: log_test.php->Log class test->testappendingtofile->Expecting [/Test line 2/] in [Test line 2]
    Pass: log_test.php->Log class test->testcreatingnewfile->Created before message
    Pass: log_test.php->Log class test->testcreatingnewfile->File created
    Pass: clock_test.php->Clock class test->testclockadvance->Advancement
    Pass: clock_test.php->Clock class test->testclocktellstime->Now is the right time
    3/3 test cases complete. 6 passes and 0 fails.
    Nice, but no gold star. We have lost a little formatting here. The display does not have a CSS style for span.pass, but we can add this easily by overriding one more method... HtmlReporter(); } function paintPass($message) { parent::paintPass($message); print "Pass: "; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); print implode("->", $breadcrumb); print "->$message
    \n"; } function _getCss() { return parent::_getCss() . ' .pass { color: green; }'; } } ]]>
    If you are adding the code as you go, you will see the style appended when you do view source on the test results page in your browser. To the eye the display itself should now look like this...

    All tests

    Pass: log_test.php->Log class test->testappendingtofile->Expecting [/Test line 1/] in [Test line 1]
    Pass: log_test.php->Log class test->testappendingtofile->Expecting [/Test line 2/] in [Test line 2]
    Pass: log_test.php->Log class test->testcreatingnewfile->Created before message
    Pass: log_test.php->Log class test->testcreatingnewfile->File created
    Pass: clock_test.php->Clock class test->testclockadvance->Advancement
    Pass: clock_test.php->Clock class test->testclocktellstime->Now is the right time
    3/3 test cases complete. 6 passes and 0 fails.
    Some people definitely prefer to see the passes being added as they are working on code; the feeling that you are getting work done is nice after all. Once you have to scroll up and down the page to find failures though, you soon come to realise its dark side.

    Try it both ways and see which you prefer. We'll leave it in for a bit anyhow when looking at the mock objects coming up. This is the first test tool that generates additional tests and it will be useful to see what is happening behind the scenes.

    How to Change the display to show test passes. Subclassing the HtmlReporter class. The previous tutorial section was subclassing the test case. This section is very specific to SimpleTest. If you use another tool you will want to skip this. software development test first, php general programming advice, programming php, software development tools, php tutorial, free php sample code, architecture, sample test cases, php simple test framework, php resources, php test case examples, phpunit, simpletest, unit test, php testing
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/simple_test.xml0000664000175000017620000004432711157271050025527 0ustar davidpalepurple Download the Simple Test testing framework - Unit tests and mock objects for PHP 1.0.1 release cycle started. Features include include file upload, better PHP5 support for mock objects, and HTML label support. There is also a big clean up of method names and some internals refactoring.

    The following assumes that you are familiar with the concept of unit testing as well as the PHP web development language. It is a guide for the impatient new user of SimpleTest. For fuller documentation, especially if you are new to unit testing see the ongoing documentation, and for example test cases see the unit testing tutorial.

    Amongst software testing tools, a unit tester is the one closest to the developer. In the context of agile development the test code sits right next to the source code as both are written simultaneously. In this context SimpleTest aims to be a complete PHP developer test solution and is called "Simple" because it should be easy to use and extend. It wasn't a good choice of name really. It includes all of the typical functions you would expect from JUnit and the PHPUnit ports, but also adds mock objects. It has some JWebUnit functionality as well. This includes web page navigation, cookie testing and form submission.

    The quickest way to demonstrate is with an example.

    Let us suppose we are testing a simple file logging class called Log in classes/log.php. We start by creating a test script which we will call tests/log_test.php and populate it as follows... require_once('simpletest/unit_tester.php'); require_once('simpletest/reporter.php'); require_once('../classes/log.php'); class TestOfLogging extends UnitTestCase { } ?> ]]> Here the simpletest folder is either local or in the path. You would have to edit these locations depending on where you placed the toolset. The TestOfLogging is our frst test case and it's currently empty.

    Now we have five lines of scaffolding code and still no tests. However from this part on we get return on our investment very quickly. We'll assume that the Log class takes the file name to write to in the constructor and we have a temporary folder in which to place this file... function testCreatingNewFile() { @unlink('/temp/test.log'); $log = new Log('/temp/test.log'); $this->assertFalse(file_exists('/temp/test.log')); $log->message('Should write this to a file'); $this->assertTrue(file_exists('/temp/test.log')); } } ?> ]]> When a test case runs it will search for any method that starts with the string test and execute that method. We would normally have more than one test method of course. Assertions within the test methods trigger messages to the test framework which displays the result immediately. This immediate response is important, not just in the event of the code causing a crash, but also so that print statements can display their content right next to the test case concerned.

    To see these results we have to actually run the tests. If this is the only test case we wish to run we can achieve it with... assertFalse(file_exists('/temp/test.log')); $log->message('Should write this to a file'); $this->assertTrue(file_exists('/temp/test.log')); } } $test = &new TestOfLogging(); $test->run(new HtmlReporter()); ?> ]]>

    On failure the display looks like this...

    testoflogging

    Fail: testcreatingnewfile->True assertion failed.
    1/1 test cases complete. 1 passes and 1 fails.
    ...and if it passes like this...

    testoflogging

    1/1 test cases complete. 2 passes and 0 fails.
    And if you get this...
    Fatal error: Failed opening required '../classes/log.php' (include_path='') in /home/marcus/projects/lastcraft/tutorial_tests/Log/tests/log_test.php on line 7
    it means you're missing the classes/Log.php file that could look like... ; ]]>

    It is unlikely in a real application that we will only ever run one test case. This means that we need a way of grouping cases into a test script that can, if need be, run every test in the application.

    Our first step is to strip the includes and to undo our previous hack... require_once('../classes/log.php'); class TestOfLogging extends UnitTestCase { function testCreatingNewFile() { @unlink('/temp/test.log'); $log = new Log('/temp/test.log'); $this->assertFalse(file_exists('/temp/test.log')); $log->message('Should write this to a file'); $this->assertTrue(file_exists('/temp/test.log')); } } ?> ]]> Next we create a new file called tests/all_tests.php and insert the following code... addTestFile('log_test.php'); $test->run(new HtmlReporter()); ?> ]]> The method TestSuite::addTestFile() will include the test case file and read any new classes created that are descended from SimpleTestCase, of which UnitTestCase is one example. Just the class names are stored for now, so that the test runner can instantiate the class when it works its way through your test suite.

    For this to work properly the test case file should not blindly include any other test case extensions that do not actually run tests. This could result in extra test cases being counted during the test run. Hardly a major problem, but to avoid this inconvenience simply add a SimpleTestOptions::ignore() directive somewhere in the test case file. Also the test case file should not have been included elsewhere or no cases will be added to this group test. This would be a more serious error as if the test case classes are already loaded by PHP the TestSuite::addTestFile() method will not detect them.

    To display the results it is necessary only to invoke tests/all_tests.php from the web server.

    Let's move further into the future.

    Assume that our logging class is tested and completed. Assume also that we are testing another class that is required to write log messages, say a SessionPool. We want to test a method that will probably end up looking like this... class SessionPool { ... function logIn($username) { ... $this->_log->message("User $username logged in."); ... } ... } ]]> In the spirit of reuse we are using our Log class. A conventional test case might look like this... logIn('fred'); $messages = file('/temp/test.log'); $this->assertEqual($messages[0], "User fred logged in.\n"); } } ?> ]]> This test case design is not all bad, but it could be improved. We are spending time fiddling with log files which are not part of our test. Worse, we have created close ties with the Log class and this test. What if we don't use files any more, but use ths syslog library instead? Did you notice the extra carriage return in the message? Was that added by the logger? What if it also added a time stamp or other data?

    The only part that we really want to test is that a particular message was sent to the logger. We reduce coupling if we can pass in a fake logging class that simply records the message calls for testing, but takes no action. It would have to look exactly like our original though.

    If the fake object doesn't write to a file then we save on deleting the file before and after each test. We could save even more test code if the fake object would kindly run the assertion for us.

    Too good to be true? Luckily we can create such an object easily... Mock::generate('Log'); class TestOfSessionLogging extends UnitTestCase { function testLogInIsLogged() { $log = &new MockLog(); $log->expectOnce('message', array('User fred logged in.')); $session_pool = &new SessionPool($log); $session_pool->logIn('fred'); } } ?> ]]> The test will be triggered when the call to message() is invoked on the MockLog object. The mock call will trigger a parameter comparison and then send the resulting pass or fail event to the test display. Wildcards can be included here too so as to prevent tests becoming too specific.

    If the mock reaches the end of the test case without the method being called, the expectOnce() expectation will trigger a test failure. In other words the mocks can detect the absence of behaviour as well as the presence.

    The mock objects in the SimpleTest suite can have arbitrary return values set, sequences of returns, return values selected according to the incoming arguments, sequences of parameter expectations and limits on the number of times a method is to be invoked.

    For this test to run the mock objects library must have been included in the test suite, say in all_tests.php.

    One of the requirements of web sites is that they produce web pages. If you are building a project top-down and you want to fully integrate testing along the way then you will want a way of automatically navigating a site and examining output for correctness. This is the job of a web tester.

    The web testing in SimpleTest is fairly primitive, there is no JavaScript for example. To give an idea here is a trivial example where a home page is fetched, from which we navigate to an "about" page and then test some client determined content. require_once('simpletest/web_tester.php'); require_once('simpletest/reporter.php'); class TestOfAbout extends WebTestCase { function setUp() { $this->get('http://test-server/index.php'); $this->click('About'); } function testSearchEngineOptimisations() { $this->assertTitle('A long title about us for search engines'); $this->assertPattern('/a popular keyphrase/i'); } } $test = &new TestOfAbout(); $test->run(new HtmlReporter()); ?> ]]> With this code as an acceptance test you can ensure that the content always meets the specifications of both the developers and the other project stakeholders.

    SourceForge.net Logo

    Using unit tester with an example. Grouping tests for testing with one click. Using mock objects to ease testing and gain tighter control. Testing web pages at the browser level. Download PHP Simple Test from SourceForge. The developer's API for SimpleTest gives full detail on the classes and assertions available. software development, php programming, programming php, software development tools, php tutorial, free php scripts, architecture, php resources, mock objects, junit, php testing, php unit, methodology, test first, sourceforge, open source, unit test, web tester, web testing, html testing tools, testing web pages, php mock objects, navigating websites automatically, automated testing, web scripting, wget, curl testing, jmock for php, jwebunit, phpunit, php unit testing, php web testing, jason sweat, marcus baker, topstyle plug in, phpedit plug in
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/group_test_documentation.xml0000664000175000017620000003026411157271050030316 0ustar davidpalepurple SimpleTest for PHP test suites

    To run test cases as part of a group, the test cases should really be placed in files without the runner code... ]]> As many cases as needed can appear in a single file. They should include any code they need, such as the library being tested, but none of the simple test libraries.

    If you have extended any test cases, you can include them as well. In PHP 4... class MyFileTestCase extends UnitTestCase { ... } SimpleTest::ignore('MyFileTestCase'); class FileTester extends MyFileTestCase { ... } class SocketTester extends UnitTestCase { ... } ?> ]]> The FileTester class does not contain any actual tests, but is a base class for other test cases. For this reason we use the SimpleTestOptions::ignore() directive to tell the upcoming group test to ignore it. This directive can appear anywhere in the file and works when a whole file of test cases is loaded (see below).

    If you are using PHP 5, you do not need this special directive at all. Simply mark any test cases that should not be run as abstract... abstract class MyFileTestCase extends UnitTestCase { ... } class FileTester extends MyFileTestCase { ... } class SocketTester extends UnitTestCase { ... } ]]>

    We will call this sample file_test.php. Next we create a group test file, called say my_group_test.php. You will think of a better name I am sure.

    We will add the test file using a safe method... require_once('file_test.php'); $test = &new TestSuite('All file tests'); $test->addTestCase(new FileTestCase()); $test->run(new HtmlReporter()); ?> ]]> This instantiates the test case before the test suite is run. This could get a little expensive with a large number of test cases, and can be surprising behaviour.

    The main problem is that for every test case that we add we will have to require_once() the test code file and manually instantiate each and every test case.

    We can save a lot of typing with... $test->addTestFile('file_test.php'); $test->run(new HtmlReporter()); ?> ]]> What happens here is that the TestSuite class has done the require_once() for us. It then checks to see if any new test case classes have been created by the new file and automatically adds them to the group test. Now all we have to do is add each new file.

    No only that, but you can guarantee that the constructor is run just before the first test method and, in PHP 5, the destructor is run just after the last test method.

    There are two things that could go wrong and which require care...

    1. The file could already have been parsed by PHP, and so no new classes will have been added. You should make sure that the test cases are only included in this file and no others.
    2. New test case extension classes that get included will be placed in the group test and run also. You will need to add a SimpleTestOptions::ignore() directive for these classes, or make sure that they are included before the TestSuite::addTestFile() line, or make sure that they are abstract classes.

    The above method places all of the test cases into one large group. For larger projects though this may not be flexible enough; you may want to group the tests in all sorts of ways.

    To get a more flexible group test we can subclass TestSuite and then instantiate it as needed... class FileTestSuite extends TestSuite { function FileTestSuite() { $this->TestSuite('All file tests'); $this->addTestFile('file_test.php'); } } ?> ]]> This effectively names the test in the constructor and then adds our test cases and a single group below. Of course we can add more than one group at this point. We can now invoke the tests from a separate runner file... $test = &new FileTestSuite(); $test->run(new HtmlReporter()); ?> ]]> ...or we can group them into even larger group tests. We can even mix groups and test cases freely as long as we are careful about double includes... $test = &new BigTestSuite('Big group'); $test->addTestFile('file_test_suite.php'); $test->addTestFile('some_test_case.php'); $test->run(new HtmlReporter()); ?> ]]> In the event of a double include, ony the first instance of the test case will be run.

    If we still wish to run the original group test, and we don't want all of these little runner files, we can put the test runner code around guard bars when we create each group. TestSuite('All file tests'); $test->addTestFile('file_test.php'); } } if (! defined('RUNNER')) { define('RUNNER', true); $test = &new FileTestSuite(); $test->run(new HtmlReporter()); } ?> ]]> This approach requires the guard to be set when including the group test file, but this is still less hassle than lots of separate runner files. You include the same guard on the top level tests to make sure that run() will run once only from the top level script that has been invoked. define('RUNNER', true); require_once('file_test_suite.php'); $test = &new BigTestSuite('Big group'); $test->addTestCase(new FileTestSuite()); $test->addTestCase(...); $test->run(new HtmlReporter()); ?> ]]> As with the normal test cases, a TestSuite can be loaded with the TestSuite::addTestFile() method. $test->addTestFile('file_test_suite.php'); $test->addTestFile(...); $test->run(new HtmlReporter()); ?> ]]>

    If you already have unit tests for your code or are extending external classes that have tests, it is unlikely that all of the test cases are in SimpleTest format. Fortunately it is possible to incorporate test cases from other unit testers directly into SimpleTest group tests.

    Say we have the following PhpUnit test case in the file config_test.php... class ConfigFileTest extends TestCase { function ConfigFileTest() { $this->TestCase('Config file test'); } function testContents() { $config = new ConfigFile('test.conf'); $this->assertRegexp('/me/', $config->getValue('username')); } } ]]> The group test can recognise this as long as we include the appropriate adapter class before we add the test file... require_once('simpletest/adapters/phpunit_test_case.php'); $test = &new TestSuite('All file tests'); $test->addTestFile('config_test.php'); $test->run(new HtmlReporter()); ?> ]]> There are only two adapters, the other is for the PEAR 1.0 unit tester... require_once('simpletest/adapters/pear_test_case.php'); $test = &new TestSuite('All file tests'); $test->addTestFile('some_pear_test_cases.php'); $test->run(new HtmlReporter()); ?> ]]> The PEAR test cases can be freely mixed with SimpleTest ones even in the same test file, but you cannot use SimpleTest assertions in the legacy test case versions. This is done as a check that you are not accidently making your test cases completely dependent on SimpleTest. You may want to do a PEAR release of your library for example, which would mean shipping it with valid PEAR::PhpUnit test cases.

    Different ways to group tests together. Combining group tests into larger groups. Integrating legacy test cases from other types of PHPUnit. SimpleTest project page on SourceForge. SimpleTest download page on LastCraft. php unit testing, test integration, documentation, marcus baker, simple test, simpletest documentation, phpunit, pear
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/authentication_documentation.xml0000664000175000017620000003031411157271050031136 0ustar davidpalepurple SimpleTest documentation for testing log-in and authentication

    One of the trickiest, and yet most important, areas of testing web sites is the security. Testing these schemes is one of the core goals of the SimpleTest web tester.

    If you fetch a page protected by basic authentication then rather than receiving content, you will instead get a 401 header. We can illustrate this with this test... function test401Header() { $this->get('http://www.lastcraft.com/protected/'); $this->showHeaders(); } } ]]> This allows us to see the challenge header...

    File test

    1/1 test cases complete. 0 passes, 0 fails and 0 exceptions.
    We are trying to get away from visual inspection though, and so SimpleTest allows to make automated assertions against the challenge. Here is a thorough test of our header... get('http://www.lastcraft.com/protected/'); $this->assertAuthentication('Basic'); $this->assertResponse(401); $this->assertRealm('SimpleTest basic authentication'); } } ]]> Any one of these tests would normally do on it's own depending on the amount of detail you want to see.

    One theme that runs through SimpleTest is the ability to use SimpleExpectation objects wherever a simple match is not enough. If you want only an approximate match to the realm for example, you can do this... get('http://www.lastcraft.com/protected/'); $this->assertRealm(new PatternExpectation('/simpletest/i')); } } ]]> Most of the time we are not interested in testing the authentication itself, but want to get past it to test the pages underneath. As soon as the challenge has been issued we can reply with an authentication response... get('http://www.lastcraft.com/protected/'); $this->authenticate('Me', 'Secret'); $this->assertTitle(...); } } ]]> The username and password will now be sent with every subsequent request to that directory and subdirectories. You will have to authenticate again if you step outside the authenticated directory, but SimpleTest is smart enough to merge subdirectories into a common realm.

    You can shortcut this step further by encoding the log in details straight into the URL... get('http://Me:Secret@www.lastcraft.com/protected/'); $this->assertTitle(...); } } ]]> If your username or password has special characters, then you will have to URL encode them or the request will not be parsed correctly. Also this header will not be sent on subsequent requests if you request a page with a fully qualified URL. If you navigate with relative URLs though, the authentication information will be preserved.

    Only basic authentication is currently supported and this is only really secure in tandem with HTTPS connections. This is usually enough to protect test server from prying eyes, however. Digest authentication and NTLM authentication may be added in the future.

    Basic authentication doesn't give enough control over the user interface for web developers. More likely this functionality will be coded directly into the web architecture using cookies and complicated timeouts.

    Starting with a simple log-in form...

    
        Username:
        
    Password:
    ]]>
    Which looks like...

    Username:
    Password:

    Let's suppose that in fetching this page a cookie has been set with a session ID. We are not going to fill the form in yet, just test that we are tracking the user. Here is the test... get('http://www.my-site.com/login.php'); $this->assertCookie('SID'); } } ]]> All we are doing is confirming that the cookie is set. As the value is likely to be rather cryptic it's not really worth testing this with... get('http://www.my-site.com/login.php'); $this->assertCookie('SID', new PatternExpectation('/[a-f0-9]{32}/i')); } } ]]> The rest of the test would be the same as any other form, but we might want to confirm that we still have the same cookie after log-in as before we entered. We wouldn't want to lose track of this after all. Here is a possible test for this... get('http://www.my-site.com/login.php'); $session = $this->getCookie('SID'); $this->setField('u', 'Me'); $this->setField('p', 'Secret'); $this->click('Log in'); $this->assertText('Welcome Me'); $this->assertCookie('SID', $session); } } ]]> This confirms that the session identifier is maintained afer log-in.

    We could even attempt to spoof our own system by setting arbitrary cookies to gain access... get('http://www.my-site.com/login.php'); $this->setCookie('SID', 'Some other session'); $this->get('http://www.my-site.com/restricted.php'); $this->assertText('Access denied'); } } ]]> Is your site protected from this attack?

    If you are testing an authentication system a critical piece of behaviour is what happens when a user logs back in. We would like to simulate closing and reopening a browser... get('http://www.my-site.com/login.php'); $this->setField('u', 'Me'); $this->setField('p', 'Secret'); $this->click('Log in'); $this->assertText('Welcome Me'); $this->restart(); $this->get('http://www.my-site.com/restricted.php'); $this->assertText('Access denied'); } } ]]> The WebTestCase::restart() method will preserve cookies that have unexpired timeouts, but throw away those that are temporary or expired. You can optionally specify the time and date that the restart happened.

    Expiring cookies can be a problem. After all, if you have a cookie that expires after an hour, you don't want to stall the test for an hour while the cookie passes it's timeout.

    To push the cookies over the hour limit you can age them before you restart the session... get('http://www.my-site.com/login.php'); $this->setField('u', 'Me'); $this->setField('p', 'Secret'); $this->click('Log in'); $this->assertText('Welcome Me'); $this->ageCookies(3600); $this->restart(); $this->get('http://www.my-site.com/restricted.php'); $this->assertText('Access denied'); } } ]]> After the restart it will appear that cookies are an hour older and any that pass their expiry will have disappeared.

    Getting through Basic HTTP authentication Testing cookie based authentication Managing browser sessions and timeouts SimpleTest project page on SourceForge. SimpleTest download page on LastCraft. The developer's API for SimpleTest gives full detail on the classes and assertions available. software development, php programming for clients, customer focused php, software development tools, acceptance testing framework, free php scripts, log in boxes, unit testing authentication systems, php resources, HTMLUnit, JWebUnit, php testing, unit test resource, web testing, HTTP authentication, testing log in, authentication testing, security tests
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/first_test_tutorial.xml0000664000175000017620000004755711157271050027320 0ustar davidpalepurple PHP unit testing tutorial - Creating an example test case in PHP

    If you are new to unit testing it is recommended that you actually try the code out as we go. There is actually not very much to type and you will get a feel for the rhythm of test first programming.

    To run the examples as is, you need an empty directory with the folders classes, tests and temp. Unpack the SimpleTest framework into the tests folder and make sure your web server can reach these locations.

    A new test case

    The quick introductory example featured the unit testing of a simple log class. In this tutorial on Simple Test I am going to try to tell the whole story of developing this class. This PHP class is small and simple and in the course of this introduction will receive far more attention than it probably would in production. Yet even this tiny class contains some surprisingly difficult design decisions.

    Maybe they are too difficult? Rather than trying to design the whole thing up front I'll start with a known requirement, namely we want to write messages to a file. These messages must be appended to the file if it exists. Later we will want priorities and filters and things, but for now we will place the file writing requirement in the forefront of our thoughts. We will think of nothing else for fear of getting confused. OK, let's make a test... UnitTestCase(); } function testCreatingNewFile() { } } $test = &new TestOfLogging(); $test->run(new HtmlReporter()); ?> ]]> Piece by piece here is what it all means.

    The SIMPLE_TEST constant is the path from this file to the Simple Test classes. The classes could be placed into the path in the php.ini file, but if you are using a shared hosting account you do not have access to this. To keep everybody happy this path is declared explicitely in the test script. Later we will see how it eventually ends up in only one place.

    Requiring the unit_tester.php library is pretty clear, but what is this reporter.php file? The Simple Test libraries are a toolkit for creating your own standardised test suite. They can be used "as is" without trouble, but consist of separate components that have to be assembled. reporter.php has a display component. It is probable that you will eventually write your own and so including the default set is optional. Simple test includes a usable, but basic, test display class called HtmlReporter. It can record test starts, ends, errors, passes and fails. It displays this information as quickly as possible in case the test code crashes the script and obscures the point of failure.

    The tests themselves are gathered in test case classes. This one is typical in extending UnitTestCase. When the test is run it will search for any method within that starts with the name "test" and run it. Our only test method at present is called testCreatingNewFile(). There is nothing in it yet.

    Now the empty method definition on its own does not do anything. We need to actually place some code inside it. The UnitTestCase class will typically generate test events when run and these events are sent to an observer. The UnitTestCase::run() method runs all of the tests in the class.

    Now to add test code... require_once('../classes/log.php'); class TestOfLogging extends UnitTestCase { function TestOfLogging() { $this->UnitTestCase(); } function testCreatingNewFile() { @unlink('../temp/test.log'); $log = new Log('../temp/test.log'); $log->message('Should write this to a file'); $this->assertTrue(file_exists('../temp/test.log')); } } $test = &new TestOfLogging(); $test->run(new HtmlReporter()); ?> ]]>

    You are probably thinking that that is a lot of test code for just one test and I would agree. Don't worry. This is a fixed cost and from now on we can add tests pretty much as one liners. Even less when using some of the test artifacts that we will use later.

    Now comes the first of our decisions. Our test file is called log_test.php (any name is fine) and is in a folder called tests (anywhere is fine). We have called our code file log.php and this is the code we are going to test. I have placed it into a folder called classes, so that means we are building a class, yes?

    For this example I am, but the unit tester is not restricted to testing classes. It is just that object oriented code is easier to break down and redesign for testing. It is no accident that the fine grain testing style of unit tests has arisen from the object community.

    The test itself is minimal. It first deletes any previous test file that may have been left lying around. Design decisions now come in thick and fast. Our class is called Log and takes the file path in the constructor. We create a log and immediately send a message to it using a method named message(). Sadly, original naming is not a desirable characteristic of a software developer.

    The smallest unit of a...er...unit test is the assertion. Here we want to assert that the log file we just sent a message to was indeed created. UnitTestCase::assertTrue() will send a pass event if the condition evaluates to true and a fail event otherwise. We can have a variety of different assertions and even more if we extend our base test cases. Here is the base list...
    assertTrue(\$x)Fail if \$x is false
    assertFalse(\$x)Fail if \$x is true
    assertNull(\$x)Fail if \$x is set
    assertNotNull(\$x)Fail if \$x not set
    assertIsA(\$x, \$t)Fail if \$x is not the class or type \$t
    assertEqual(\$x, \$y)Fail if \$x == \$y is false
    assertNotEqual(\$x, \$y)Fail if \$x == \$y is true
    assertIdentical(\$x, \$y)Fail if \$x === \$y is false
    assertNotIdentical(\$x, \$y)Fail if \$x === \$y is true
    assertReference(\$x, \$y)Fail unless \$x and \$y are the same variable
    assertCopy(\$x, \$y)Fail if \$x and \$y are the same variable
    assertWantedPattern(\$p, \$x)Fail unless the regex \$p matches \$x
    assertNoUnwantedPattern(\$p, \$x)Fail if the regex \$p matches \$x
    assertNoErrors()Fail if any PHP error occoured
    assertError(\$x)Fail if no PHP error or incorrect message

    We are now ready to execute our test script by pointing the browser at it. What happens? It should crash...

    Fatal error: Failed opening required '../classes/log.php' (include_path='') in /home/marcus/projects/lastcraft/tutorial_tests/Log/tests/log_test.php on line 7
    The reason is that we have not yet created log.php.

    Hang on, that's silly! You aren't going to build a test without creating any of the code you are testing, surely...?

    Test Driven Development

    Co-inventor of Extreme Programming, Kent Beck, has come up with another manifesto. The book is called Test driven development or TDD and raises unit testing to a senior position in design. In a nutshell you write a small test first and then only get this passing by writing code. Any code. Just get it working.

    You write another test and get that passing. What you will now have is some duplication and generally lousy code. You re-arrange (refactor) that code while the tests are passing and thus while you cannot break anything. Once the code is as clean as possible you are ready to add more functionality. In turn you only achieve this by adding another test and starting the cycle again.

    This is a radical approach and one that I feel is incomplete. However it makes for a great way to explain a unit tester! We happen to have a failing, not to say crashing, test right now so let's write some code into log.php... ]]> This is the minimum to avoid a PHP fatal error. We now get the respones...

    testoflogging

    Fail: testcreatingnewfile->True assertion failed.
    1/1 test cases complete. 0 passes and 1 fails.
    And "testoflogging" has failed. PHP has this really annoying effect of reducing class and method names to lower case internally. SimpleTest uses these names by default to describe the tests, but we can replace them with our own... $this->UnitTestCase('Log class test'); } function testCreatingNewFile() { @unlink('../temp/test.log'); $log = new Log('../temp/test.log'); $log->message('Should write this to a file'); $this->assertTrue(file_exists('../temp/test.log'), 'File created'); } } ]]> Giving...

    Log class test

    Fail: testcreatingnewfile->File created.
    1/1 test cases complete. 0 passes and 1 fails.
    There is not much we can do about the method name I am afraid.

    Test messages like this are a bit like code comments. Some organisations insist on them while others ban them as clutter and a waste of good typing. I am somewhere in the middle.

    To get the test passing we could just create the file in the Log constructor. This "faking it" technique is very useful for checking that your tests work when the going gets tough. This is especially so if you have had a run of test failures and just want to confirm that you haven't just missed something stupid. We are not going that slow, so... var $_file_path; function Log($file_path) { $this->_file_path = $file_path; } function message($message) { $file = fopen($this->_file_path, 'a'); fwrite($file, $message . "\n"); fclose($file); } } ?> ]]> It took me no less than four failures to get to the next step. I had not created the temporary directory, I had not made it publicly writeable, I had one typo and I did not check in the new directory to CVS. Any one of these could have kept me busy for several hours if they had come to light later, but then that is what testing is for. With the necessary fixes we get...

    Log class test

    1/1 test cases complete. 1 passes and 0 fails.
    Success!

    You may not like the rather minimal style of the display. Passes are not shown by default because generally you do not need more information when you actually understand what is going on. If you do not know what is going on then you should write another test.

    OK, this is a little strict. If you want to see the passes as well then you can subclass the HtmlReporter class and attach that to the test instead. Even I like the comfort factor sometimes.

    Tests as Documentation

    There is a subtlety here. We don't want the file created until we actually send a message. Rather than think about this too deeply we will just add another test for it... UnitTestCase('Log class test'); } function testCreatingNewFile() { @unlink('../temp/test.log'); $log = new Log('../temp/test.log'); $this->assertFalse(file_exists('../temp/test.log'), 'No file created before first message'); $log->message('Should write this to a file'); $this->assertTrue(file_exists('../temp/test.log'), 'File created'); } } ]]> ...and find it already works...

    Log class test

    1/1 test cases complete. 2 passes and 0 fails.
    Actually I knew it would. I am putting this test in to confirm this partly for peace of mind, but also to document the behaviour. That little extra test line says more in this context than a dozen lines of use case or a whole UML activity diagram. That the test suite acts as a source of documentation is a pleasant side effect of all these tests.

    Should we clean up the temporary file at the end of the test? I usually do this once I am finished with a test method and it is working. I don't want to check in code that leaves remnants of test files lying around after a test. I don't do it while I am writing the code, though. I probably should, but sometimes I need to see what is going on and there is that comfort thing again.

    In a real life project we usually have more than one test case, so we next have to look at grouping tests into test suites.

    Creating a new test case. Test driven development in PHP. Tests as documentation is one of many side effects. The JUnit FAQ has plenty of useful testing advice. Next is grouping test cases together. You will need the SimpleTest testing framework for these examples. software development, php programming, programming php, software development tools, php tutorial, free php scripts, architecture, php resources, mock objects, junit, php testing, unit test, automated php testing, test cases tutorial, explain unit test case, unit test example, unit test
    postfixadmin-2.3.7/tests/simpletest/docs/source/en/expectation_documentation.xml0000664000175000017620000003447311157271050030454 0ustar davidpalepurple Extending the SimpleTest unit tester with additional expectation classes

    The default behaviour of the mock objects in SimpleTest is either an identical match on the argument or to allow any argument at all. For almost all tests this is sufficient. Sometimes, though, you want to weaken a test case.

    One place where a test can be too tightly coupled is with text matching. Suppose we have a component that outputs a helpful error message when something goes wrong. You want to test that the correct error was sent, but the actual text may be rather long. If you test for the text exactly, then every time the exact wording of the message changes, you will have to go back and edit the test suite.

    For example, suppose we have a news service that has failed to connect to its remote source. class NewsService { ... function publish(&$writer) { if (! $this->isConnected()) { $writer->write('Cannot connect to news service "' . $this->_name . '" at this time. ' . 'Please try again later.'); } ... } } ]]> Here it is sending its content to a Writer class. We could test this behaviour with a MockWriter like so... $writer = &new MockWriter(); $writer->expectOnce('write', array( 'Cannot connect to news service ' . '"BBC News" at this time. ' . 'Please try again later.')); $service = &new NewsService('BBC News'); $service->publish($writer); } } ]]> This is a good example of a brittle test. If we decide to add additional instructions, such as suggesting an alternative news source, we will break our tests even though no underlying functionality has been altered.

    To get around this, we would like to do a regular expression test rather than an exact match. We can actually do this with... $writer->expectOnce( 'write', array(new PatternExpectation('/cannot connect/i'))); $service = &new NewsService('BBC News'); $service->publish($writer); } } ]]> Instead of passing in the expected parameter to the MockWriter we pass an expectation class called WantedPatternExpectation. The mock object is smart enough to recognise this as special and to treat it differently. Rather than simply comparing the incoming argument to this object, it uses the expectation object itself to perform the test.

    The WantedPatternExpectation takes the regular expression to match in its constructor. Whenever a comparison is made by the MockWriter against this expectation class, it will do a preg_match() with this pattern. With our test case above, as long as "cannot connect" appears in the text of the string, the mock will issue a pass to the unit tester. The rest of the text does not matter.

    The possible expectation classes are...
    AnythingExpectationWill always match
    EqualExpectationAn equality, rather than the stronger identity comparison
    NotEqualExpectationAn inequality comparison
    IndenticalExpectationThe default mock object check which must match exactly
    NotIndenticalExpectationInverts the mock object logic
    WithinMarginExpectationCompares a value to within a margin
    OutsideMarginExpectationChecks that a value is out side the margin
    PatternExpectationUses a Perl Regex to match a string
    NoPatternExpectationPasses only if failing a Perl Regex
    IsAExpectationChecks the type or class name only
    NotAExpectationOpposite of the IsAExpectation
    MethodExistsExpectationChecks a method is available on an object
    Most take the expected value in the constructor. The exceptions are the pattern matchers, which take a regular expression, and the IsAExpectation and NotAExpectation which takes a type or class name as a string.

    Some examples...

    expectOnce('method', array(new IdenticalExpectation(14))); ]]> This is the same as $mock->expectOnce('method', array(14)). expectOnce('method', array(new EqualExpectation(14))); ]]> This is different from the previous version in that the string "14" as a parameter will also pass. Sometimes the additional type checks of SimpleTest are too restrictive. expectOnce('method', array(new AnythingExpectation(14))); ]]> This is the same as $mock->expectOnce('method', array('*')). expectOnce('method', array(new IdenticalExpectation('*'))); ]]> This is handy if you want to assert a literal "*". This matches on anything other than integer 14. Even the string "14" would pass. This will accept any value from 13.999 to 14.001 inclusive.

    The expectation classes can be used not just for sending assertions from mock objects, but also for selecting behaviour for the mock objects. Anywhere a list of arguments is given, a list of expectation objects can be inserted instead.

    Suppose we want a mock authorisation server to simulate a successful login, but only if it receives a valid session object. We can do this as follows... $authorisation = new MockAuthorisation(); $authorisation->setReturnValue( 'isAllowed', true, array(new IsAExpectation('Session', 'Must be a session'))); $authorisation->setReturnValue('isAllowed', false); ]]> We have set the default mock behaviour to return false when isAllowed is called. When we call the method with a single parameter that is a Session object, it will return true. We have also added a second parameter as a message. This will be displayed as part of the mock object failure message if this expectation is the cause of a failure.

    This kind of sophistication is rarely useful, but is included for completeness.

    The expectation classes have a very simple structure. So simple that it is easy to create your own versions for commonly used test logic.

    As an example here is the creation of a class to test for valid IP addresses. In order to work correctly with the stubs and mocks the new expectation class should extend SimpleExpectation... class ValidIp extends SimpleExpectation { function test($ip) { return (ip2long($ip) != -1); } function testMessage($ip) { return "Address [$ip] should be a valid IP address"; } } ]]> There are only two methods to implement. The test() method should evaluate to true if the expectation is to pass, and false otherwise. The testMessage() method should simply return some helpful text explaining the test that was carried out.

    This class can now be used in place of the earlier expectation classes.

    The SimpleTest unit testing framework also uses the expectation classes internally for the UnitTestCase class. We can also take advantage of these mechanisms to reuse our homebrew expectation classes within the test suites directly.

    The most crude way of doing this is to use the SimpleTest::assert() method to test against it directly... class TestOfNetworking extends UnitTestCase { ... function testGetValidIp() { $server = &new Server(); $this->assert( new ValidIp(), $server->getIp(), 'Server IP address->%s'); } } ]]> This is a little untidy compared with our usual assert...() syntax.

    For such a simple case we would normally create a separate assertion method on our test case rather than bother using the expectation class. If we pretend that our expectation is a little more complicated for a moment, so that we want to reuse it, we get... function assertValidIp($ip, $message = '%s') { $this->assert(new ValidIp(), $ip, $message); } function testGetValidIp() { $server = &new Server(); $this->assertValidIp( $server->getIp(), 'Server IP address->%s'); } } ]]> It is unlikely we would ever need this degree of control over the testing machinery. It is rare to need the expectations for more than pattern matching. Also, complex expectation classes could make the tests harder to read and debug. These mechanisms are really of most use to authors of systems that will extend the test framework to create their own tool set.

    Using expectations for more precise testing with mock objects Changing mock object behaviour with expectations Extending the expectations Underneath SimpleTest uses expectation classes SimpleTest project page on SourceForge. SimpleTest download page on LastCraft. The expectations mimic the constraints in JMock. Full API for SimpleTest from the PHPDoc. mock objects, test driven development, inheritance of expectations, mock object constraints, advanced PHP unit testing, test first, test framework architecture expectations in simpletest test cases server stubs
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/0000775000175000017620000000000012301477470022456 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/docs/source/fr/download_website.xml0000664000175000017620000000632711157271050026533 0ustar davidpalepurple Télécharger SimpleTest

    La version courante est : SimpleTest v1.0.1beta.

    Vous pouvez télécharger cette version depuis SourceForget.net et votre miroir le plus proche. Vous pouvez aussi jeter un oeil du côté du changelog actuel.

    Au fait, ne soyez pas effrayé par le mot beta : pas mal d'utilisateurs vont même jusqu'à utiliser la version CVS.

    Si Eclipse est votre IDE / éditeur de prédilection, vous aurez peut-être envie d'utiliser le plugin Eclipse.

    Pour utilser les procédures automatiques, l'URL est :

    http://simpletest.org/eclipse/

    SimpleTest a été packagé par la communauté avec d'autres parfums encore.

    Attention : certains paquets ne sont pas toujours très à jour.

    Le code source est hébergé par SourceForge : vous pouvez l'étudier / le butiner via le CVS repository.

    Version courante Paquet Eclipse Autres paquets Source Autres versions stables SimpleTest, download, source code, stable release, eclipse release, eclipse plugin, debian package, drupal module, pear channel, pearified package
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/index.xml0000664000175000017620000000656311157271050024313 0ustar davidpalepurple Les articles de :: onpk :: sur php / simpletest : traductions en franais des articles publis sur Lastcraft.com

    Cette section rassemble l'ensemble des articles et documentations pour SimpleTest traduits en franais.

    J'ai commenc par dcouvrir l'Extreme Programming via le web. Ensuite j'ai gagn un livre en franais sur XP. Et dcouvrant la confiance supplmentaire gagne via les tests unitaires et de recette, je suis devenu "test-infected".

    Aprs avoir got aux joies de SimpleTest, j'ai contact Marcus Baker -- responsable du projet -- pour lui proposer de traduire en franais la page d'introduction, puis les tutoriaux et finalement toute la documentation. Un travail qui n'aurait pas t possible sans l'aide de quelques relecteurs bienveillants : Jrmie C., David B., Emmanuel G., Olivier L. et Cdric G. (dans le dsordre).

    Si vous lisez attentivement ces quelques pages et que vous y trouvez encore des fautes d'orthographe, pensez me les renvoyer : comme a le prochain ne pourra pas se dire la mme chose.

    J'ai un blog -- :: onpk ::, une entreprise -- No Parking dont le produit phare est openTIME. Dans la communaut je me ballade du ct de l'AFUP, des apros PHP et des praticiens XP.

    Comment en arrive-t-on au dveloppement pilot par les tests ? Et en dehors des tests ? Tous les articles SimpleTest -- l'original en anglais. dveloppement logiciel, programmation php, outils de dveloppement logiciel, tutorial php, scripts php gratuits, conseil de test, architecture logicielle pour des tests, exemple de code php, junit, test php, outil de test unitaire, suite de test php Des articles (documentations et tutoriels) pour dcouvrir le dveloppement agile en PHP avec le framework de tests unitaires SimpleTest.
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/books_website.xml0000664000175000017620000000750311157271050026036 0ustar davidpalepurple Livres avec / à propos / pas loin de SimpleTest

    De temps en temsp, un livre est recommandé sur la mailing-list, vous le trouverez ci-dessous avec les commentaires originaux !

    Domain-Driven Design: Tackling Complexity in the Heart of Software

    Le Développement Piloté par les Tests est principalement intéressé par les mécanismes pour coder, mais il dit que c'est fini quand il n'y plus de duplication. Le Développement Piloté par la Conception (DDD) considère que le code est constamment in churn, changeant de terminologie au fur et à mesure que le domaine devient plus clair, et aussi nourrisant le domaine avec des nouveaux termes quand le code évolue..

    Et puis, c'est un super bouquin :) [source]

    Deux contributeurs de Simpletest ont écrit des livres sur PHP. Tous les deux ont de nombreux exemples avec le framework SimpleTest.

    PHP|Architect's Guide to PHP Design Patterns
    PHP|Architect's Guide to PHP Design Patterns
    par Jason E. Sweat
    (l'obtenir depuis : PHP|Architect | Amazon )

    The PHP Anthology: Object Oriented PHP Solutions
    The PHP Anthology: Object Oriented PHP Solutions
    par Harry Fuecks
    (l'obtenir depuis : SitePoint | Amazon | critique sur Slashdot )

    Une manière d'aider l'équipe de contributeurs, c'est d'acheter des livres via cete page avec Amazon (avec le mot-clé simpletest-21). Nous adorons tous lire des trucs à la fois intéressants et stimulants.

    Latest recommandation Books by contributors Buying books
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/mock_objects_tutorial.xml0000664000175000017620000003354211157271050027566 0ustar davidpalepurple tutorial sur les tests unitaires en PHP - Utiliser les objets fantaisie en PHP

    Remanier les tests nouveau

    Avant d'ajouter de nouvelles fonctionnalits il y a du remaniement faire. Nous allons effectuer des tests chronomtrs et la classe TimeTestCase a dfinitivement besoin d'un fichier propre. Appelons le tests/time_test_case.php... UnitTestCase($test_name); } function assertSameTime($time1, $time2, $message = '') { if (! $message) { $message = "Time [$time1] should match time [$time2]"; } $this->assertTrue( ($time1 == $time2) || ($time1 + 1 == $time2), $message); } } ?> ]]> Nous pouvons lors utiliser require() pour incorporer ce fichier dans le script all_tests.php.

    Ajouter un timestamp au Log

    Je ne sais pas trop quel devrait tre le format du message de log pour le test alors pour vrifier le timestamp nous pourrions juste faire la plus simple des choses possibles, c'est dire rechercher une suite de chiffres. require_once('../classes/clock.php'); class TestOfLogging extends TimeTestCase { function TestOfLogging() { $this->TimeTestCase('Log class test'); } function setUp() { @unlink('../temp/test.log'); } function tearDown() { @unlink('../temp/test.log'); } function getFileLine($filename, $index) { $messages = file($filename); return $messages[$index]; } function testCreatingNewFile() { ... } function testAppendingToFile() { ... } function testTimestamps() { $log = new Log('../temp/test.log'); $log->message('Test line'); $this->assertTrue( preg_match('/(\d+)/', $this->getFileLine('../temp/test.log', 0), $matches), 'Found timestamp'); $clock = new clock(); $this->assertSameTime((integer)$matches[1], $clock->now(), 'Correct time'); } } ?> ]]> Ce scnario de test cre un nouvel objet Log et crit un message. Nous recherchons une suite de chiffres et nous la comparons l'horloge prsente en utilisant notre objet Clock. Bien sr a ne marche pas avant d'avoir crit le code.

    All tests

    Pass: log_test.php->Log class test->testappendingtofile->Expecting [/Test line 1/] in [Test line 1]
    Pass: log_test.php->Log class test->testappendingtofile->Expecting [/Test line 2/] in [Test line 2]
    Pass: log_test.php->Log class test->testcreatingnewfile->Created before message
    Pass: log_test.php->Log class test->testcreatingnewfile->File created
    Fail: log_test.php->Log class test->testtimestamps->Found timestamp

    Notice: Undefined offset: 1 in /home/marcus/projects/lastcraft/tutorial_tests/tests/log_test.php on line 44
    Fail: log_test.php->Log class test->testtimestamps->Correct time
    Pass: clock_test.php->Clock class test->testclockadvance->Advancement
    Pass: clock_test.php->Clock class test->testclocktellstime->Now is the right time
    3/3 test cases complete. 6 passes and 2 fails.
    Cette suite de tests montre encore les succs de notre modification prcdente.

    Nous pouvons faire passer les tests en ajoutant simplement un timestamp l'criture dans le fichier. Oui, bien sr, tout ceci est assez trivial et d'habitude je ne le testerais pas aussi fanatiquement, mais a va illustrer un problme plus gnral... Le fichier log.php devient... require_once('../classes/clock.php'); class Log { var $_file_path; function Log($file_path) { $this->_file_path = $file_path; } function message($message) { $clock = new Clock(); $file = fopen($this->_file_path, 'a'); fwrite($file, "[" . $clock->now() . "] $message\n"); fclose($file); } } ?> ]]> Les tests devraient passer.

    Par contre notre nouveau test est plein de problmes. Qu'est-ce qui se passe si notre format de temps change ? Les choses vont devenir largement plus compliques si a venait se produire. Cela veut aussi dire que n'importe quel changement du format de notre classe horloge causera aussi un chec dans les tests de log. Bilan : nos tests de log sont tout mlangs avec les test d'horloge et par la mme trs fragiles. Tester la fois des facettes de l'horloge et d'autres du log manque de cohsion, ou de focalisation tanche si vous prfrez. Nos problmes sont causs en partie parce que le rsultat de l'horloge est imprvisible alors que l'unique chose tester est la prsence du rsultat de Clock::now(). Peu importe le contenu de l'appel de cette mthode.

    Pouvons-nous rendre cet appel prvisible ? Oui si nous pouvons forcer le loggueur utiliser une version factice de l'horloge lors du test. Cette classe d'horloge factice devrait se comporter exactement comme la classe Clock part une sortie fixe dans la mthode now(). Et au passage, a nous affranchirait mme de la classe TimeTestCase !

    Nous pourrions crire une telle classe assez facilement mme s'il s'agit d'un boulot plutt fastidieux. Nous devons juste crer une autre classe d'horloge avec la mme interface sauf que la mthode now() retourne une valeur modifiable via une autre mthode d'initialisation. C'est plutt pas mal de travail pour un test plutt mineur.

    Sauf que a se fait sans aucun effort.

    Une horloge fantaisie

    Pour atteindre le nirvana de l'horloge instantan pour test nous n'avons besoin que de trois lignes de code supplmentaires... Cette instruction inclut le code de gnrateur d'objet fantaisie. Le plus simple reste de le mettre dans le script all_tests.php tant donn qu'il est utilis assez frquemment. C'est la ligne qui fait le travail. Le gnrateur de code scanne la classe, en extrait toutes ses mthodes, cre le code pour gnrer une classe avec une interface identique, mais en ajoutant le nom "Mock" et ensuite eval() le nouveau code pour crer la nouvelle classe. Cette ligne peut tre ajoute dans n'importe quelle mthode de test qui nous intresserait. Elle cre l'horloge fantaisie prte recevoir nos instructions.

    Notre scnario de test en est ses premiers pas vers un nettoyage radical... Mock::generate('Clock'); class TestOfLogging extends UnitTestCase { function TestOfLogging() { $this->UnitTestCase('Log class test'); } function setUp() { @unlink('../temp/test.log'); } function tearDown() { @unlink('../temp/test.log'); } function getFileLine($filename, $index) { $messages = file($filename); return $messages[$index]; } function testCreatingNewFile() { ... } function testAppendingToFile() { ... } function testTimestamps() { $clock = &new MockClock($this); $clock->setReturnValue('now', 'Timestamp'); $log = new Log('../temp/test.log'); $log->message('Test line', &$clock); $this->assertWantedPattern( '/Timestamp/', $this->getFileLine('../temp/test.log', 0), 'Found timestamp'); } } ?> ]]> Cette mthode de test cre un objet MockClock puis dfinit la valeur retourn par la mthode now() par la chane "Timestamp". A chaque fois que nous appelons $clock->now(), elle retournera cette mme chane. a devrait tre quelque chose de facilement reprable.

    Ensuite nous crons notre loggueur et envoyons un message. Nous incluons dans l'appel message() l'horloge que nous souhaitons utiliser. a veut dire que nous aurons ajouter un paramtre optionnel la classe de log pour rendre ce test possible... _file_path = $file_path; } function message($message, $clock = false) { if (!is_object($clock)) { $clock = new Clock(); } $file = fopen($this->_file_path, 'a'); fwrite($file, "[" . $clock->now() . "] $message\n"); fclose($file); } } ]]> Maintenant tous les tests passent et ils ne testent que le code du loggueur. Nous pouvons nouveau respirer.

    Est-ce que ce paramtre supplmentaire dans la classe Log vous gne ? Nous n'avons chang l'interface que pour faciliter les tests aprs tout. Les interfaces ne sont-elles pas la chose la plus importante ? Avons nous souill notre classe avec du code de test ?

    Peut-tre, mais rflchissez ce qui suit. A la prochaine occasion, regardez une carte avec des circuits imprims, peut-tre la carte mre de l'ordinateur que vous regardez actuellement. Sur la plupart d'entre elles vous trouverez un trou bizarre et vide ou alors un point de soudure sans rien de fix ou mme une pingle ou une prise sans aucune fonction vidente. Peut-tre certains sont l en prvision d'une expansion ou d'une variation future, mais la plupart n'y sont que pour les tests.

    Pensez-y. Les usines qui fabriquent ces cartes imprimes par centaine de milliers gaspillent des matires premires sur des pices qui n'ajoutent rien la fonction finale. Si les ingnieurs matriel peuvent faire quelques sacrifices l'lgance, je suis sr que nous pouvons aussi le faire. Notre sacrifice ne gaspille pas de matriel aprs tout.

    a vous gne encore ? En fait moi aussi, mais pas tellement ici. La priorit numro 1 reste du code qui marche, pas un prix pour minimalisme. Si a vous gne vraiment alors dplacez la cration de l'horloge dans une autre mthode mre protge. Ensuite sous classez l'horloge pour le test et crasez la mthode mre avec une qui renvoie le leurre. Vos tests sont bancals mais votre interface est intacte.

    Une nouvelle fois je vous laisse la dcision finale.

    Remanier les tests dans le but de rutiliser notre nouveau test de temps. Ajouter des timestamps de Log. Crer une horloge fantaisie pour rendre les tests cohsifs. La section prcdente : tutorial de test unitaire. La section suivante : les frontires de l'application. Vous aurez besoin du framework de test SimpleTest pour essayer ces exemples. Documents sur les objets fantaisie. dveloppement logiciel, programmation php, outils de dveloppement logiciel, tutoriel php, scripts php gratuits, architecture, ressources php, objet fantaisie, junit, phpunit, simpletest, test php, outil de test unitaire, suite de test php
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/form_testing_documentation.xml0000664000175000017620000002445511157271050030635 0ustar davidpalepurple Documentation SimpleTest : tester des formulaires HTML

    Lorsqu'une page est tlcharge par WebTestCase en utilisant get() ou post() le contenu de la page est automatiquement analys. De cette analyse dcoule le fait que toutes les commandes l'intrieur de la balise <form> sont disponibles depuis l'intrieur du scnario de test. Prenons par exemple cet extrait de code HTML...

    
        
        
    
    ]]>
    Il ressemble ...

    Nous pouvons naviguer vers ce code, via le site LastCraft, avec le test suivant... function testDefaultValue() { $this->get('http://www.lastcraft.com/form_testing_documentation.php'); $this->assertField('a', 'A default'); } } ]]> Directement aprs le chargement de la page toutes les commandes HTML sont inities avec leur valeur par dfaut, comme elles apparatraient dans un navigateur web. L'assertion teste qu'un objet HTML avec le nom "a" existe dans la page et qu'il contient la valeur "A default".

    Nous pourrions retourner le formulaire tout de suite, mais d'abord nous allons changer la valeur du champ texte. Ce n'est qu'aprs que nous le transmettrons... get('http://www.my-site.com/'); $this->assertField('a', 'A default'); $this->setField('a', 'New value'); $this->clickSubmit('Go'); } } ]]> Parce que nous n'avons spcifi ni attribut "method" sur la balise form, ni attribut "action", le scnario de test suivra le comportement classique d'un navigateur : transmission des donnes avec une requte GET vers la mme page. SimpleTest essaie d'muler le comportement typique d'un navigateur autant que possible, plutt que d'essayer d'attraper des attributs manquants sur les balises. La raison est simple : la cible d'un framework de test est la logique d'une application PHP, pas les erreurs -- de syntaxe ou autres -- du code HTML. Pour les erreurs HTML, d'autres outils tel HTMLTidy devraient tre employs.

    Si un champ manque dans n'importe quel formulaire ou si une option est indisponible alors WebTestCase::setField() renverra false. Par exemple, supposons que nous souhaitons vrifier qu'une option "Superuser" n'est pas prsente dans ce formulaire...

    Select type of user to add:
    
    ]]>
    Qui ressemble ...

    Select type of user to add:

    Le test suivant le confirmera... $this->get('http://www.lastcraft.com/form_testing_documentation.php'); $this->assertFalse($this->setField('type', 'Superuser')); } } ]]> La slection ne sera pas change suite un chec d'initialisation d'une valeur sur un objet.

    Voici la liste complte des objets supports aujourd'hui...

    • Champs texte, y compris les champs masqus (hidden) ou crypts (password).
    • Boutons submit, en incluant aussi la balise button, mais pas encore les boutons reset
    • Aires texte (textarea) avec leur gestion des retours la ligne (wrap).
    • Cases cocher, y compris les cases cocher multiples dans un mme formulaire.
    • Listes menu droulant, y compris celles slections multiples.
    • Boutons radio.
    • Images.

    Bien que la plupart des objets HTML standards soient couvert par le parseur de SimpleTest, il est peu probable que JavaScript soit implment dans un futur proche.

    SimpleTest peut grer deux types de commandes valeur multiple : les menus droulants slection multiple et les cases cocher avec le mme nom l'intrieur mme d'un formulaire. La nature de ceux-ci implique que leur initialisation et leur test sont lgrement diffrents. Voici un exemple avec des cases cocher...

    
        Create privileges allowed:
        
    Retrieve privileges allowed:
    Update privileges allowed:
    Destroy privileges allowed:
    ]]>
    Qui se traduit par...

    Create privileges allowed:
    Retrieve privileges allowed:
    Update privileges allowed:
    Destroy privileges allowed:

    Si nous souhaitons dsactiver tous les privilges sauf ceux de tlchargement (Retrieve) et transmettre cette information, nous pouvons y arriver par... function testDisableNastyPrivileges() { $this->get('http://www.lastcraft.com/form_testing_documentation.php'); $this->assertField('crud', array('c', 'r', 'u', 'd')); $this->setField('crud', array('r')); $this->clickSubmit('Enable Privileges'); } } ]]> Plutt que d'initier le champ une valeur unique, nous lui donnons une liste de valeurs. Nous faisons la mme chose pour tester les valeurs attendues. Nous pouvons crire d'autres bouts de code de test pour confirmer cet effet, peut-tre en nous connectant comme utilisateur et en essayant d'effectuer une mise jour.

    Envoi brut

    Si vous souhaitez tester un gestionnaire de formulaire mais que vous ne l'avez pas crit ou que vous n'y avez pas encore accs, vous pouvez crer un envoi de formulaire la main. function testAttemptedHack() { $this->post( 'http://www.my-site.com/add_user.php', array('type' => 'superuser')); $this->assertNoUnwantedPattern('/user created/i'); } } ]]> En ajoutant des donnes la mthode WebTestCase::post(), nous essayons de tlcharger la page via la transmission d'un formulaire.

    Modifier les valeurs d'un formulaire et russir transmettre un simple formulaire Grer des objets valeurs multiples en initialisant des listes. Envoi brut quand il n'existe pas de bouton cliquer. La page du projet SimpleTest sur SourceForge. La page de tlchargement de SimpleTest sur LastCraft. L'API du dveloppeur pour SimpleTest donne tous les dtails sur les classes et les assertions disponibles. dveloppement logiciel, programmation php pour des clients, php centr sur le client, outils de dveloppement logiciel, frameword de test de recette, scripts php gratuits, architecture, ressources php, HTMLUnit, JWebUnit, test php, ressources de test unitaire, test web
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/unit_test_documentation.xml0000664000175000017620000003225711157271050030152 0ustar davidpalepurple Documentation SimpleTest pour les tests de rgression en PHP

    Le coeur du systme est un framework de tests de rgression construit autour des scnarios de test. Un exemple de scnario de test ressemble ... class FileTestCase extends UnitTestCase { } ]]> Si aucun nom de test n'est fourni au moment de la liaison avec le constructeur alors le nom de la classe sera utilis. Il s'agit du nom qui sera affich dans les rsultats du test.

    Les vritables tests sont ajouts en tant que mthode dans le scnario de test dont le nom par dfaut commence par la chane "test" et quand le scnario de test est appel toutes les mthodes de ce type sont excutes dans l'ordre utilis par l'introspection de PHP pour les trouver. Peuvent tre ajoutes autant de mthodes de test que ncessaires. Par exemple... UnitTestCase('File test'); } function setUp() { @unlink('../temp/test.txt'); } function tearDown() { @unlink('../temp/test.txt'); } function testCreation() { $writer = &new FileWriter('../temp/test.txt'); $writer->write('Hello'); $this->assertTrue(file_exists('../temp/test.txt'), 'File created'); } } ]]> Le constructeur est optionnel et souvent omis. Sans nom, le nom de la classe est utilis comme nom pour le scnario de test.

    Notre unique mthode de test pour le moment est testCreation() o nous vrifions qu'un fichier a bien t cr par notre objet Writer. Nous pourrions avoir mis le code unlink() dans cette mthode, mais en la plaant dans setUp() et tearDown() nous pouvons l'utiliser pour nos autres mthodes de test que nous ajouterons.

    La mthode setUp() est lanc juste avant chaque mthode de test. tearDown() est lanc aprs chaque mthode de test.

    Vous pouvez placer une initialisation de scnario de test dans le constructeur afin qu'elle soit lance pour toutes les mthodes dans le scnario de test mais dans un tel cas vous vous exposeriez des interfrences. Cette faon de faire est lgrement moins rapide, mais elle est plus sre. Notez que si vous arrivez avec des notions de JUnit, il ne s'agit pas du comportement auquel vous tes habitus. Bizarrement JUnit re-instancie le scnario de test pour chaque mthode de test pour se prvenir d'une telle interfrence. SimpleTest demande l'utilisateur final d'utiliser setUp(), mais fournit aux codeurs de bibliothque d'autres crochets.

    Pour rapporter les rsultats de test, le passage par une classe d'affichage - notifie par les diffrentes mthodes de type assert...() - est utilise. En voici la liste complte pour la classe UnitTestCase, celle par dfaut dans SimpleTest...
    assertTrue($x)Echoue si $x est faux
    assertFalse($x)Echoue si $x est vrai
    assertNull($x)Echoue si $x est initialis
    assertNotNull($x)Echoue si $x n'est pas initialis
    assertIsA($x, $t)Echoue si $x n'est pas de la classe ou du type $t
    assertEqual($x, $y)Echoue si $x == $y est faux
    assertNotEqual($x, $y)Echoue si $x == $y est vrai
    assertIdentical($x, $y)Echoue si $x === $y est faux
    assertNotIdentical($x, $y)Echoue si $x === $y est vrai
    assertReference($x, $y)Echoue sauf si $x et $y sont la mme variable
    assertCopy($x, $y)Echoue si $x et $y sont la mme variable
    assertWantedPattern($p, $x)Echoue sauf si l'expression rationnelle $p capture $x
    assertNoUnwantedPattern($p, $x)Echoue si l'expression rationnelle $p capture $x
    assertNoErrors()Echoue si une erreur PHP arrive
    assertError($x)Echoue si aucune erreur ou message incorrect de PHP n'arrive
    Toutes les mthodes d'assertion peuvent recevoir une description optionnelle : cette description sert pour tiqueter le rsultat. Sans elle, une message par dfaut est envoye la place : il est gnralement suffisant. Ce message par dfaut peut encore tre encadr dans votre propre message si vous incluez "%s" dans la chane. Toutes les assertions renvoient vrai / true en cas de succs et faux / false en cas d'chec.

    D'autres exemples... $variable = null; $this->assertNull($variable, 'Should be cleared'); ]]> ...passera et normalement n'affichera aucun message. Si vous avez configur le testeur pour afficher aussi les succs alors le message sera affich comme tel. $this->assertIdentical(0, false, 'Zero is not false [%s]'); ]]> Ceci chouera tant donn qu'il effectue une vrification sur le type en plus d'une comparaison sur les deux valeurs. La partie "%s" est remplace par le message d'erreur par dfaut qui aurait t affich si nous n'avions pas fourni le ntre. Cela nous permet d'emboter les messages de test. $a = 1; $b = $a; $this->assertReference($a, $b); ]]> chouera tant donn que la variable $b est une copie de $a. $this->assertWantedPattern('/hello/i', 'Hello world'); ]]> L, a passe puisque la recherche est insensible la casse et que donc hello est bien reprable dans Hello world. trigger_error('Disaster'); trigger_error('Catastrophe'); $this->assertError(); $this->assertError('Catastrophe'); $this->assertNoErrors(); ]]> Ici, il y a besoin d'une petite explication : toutes passent !

    Les erreurs PHP dans SimpleTest sont piges et places dans une queue. Ici la premire vrification d'erreur attrape le message "Disaster" sans vrifier le texte et passe. Rsultat : l'erreur est supprime de la queue. La vrification suivante teste non seulement l'existence de l'erreur mais aussi le texte qui correspond : un autre succs. Dsormais la queue est vide et le dernier test passe aussi. Si une autre erreur non vrifie est encore dans la queue la fin de notre mthode de test alors une exception sera rapporte dans le test. Notez que SimpleTest ne peut pas attraper les erreurs PHP la compilation.

    Les scnarios de test peuvent utiliser des mthodes bien pratiques pour dboguer le code ou pour tendre la suite...
    setUp()Est lance avant chaque mthode de test
    tearDown()Est lance aprs chaque mthode de test
    pass()Envoie un succs
    fail()Envoie un chec
    error()Envoi un vnement exception
    sendMessage()Envoie un message d'tat aux systmes d'affichage qui le supporte
    signal($type, $payload)Envoie un message dfini par l'utilisateur au rapporteur du test
    dump($var)Effectue un print_r() format pour du dboguage rapide et grossier
    swallowErrors()Vide les erreurs de la queue

    Bien sr des mthodes supplmentaires de test peuvent tre ajoutes pour crer d'autres types de scnario de test afin d'tendre le framework... class FileTester extends UnitTestCase { function FileTester($name = false) { $this->UnitTestCase($name); } function assertFileExists($filename, $message = '%s') { $this->assertTrue( file_exists($filename), sprintf($message, 'File [$filename] existence check')); } } ]]> Ici la bibliothque SimpleTest est localise dans un rpertoire local appel simpletest. Pensez le modifier pour votre propre environnement.

    Ce nouveau scnario peut tre hrit exactement comme un scnario de test classique... FileTester { function setUp() { @unlink('../temp/test.txt'); } function tearDown() { @unlink('../temp/test.txt'); } function testCreation() { $writer = &new FileWriter('../temp/test.txt'); $writer->write('Hello'); $this->assertFileExists('../temp/test.txt'); } } ]]>

    Si vous souhaitez un scnario de test sans toutes les assertions de UnitTestCase mais uniquement avec les vtres propres, vous aurez besoin d'tendre la classe SimpleTestCase la place. Elle se trouve dans simple_test.php en lieu et place de unit_tester.php. A consulter plus tard si vous souhaitez incorporer les scnarios d'autres testeurs unitaires dans votre suite de test.

    Ce n'est pas souvent qu'il faille lancer des scnarios avec un unique test. Sauf lorsqu'il s'agit de s'arracher les cheveux sur un module problme sans pour autant dsorganiser la suite de test principale. Voici l'chafaudage ncessaire pour lancer un scnario de test solitaire... require_once('simpletest/reporter.php'); require_once('../classes/writer.php'); class FileTestCase extends UnitTestCase { function FileTestCase() { $this->UnitTestCase('File test'); } } $test = &new FileTestCase(); $test->run(new HtmlReporter()); ?> ]]> Ce script sera lanc tel que mais il n'y aura aucun succs ou chec avant que des mthodes de test soient ajoutes.

    Scnarios de test unitaire et oprations basiques. tendre des scnarios de test pour les personnaliser votre propre projet. Lancer un scnario seul comme un script unique. La page de SimpleTest sur SourceForge. La page de tlchargement de SimpleTest sur LastCraft. L'API complte de SimpleTest partir de PHPDoc. test unitaire php, test d'intgration, documentation, marcus baker, perrick penet simple test, documentation simpletest, phpunit, junit, xunit
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/web_tester_documentation.xml0000664000175000017620000004476011157271050030301 0ustar davidpalepurple Documentation SimpleTest : tester des scripts web

    Tester des classes c'est trs bien. Reste que PHP est avant tout un langage pour crer des fonctionnalits l'intrieur de pages web. Comment pouvons tester la partie de devant -- celle de l'interface -- dans nos applications en PHP ? Etant donn qu'une page web n'est constitue que de texte, nous devrions pouvoir les examiner exactement comme n'importe quelle autre donne de test.

    Cela nous amne une situation dlicate. Si nous testons dans un niveau trop bas, vrifier des balises avec un motif ad hoc par exemple, nos tests seront trop fragiles. Le moindre changement dans la prsentation pourrait casser un grand nombre de test. Si nos tests sont situs trop haut, en utilisant une version fantaisie du moteur de template pour donner un cas prcis, alors nous perdons compltement la capacit automatiser certaines classes de test. Par exemple, l'interaction entre des formulaires et la navigation devra tre test manuellement. Ces types de test sont extrmement fastidieux et plutt sensibles aux erreurs.

    SimpleTest comprend une forme spciale de scnario de test pour tester les actions d'une page web. WebTestCase inclut des facilits pour la navigation, des vrifications sur le contenu et les cookies ainsi que la gestion des formulaires. Utiliser ces scnarios de test ressemble fortement UnitTestCase... class TestOfLastcraft extends WebTestCase { } ]]> Ici nous sommes sur le point de tester le site de Last Craft. Si ce scnario de test est situ dans un fichier appel lastcraft_test.php alors il peut tre charg dans un script de lancement tout comme des tests unitaires... require_once('simpletest/web_tester.php'); require_once('simpletest/reporter.php'); $test = &new GroupTest('Web site tests'); $test->addTestFile('lastcraft_test.php'); exit ($test->run(new TextReporter()) ? 0 : 1); ?> ]]> J'utilise ici le rapporteur en mode texte pour mieux distinguer le contenu au format HTML du rsultat du test proprement dit.

    Rien n'est encore test. Nous pouvons tlcharger la page d'accueil en utilisant la mthode get()... function testHomepage() { $this->assertTrue($this->get('http://www.lastcraft.com/')); } } ]]> La mthode get() renverra "true" uniquement si le contenu de la page a bien t tlcharg. C'est un moyen simple, mais efficace pour vrifier qu'une page web a bien t dlivr par le serveur web. Cependant le contenu peut rvler tre une erreur 404 et dans ce cas notre mthode get() renverrait encore un succs.

    En supposant que le serveur web pour le site Last Craft soit oprationnel (malheureusement ce n'est pas toujours le cas), nous devrions voir...

    Web site tests
    OK
    Test cases run: 1/1, Failures: 0, Exceptions: 0
    
    Nous avons vrifi qu'une page, de n'importe quel type, a bien t renvoye. Nous ne savons pas encore s'il s'agit de celle que nous souhaitions.

    Pour obtenir la confirmation que la page tlcharge est bien celle que nous attendions, nous devons vrifier son contenu. $this->get('http://www.lastcraft.com/'); $this->assertWantedPattern('/why the last craft/i'); } } ]]> La page obtenue par le dernier tlchargement est place dans un buffer au sein mme du scnario de test. Il n'est donc pas ncessaire de s'y rfrer directement. La correspondance du motif est toujours effectue par rapport ce buffer.

    Voici une liste possible d'assertions sur le contenu...
    assertWantedPattern($pattern)Vrifier une correspondance sur le contenu via une expression rationnelle Perl
    assertNoUnwantedPattern($pattern)Une expression rationnelle Perl pour vrifier une absence
    assertTitle($title)Passe si le titre de la page correspond exactement
    assertLink($label)Passe si un lien avec ce texte est prsent
    assertNoLink($label)Passe si aucun lien avec ce texte est prsent
    assertLinkById($id)Passe si un lien avec cet attribut d'identification est prsent
    assertField($name, $value)Passe si une balise input avec ce nom contient cette valeur
    assertFieldById($id, $value)Passe si une balise input avec cet identifiant contient cette valeur
    assertResponse($codes)Passe si la rponse HTTP trouve une correspondance dans la liste
    assertMime($types)Passe si le type MIME se retrouve dans cette liste
    assertAuthentication($protocol)Passe si l'authentification provoque est de ce type de protocole
    assertNoAuthentication()Passe s'il n'y pas d'authentification provoque en cours
    assertRealm($name)Passe si le domaine provoqu correspond
    assertHeader($header, $content)Passe si une entte tlcharge correspond cette valeur
    assertNoUnwantedHeader($header)Passe si une entte n'a pas t tlcharg
    assertHeaderPattern($header, $pattern)Passe si une entte tlcharge correspond cette expression rationnelle Perl
    assertCookie($name, $value)Passe s'il existe un cookie correspondant
    assertNoCookie($name)Passe s'il n'y a pas de cookie avec un tel nom
    Comme d'habitude avec les assertions de SimpleTest, elles renvoient toutes "false" en cas d'chec et "true" si c'est un succs. Elles renvoient aussi un message de test optionnel : vous pouvez l'ajouter dans votre propre message en utilisant "%s".

    A prsent nous pourrions effectu le test sur le titre uniquement... $this->assertTitle('The Last Craft?'); ]]> En plus d'une simple vrification sur le contenu HTML, nous pouvons aussi vrifier que le type MIME est bien d'un type acceptable... $this->assertMime(array('text/plain', 'text/html')); ]]> Plus intressant encore est la vrification sur le code de la rponse HTTP. Pareillement au type MIME, nous pouvons nous assurer que le code renvoy se trouve bien dans un liste de valeurs possibles... get('http://simpletest.sourceforge.net/'); $this->assertResponse(200); } } ]]> Ici nous vrifions que le tlchargement s'est bien termin en ne permettant qu'une rponse HTTP 200. Ce test passera, mais ce n'est pas la meilleure faon de procder. Il n'existe aucune page sur http://simpletest.sourceforge.net/, la place le serveur renverra une redirection vers http://www.lastcraft.com/simple_test.php. WebTestCase suit automatiquement trois de ces redirections. Les tests sont quelque peu plus robustes de la sorte. Surtout qu'on est souvent plus intress par l'interaction entre les pages que de leur simple livraison. Si les redirections se rvlent tre digne d'intrt, il reste possible de les supprimer... $this->setMaximumRedirects(0); $this->get('http://simpletest.sourceforge.net/'); $this->assertResponse(200); } } ]]> Alors l'assertion choue comme prvue...

    Web site tests
    1) Expecting response in [200] got [302]
    	in testhomepage
    	in testoflastcraft
    	in lastcraft_test.php
    FAILURES!!!
    Test cases run: 1/1, Failures: 1, Exceptions: 0
    
    Nous pouvons modifier le test pour accepter les redirections... setMaximumRedirects(0); $this->get('http://simpletest.sourceforge.net/'); $this->assertResponse(array(301, 302, 303, 307)); } } ]]> Maitenant a passe.

    Les utilisateurs ne naviguent pas souvent en tapant les URLs, mais surtout en cliquant sur des liens et des boutons. Ici nous confirmons que les informations sur le contact peuvent tre atteintes depuis la page d'accueil... get('http://www.lastcraft.com/'); $this->clickLink('About'); $this->assertTitle('About Last Craft'); } } ]]> Le paramtre est le texte du lien.

    Il l'objectif est un bouton plutt qu'une balise ancre, alors clickSubmit() doit tre utilis avec le titre du bouton... $this->clickSubmit('Go!'); ]]>

    La liste des mthodes de navigation est...
    get($url, $parameters)Envoie une requte GET avec ces paramtres
    post($url, $parameters)Envoie une requte POST avec ces paramtres
    head($url, $parameters)Envoie une requte HEAD sans remplacer le contenu de la page
    retry()Relance la dernire requte
    back()Identique au bouton "Prcdent" du navigateur
    forward()Identique au bouton "Suivant" du navigateur
    authenticate($name, $password)Re-essaye avec une tentative d'authentification
    getFrameFocus()Le nom de la fentre en cours d'utilisation
    setFrameFocusByIndex($choice)Change le focus d'une fentre en commenant par 1
    setFrameFocus($name)Change le focus d'une fentre en utilisant son nom
    clearFrameFocus()Revient un traitement de toutes les fentres comme une seule
    clickSubmit($label)Clique sur le premier bouton avec cette tiquette
    clickSubmitByName($name)Clique sur le bouton avec cet attribut de nom
    clickSubmitById($id)Clique sur le bouton avec cet attribut d'identification
    clickImage($label, $x, $y)Clique sur une balise input de type image avec ce titre ou ce texte dans l'attribut alt
    clickImageByName($name, $x, $y)Clique sur une balise input de type image avec ce nom
    clickImageById($id, $x, $y)Clique sur une balise input de type image avec cet attribut d'identification
    submitFormById($id)Soumet un formulaire sans valeur de soumission
    clickLink($label, $index)Clique sur une ancre avec ce texte d'tiquette visible
    clickLinkById($id)Clique sur une ancre avec cet attribut d'identification

    Les paramtres dans les mthodes get(), post() et head() sont optionnels. Le tlchargement via HTTP HEAD ne modifie pas le contexte du navigateur, il se limite au chargement des cookies. Cela peut tre utilise lorsqu'une image ou une feuille de style initie un cookie pour bloquer un robot trop entreprenant.

    Les commandes retry(), back() et forward() fonctionnent exactement comme dans un navigateur. Elles utilisent l'historique pour relancer les pages. Une technique bien pratique pour vrifier les effets d'un bouton retour sur vos formulaires.

    Les mthodes sur les fentres mritent une petite explication. Par dfaut, une page avec des fentres est traite comme toutes les autres. Le contenu sera vrifi travers l'ensemble de la "frameset", par consquent un lien fonctionnera, peu importe la fentre qui contient la balise ancre. Vous pouvez outrepass ce comportement en exigeant le focus sur une unique fentre. Si vous ralisez cela, toutes les recherches et toutes les actions se limiteront cette unique fentre, y compris les demandes d'authentification. Si un lien ou un bouton n'est pas dans la fentre en focus alors il ne peut pas tre cliqu.

    Tester la navigation sur des pages fixes ne vous alerte que quand vous avez cass un script entier. Pour des pages fortement dynamiques, un forum de discussion par exemple, a peut tre crucial pour vrifier l'tat de l'application. Pour la plupart des applications cependant, la logique vraiment dlicate se situe dans la gestion des formulaires et des sessions. Heureusement SimpleTest aussi inclut des outils pour tester des formulaires web.

    Bien que SimpleTest n'ait pas comme objectif de contrler des erreurs rseau, il contient quand mme des mthodes pour modifier et dboguer les requtes qu'il lance. Voici une autre liste de mthode...
    getTransportError()La dernire erreur de socket
    getUrl()La localisation courante
    showRequest()Dverse la requte sortante
    showHeaders()Dverse les enttes d'entre
    showSource()Dverse le contenu brut de la page HTML
    ignoreFrames()Ne recharge pas les framesets
    setCookie($name, $value)Initie un cookie partir de maintenant
    addHeader($header)Ajoute toujours cette entte la requte
    setMaximumRedirects($max)S'arrte aprs autant de redirections
    setConnectionTimeout($timeout)Termine la connexion aprs autant de temps entre les bytes
    useProxy($proxy, $name, $password)Effectue les requtes travers ce proxy d'URL

    Russir tlcharger une page web Tester le contenu de la page Naviguer sur un site web pendant le test Mthodes pour modifier une requte et pour dboguer La page du projet SimpleTest sur SourceForge. La page de tlchargement de SimpleTest sur LastCraft. L'API du dveloppeur pour SimpleTest donne tous les dtails sur les classes et les assertions disponibles. dveloppement logiciel, programmation php pour des clients, php orient client, outils de dveloppement logiciel, framework de test de recette, scripts php gratuits, architecture, ressources php, HTMLUnit, JWebUnit, test php, ressource de test unitaire, test web
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/server_stubs_documentation.xml0000664000175000017620000003310511157271050030653 0ustar davidpalepurple Documentation SimpleTest : les bouchons serveur

    Au dpart il s'agit d'un modle de conception initi par Robert Binder (Testing object-oriented systems: models, patterns, and tools, Addison-Wesley) in 1999. Un bouchon serveur est une simulation d'un objet ou d'un composant. Il doit remplacer exactement un composant dans un systme pour des raisons de testabilit ou de prototypage, tout en restant lger. Il permet aux tests de tourner plus rapidement ou alors, si la classe simule n'a pas t crite, juste de fonctionner.

    Nous avons juste besoin d'une classe prexistante, par exemple une connexion vers une base de donnes qui ressemblerait ... class DatabaseConnection { function DatabaseConnection() { } function query() { } function selectQuery() { } } ]]> La classe n'a mme pas encore besoin d'avoir t implmente. Pour crer la version bouchonne de cette classe, nous incluons la librairie de bouchon serveur et excutons le gnrateur... require_once('simpletest/mock_objects.php'); require_once('database_connection.php'); Stub::generate('DatabaseConnection'); ]]> Est gnr un clone de la classe appel StubDatabaseConnection. Nous pouvons alors crer des instances de cette nouvelle classe l'intrieur de notre prototype de script... $connection = new StubDatabaseConnection(); ]]> La version bouchonne de la classe contient toutes les mthodes de l'original de telle sorte qu'une opration comme query()]]> soit encore lgale. La valeur retourne sera null, Mais nous pouvons y remdier avec... $connection->setReturnValue('query', 37) ]]> Dsormais chaque appel de query()]]> nous obtenons un rsultat de 37. Nous pouvons choisir n'importe quelle valeur pour le rsultat, par exemple un hash de rsultats provenant d'une base de donnes imaginaire ou alors une liste d'objets persistants. Peu importe les paramtres, nous obtenons systmatiquement les mme valeurs chaque fois qu'ils ont t initialiss de la sorte : a ne ressemble peut-tre pas une rponse convaincante venant d'une connexion vers une base de donnes. Mais pour la demi-douzaine de lignes d'une mthode de test c'est souvent largement suffisant.

    Sauf que les choses ne sont que rarement aussi simples. Parmi les problmes les plus courants on trouve les itrateurs : le renvoi d'une valeur constante peut causer une boucle infini dans l'objet test. Pour ceux-ci nous avons besoin de mettre sur pied une suite de valeurs. Prenons par exemple un itrateur simple qui ressemble ... C'est probablement le plus simple des itrateurs possibles. Supposons que cet itrateur ne retourne que du texte, jusqu' la fin - quand il retourne false. Une simulation est possible avec... Stub::generate('Iterator'); $iterator = new StubIterator(); $iterator->setReturnValue('next', false); $iterator->setReturnValueAt(0, 'next', 'First string'); $iterator->setReturnValueAt(1, 'next', 'Second string'); ]]> A l'appel de next() sur l'itrateur bouchonn il va d'abord renvoyer "First string", puis au second appel c'est "Second string" qui sera renvoy. Finalement pour tous les autres appels, il s'agira d'un false. Les valeurs renvoyes successivement ont priorit sur la valeur constante renvoy. Cette dernire est un genre de valeur par dfaut.

    Une autre situation dlicate est une opration get() surcharge. Un exemple ? Un porteur d'information avec des pairs de clef / valeur. Prenons une classe de configuration... Il s'agit d'une situation propice l'utilisation d'objets bouchon, surtout que la configuration en production dpend invariablement de la machine : l'utiliser directement ne va pas nous aider maintenir notre confiance dans nos tests. Sauf que le problme tient de ce que toutes les donnes proviennent de la mthode getValue() et que nous voulons des rsultats diffrents suivant la clef. Par chance les bouchons ont un systme de filtre... Stub::generate('Configuration'); $config = &new StubConfiguration(); $config->setReturnValue('getValue', 'primary', array('db_host')); $config->setReturnValue('getValue', 'admin', array('db_user')); $config->setReturnValue('getValue', 'secret', array('db_password')); ]]> Ce paramtre supplmentaire est une liste d'arguments que l'on peut utiliser. Dans ce cas nous essayons d'utiliser un unique argument, savoir la clef recherche. Maintenant quand on invoque le bouchon serveur via la mthode getValue() avec... getValue('db_user'); ]]> ...il renvoie "admin". Il le trouve en essayant d'assortir successivement les arguments d'entre avec sa liste de ceux de sortie jusqu'au moment o une correspondance exacte est trouve.

    Vous pouvez dfinir un argument par dfaut avec... $config->setReturnValue('getValue', false, array('*')); ]]> Attention ce n'est pas quivalent initialiser la valeur retourne sans aucun argument. $config->setReturnValue('getValue', false); ]]> Dans le premier cas il acceptera n'importe quel argument, mais exactement un -- pas plus -- est ncessaire. Dans le second cas n'importe quel nombre d'arguments fera l'affaire : il agit comme un catchall aprs tous les correspondances. Prenez garde l'ordre : si nous ajoutons un autre paramtre aprs le joker ('*') il sera ignor puisque le joker aura t trouv auparavant. Avec des listes de paramtres complexes l'ordre peut devenir crucial, au risque de perdre des correspondances souhaites, masques par un joker antrieur. Pensez mettre d'abord les cas les plus spcifiques si vous n'tes pas sr.

    Il y a des fois o l'on souhaite qu'un objet spcifique soit servi par le bouchon plutt qu'une simple copie. La smantique de la copie en PHP nous force utiliser une autre mthode pour cela. Vous tes peut-tre en train de simuler un conteneur par exemple... Dans ce cas vous pouvez mettre une rfrence dans la liste renvoye par le bouchon... $vector = &new StubVector(); $vector->setReturnReference('get', $thing, array(12)); ]]> Avec ce petit arrangement vous vous assurez qu' chaque fois que get(12)]]> est appel il renverra le mme $thing.

    Ces trois facteurs, ordre, paramtres et copie (ou rfrence), peuvent tre combins orthogonalement. Par exemple... $complex->setReturnReferenceAt(3, 'get', $stuff, array('*', 1)); ]]> Le $stuff ne sera renvoy qu'au troisime appel et seulement si deux paramtres taient indiqus, avec la contrainte que le second de ceux-ci soit l'entier 1. N'est-ce pas suffisant pour des situations de prototypage simple ?

    Un dernier cas critique reste celle d'un objet en crant un autre, connu sous le nom du modle factory - fabrique. Supposons qu'aprs une requte russie notre base de donnes imaginaire, un ensemble de rsultats est retourn sous la forme d'un itrateur, chaque appel next() donnant une ligne et la fin un false. Au premier abord, a donne l'impression d'tre cauchemardesque simuler. Alors qu'en fait tout peut tre bouchonn en utilisant les mcanismes ci-dessus.

    Voici comment... $result = &new StubResultIterator(); $result->setReturnValue('next', false); $result->setReturnValueAt(0, 'next', array(1, 'tom')); $result->setReturnValueAt(1, 'next', array(3, 'dick')); $result->setReturnValueAt(2, 'next', array(6, 'harry')); $connection = &new StubDatabaseConnection(); $connection->setReturnValue('query', false); $connection->setReturnReference( 'query', $result, array('select id, name from users')); $finder = &new UserFinder($connection); $this->assertIdentical( $finder->findNames(), array('tom', 'dick', 'harry')); } } ]]> Dsormais ce n'est que si notre $connection est appel avec la bonne query() que le $result sera renvoy aprs le troisime appel next(). Cela devrait tre suffisant pour que notre classe UserFinder, la classe effectivement teste ce niveau, puisse s'excuter comme il faut. Un test trs prcis et pas une seule base de donnes l'horizon.

    Il y a d'autres options additionnelles la cration d'un bouchon. Au moment de la gnration nous pouvons changer le nom de la classe... Stub::generate('Iterator', 'MyStubIterator'); $iterator = &new MyStubIterator(); ]]> Pris tout seul ce n'est pas trs utile tant donn qu'il n'y aurait pas de diffrence entre cette classe et celle par dfaut -- part le nom bien entendu. Par contre nous pouvons aussi lui ajouter d'autres mthodes qui ne se trouveraient pas dans l'interface originale... Stub::generate('Iterator', 'PrototypeIterator', array('next', 'isError')); $iterator = &new PrototypeIterator(); $iterator->setReturnValue('next', 0); ]]> Les mthodes next() et isError() peuvent maintenant renvoyer des ensembles de valeurs exactement comme si elles existaient dans la classe originale.

    Un moyen encore plus sotrique de modifier les bouchons est de changer le joker utilis par dfaut pour la correspondance des paramtres. Stub::generate('Connection'); $iterator = &new StubConnection('wild'); $iterator->setReturnValue('query', array('id' => 33), array('wild')); ]]> L'unique raison valable pour effectuer cette opration, c'est quand vous souhaitez tester la chane "*" sans pour autant l'interprter comme un "n'importe lequel".

    Que sont les bouchons ? Crer des bouchons serveur avec SimpleTest. Modles de simulation pour simuler des interactions d'objet plus complexes. Options la gnration pour diffrents contextes. La page du projet SimpleTest sur SourceForge. La page de tlchargement de SimpleTest sur LastCraft. L'API complte pour SimpleTest gnre par PHPDoc. dveloppement logiciel, programmation php, outils de dveloppement logiciel, tutoriel php, outil gratuit de test pour php, architecture, ressuorces php, objets fantaisie, prototypage avec langage de scripts, bouchons serveur, test unitaire, prototypage en php, mthodes de test, mthodologie de test
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/browser_documentation.xml0000664000175000017620000003560411157271050027616 0ustar davidpalepurple Documentation SimpleTest : le composant de navigation web scriptable

    Le composant de navigation web de SimpleTest peut tre utilis non seulement l'extrieur de la classe WebTestCase, mais aussi indpendamment du framework SimpleTest lui-mme.

    Vous pouvez utiliser le navigateur web dans des scripts PHP pour confirmer que des services marchent bien comme il faut ou pour extraire des informations partir de ceux-ci de faon rgulire. Par exemple, voici un petit script pour extraire le nombre de bogues ouverts dans PHP 5 partir du site web PHP... get('http://php.net/'); $browser->clickLink('reporting bugs'); $browser->clickLink('statistics'); $browser->clickLink('PHP 5 bugs only'); $page = $browser->getContent(); preg_match('/status=Open.*?by=Any.*?(\d+)<\/a>/', $page, $matches); print $matches[1]; ?> ]]> Bien sr Il y a des mthodes plus simple pour raliser cet exemple en PHP. Par exemple, vous pourriez juste utiliser la commande PHP file() sur ce qui est ici une page fixe. Cependant, en utilisant des scripts avec le navigateur web vous vous autorisez l'authentification, la gestion des cookies, le chargement automatique des fentres, les redirections, la transmission de formulaires et la capacit d'examiner les enttes. De telles mthodes sont fragiles dans un site en constante volution et vous voudrez employer une mthode plus directe pour accder aux donnes de faon permanente, mais pour des tches simples cette technique peut s'avrer une solution trs rapide.

    Toutes les mthode de navigation utilises dans WebTestCase sont prsente dans la classe SimpleBrowser, mais les assertions sont remplaces par de simples accesseurs. Voici une liste complte des mthodes de navigation de page page...
    addHeader($header)Ajouter une entte chaque tlchargement
    useProxy($proxy, $username, $password)Utilise ce proxy partir de maintenant
    head($url, $parameters)Effectue une requte HEAD
    get($url, $parameters)Tlcharge une page avec un GET
    post($url, $parameters)Tlcharge une page avec un POST
    clickLink($label)Suit un lien par son tiquette
    isLink($label)Vrifie si un lien avec cette tiquette existe
    clickLinkById($id)Suit un lien par son attribut d'identification
    isLinkById($id)Vrifie si un lien avec cet attribut d'identification existe
    getUrl()La page ou la fentre URL en cours
    getTitle()Le titre de la page
    getContent()Le page ou la fentre brute
    getContentAsText()Sans code HTML l'exception du text "alt"
    retry()Rpte la dernire requte
    back()Utilise le bouton "prcdent" du navigateur
    forward()Utilise le bouton "suivant" du navigateur
    authenticate($username, $password)Retente la page ou la fentre aprs une rponse 401
    restart($date)Relance le navigateur pour une nouvelle session
    ageCookies($interval)Change la date des cookies
    setCookie($name, $value)Lance un nouveau cookie
    getCookieValue($host, $path, $name)Lit le cookie le plus spcifique
    getCurrentCookieValue($name)Lit le contenue du cookie en cours
    Les mthode SimpleBrowser::useProxy() et SimpleBrowser::addHeader() sont spciales. Une fois appeles, elles continuent s'appliquer sur les tlchargements suivants.

    Naviguer dans les formulaires est similaire la navigation des formulaires via WebTestCase...
    setField($name, $value)Modifie tous les champs avec ce nom
    setFieldById($id, $value)Modifie tous les champs avec cet identifiant
    getField($name)Accesseur de la valeur d'un lment de formulaire
    getFieldById($id)Accesseur de la valeur de l'lment de formulaire avec cet identifiant
    clickSubmit($label)Transmet le formulaire avec l'tiquette de son bouton
    clickSubmitByName($name)Transmet le formulaire avec l'attribut de son bouton
    clickSubmitById($id)Transmet le formulaire avec l'identifiant de son bouton
    clickImage($label, $x, $y)Clique sur l'image par son texte alternatif
    clickImageByName($name, $x, $y)Clique sur l'image par son attribut
    clickImageById($id, $x, $y)Clique sur l'image par son identifiant
    submitFormById($id)Transmet le formulaire par son identifiant propre
    Au jourd d'aujourd'hui il n'existe aucune mthode pour lister les formulaires et les champs disponibles : ce sera probablement ajout dans des versions successives de SimpleTest.

    A l'intrieur d'une page, les fentres individuelles peuvent tre slectionnes. Si aucune slection n'est ralise alors toutes les fentres sont fusionnes ensemble dans une unique et grande page. Le contenu de la page en cours sera une concatnation des toutes les fentres dans l'ordre spcifi par les balises "frameset".
    getFrames()Un dchargement de la structure de la fentre courante
    getFrameFocus()L'index ou l'tiquette de la fentre en courante
    setFrameFocusByIndex($choice)Slectionne la fentre numrote partir de 1
    setFrameFocus($name)Slectionne une fentre par son tiquette
    clearFrameFocus()Traite toutes les fentres comme une seule page
    Lorsqu'on est focalis sur une fentre unique, le contenu viendra de celle-ci uniquement. Cela comprend les liens cliquer et les formulaires transmettre.

    Toute cette masse de fonctionnalits est gniale lorsqu'on arrive bien tlcharger les pages, mais ce n'est pas toujours vident. Pour aider dcouvrir les erreurs, le navigateur a aussi des mthodes pour aider au dbogage.
    setConnectionTimeout($timeout)Ferme la socket avec un dlai trop long
    getRequest()L'entte de la requte brute de la page ou de la fentre
    getHeaders()L'entte de rponse de la page ou de la fentre
    getTransportError()N'importe quel erreur au niveau de la socket dans le dernier tlchargement
    getResponseCode()La rponse HTTP de la page ou de la fentre
    getMimeType()Le type Mime de la page our de la fentre
    getAuthentication()Le type d'authentification dans l'entte d'une provocation 401
    getRealm()Le realm d'authentification dans l'entte d'une provocation 401
    setMaximumRedirects($max)Nombre de redirections avant que la page ne soit charge automatiquement
    setMaximumNestedFrames($max)Protection contre des framesets rcursifs
    ignoreFrames()Neutralise le support des fentres
    useFrames()Autorise le support des fentres
    Les mthodes SimpleBrowser::setConnectionTimeout(), SimpleBrowser::setMaximumRedirects(),SimpleBrowser::setMaximumNestedFrames(), SimpleBrowser::ignoreFrames() et SimpleBrowser::useFrames() continuent s'appliquer sur toutes les requtes suivantes. Les autres mthodes tiennent compte des fentres. Cela veut dire que si une fentre individuelle ne se charge pas, il suffit de se diriger vers elle avec SimpleBrowser::setFrameFocus() : ensuite on utilisera SimpleBrowser::getRequest(), etc. pour voir ce qui se passe.

    Tout ce qui peut tre fait dans WebTestCase peut maintenant tre fait dans un UnitTestCase. Ce qui revient dire que nous pouvons librement mlanger des tests sur des objets de domaine avec l'interface web... get('http://my-site.com/register.php'); $browser->setField('email', 'me@here'); $browser->setField('password', 'Secret'); $browser->clickSubmit('Register'); $authenticator = &new Authenticator(); $member = &$authenticator->findByEmail('me@here'); $this->assertEqual($member->getPassword(), 'Secret'); } } ]]> Bien que a puisse tre utile par convenance temporaire, je ne suis pas fan de ce genre de test. Ce test s'applique plusieurs couches de l'application, a implique qu'il est plus que probable qu'il faudra le remanier lorsque le code changera.

    Un cas plus utile d'utilisation directe du navigateur est le moment o le WebTestCase ne peut plus suivre. Un exemple ? Quand deux navigateurs doivent tre utiliss en mme temps.

    Par exemple, supposons que nous voulions interdire des usages simultans d'un site avec le mme login d'identification. Ce scnario de test le vrifie... get('http://my-site.com/login.php'); $first->setField('name', 'Me'); $first->setField('password', 'Secret'); $first->clickSubmit('Enter'); $this->assertEqual($first->getTitle(), 'Welcome'); $second = &new SimpleBrowser(); $second->get('http://my-site.com/login.php'); $second->setField('name', 'Me'); $second->setField('password', 'Secret'); $second->clickSubmit('Enter'); $this->assertEqual($second->getTitle(), 'Access Denied'); } } ]]> Vous pouvez aussi utiliser la classe SimpleBrowser quand vous souhaitez crire des scnarios de test en utilisant un autre outil que SimpleTest.

    Utiliser le navigateur web dans des scripts Dboguer les erreurs sur les pages Tests complexes avec des navigateurs web multiples La page du projet SimpleTest sur SourceForge. La page de tlchargement de SimpleTest sur LastCraft. L'API de dveloppeur pour SimpleTest donne tous les dtails sur les classes et les assertions disponibles. dveloppement logiciel, programmation php pour des clients, php centr autour du client, outils de dveloppement logiciel, framework de test de recette, scripts php gratuits, test unitaire de systmes d'authentification, ressources php, HTMLUnit, JWebUnit, test php, ressource de test unitaire, test web, authentification HTTP, tester la connection, tester l'authentification, tests de scurit
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/improving_design_tutorial.xml0000664000175000017620000001754711157271050030476 0ustar davidpalepurple tutoriel de test unitaire en PHP - Conception du haut vers le bas, tester d'abord avec des objets fantaisie

    Commencer par la fantaisie, passer au code ensuite

    J'ai menti.

    Je n'ai pas cr de test pour le scripteur, uniquement l'interface FileWriter que j'ai affich plus tt. En fait je vais encore m'loigner d'un article fini et prsumer l'existence un scripteur abstrait dans classes/writer.php... Writer { function Writer() { } function write($message) { } } ?> ]]> Les changements correspondant au niveau du test sont... Mock::generate('Writer'); class TestOfLogging extends UnitTestCase { function TestOfLogging() { $this->UnitTestCase('Log class test'); } function testWriting() { $clock = &new MockClock($this); $clock->setReturnValue('now', 'Timestamp'); $writer = &new MockWriter($this); $writer->expectOnce('write', array('[Timestamp] Test line')); $log = &new Log($writer); $log->message('Test line', &$clock); $writer->tally(); } } ?> ]]> Afin d'utiliser la classe de log, nous aurions besoin de coder un scripteur de fichier - ou un autre type de scripteur - mais pour le moment nous ne faisons que des tests et nous n'en avons pas encore besoin. En d'autres termes, en utilisant des objets fantaisie nous pouvons dcaler la cration d'un objet de niveau plus bas jusqu'au moment opportun. Non seulement nous pouvons faire la conception du haut vers le bas, mais en plus nous pouvons aussi tester du haut vers le bas.

    S'approcher du bridge - pont

    Imaginez pour un moment que nous ayons commenc la classe de log partir d'une autre direction. Simulez avoir crit juste assez du Log pour avoir raliser le besoin d'un Writer. Comme l'aurions-nous inclus ?

    Bon, l'hritage du scripteur ne nous aurait pas permis de le simuler du point de vue des tests. De celui de la conception nous aurions t restreint un unique scripteur sans hritage multiple.

    Crer un scripteur interne, plutt qu'en le passant au constructeur, en choisissant un nom de classe, est possible, mais nous aurions moins de contrle sur l'initialisation de l'objet fantaisie. Du point de vue de la conception il aurait t presque impossible de passer des paramtres au scripteur dans tous les formats possibles et envisageables. Vous auriez d restreindre le scripteur un hash ou une chane complique dcrivant tous les dtails de la cible. Au mieux compliqu sans raison.

    Utiliser une mthode fabrique pour crer le scripteur intrieurement serait possible, mais a voudrait dire le sous classer pour les tests de manire remplacer la mthode fabrique par une autre mthode renvoyant un leurre. Plus de boulot du point de vue des tests, quoique toujours possible. Du point de vue de la conception, a voudrait dire crer une nouvelle sous-classe de log pour chaque type de scripteur. Cela s'appelle une hirarchie de classe parallle et fait bien entendu de la duplication. Beurk.

    A l'autre extrme, passer ou crer le scripteur chaque message aurait t rptitif et aurait rduit le code de la classe Log une unique mthode, un signe certain que toute la classe est devenue redondante.

    Cette tension entre la facilit du test et le refus de la rptition nous a permis de trouver une conception la fois flexible et propre. Vous vous souvenez de notre bref envie de l'hritage multiple ? Nous l'avons remplac par du polymorphisme (plein de scripteurs) et spar la hirarchie du journal de celle de l'criture. Nous relions les deux par agrgation travers le plus simple Log. Cette astuce est en fait un design pattern (modle de conception) appel "Pont" ou "Bridge".

    Donc nous avons t pouss par le code de test (nous n'avons presque rien crit d'autre) vers un design pattern. Pensez-y une seconde. Les tests amliorent la qualit du code, coup sr dans mon cas, mais il y a quelque chose de bien plus profond et plus puissant.

    Les tests ont amlior la conception.

    Simuler la conception

    Crer un objet fantaisie est aussi simple que de crer l'interface l'crit. Si vous utilisez de l'UML ou d'autres outils pour gnrer ces interfaces alors vous avez un chemin encore plus flexible pour gnrer rapidement vos objets de test. Mme sans, vous pouvez passer du dessin sur tableau blanc, l'criture de l'objet fantaisie, puis la gnration de l'interface qui nous renvoie de nouveau au tableau blanc, le tout trs simplement. Comme le remaniement, la conception, le code et les tests s'unifient.

    Parce que les objets fantaisie travaillent du haut vers le bas, ils peuvent tre amens dans la conception plus rapidement qu'un remaniement classique qui demande quant lui du code fonctionnel avant de pourvoir s'installer. a veut dire que le code de test interagit plus vite avec la conception : par consquent la qualit de la conception augmente elle aussi plus vite.

    Un testeur unitaire est un outil de code. Un testeur unitaire avec objet fantaisie est un outil de conception.

    Simuler maintenant, coder plus tard. Nous drivons vers le design pattern bridge. Conception et test main dans la main. Ce tutorial suit les classes frontire. Vous aurez besoin du framework de test SimpleTest pour essayer ces exemples. Pour des discussions plus fournis sur les objets fantaisie, voyez le Wiki des Extreme Tuesday ou le Wiki C2 (en anglais tous les deux). dveloppement logiciel, tutoriel de programmation php, scnarios de test en php, outils de dveloppement logiciel, tutorial php, scripts php gratuits, architecture, exemple php, exemple d'objet fantaisie, test style junit, architecture logicielle pour des tests, framework de test en php, test unitaire, objet fantaisie en php test php, suite de test php
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/boundary_classes_tutorial.xml0000664000175000017620000004105511157271050030462 0ustar davidpalepurple Tutorial de tests unitaires PHP - Organiser les tests unitaires et les scnarios de test de classe frontire

    Vous pensez probablement que nous avons dsormais puis les modifications sur la classe Log et qu'il n'y a plus rien ajouter. Sauf que les choses ne sont jamais simples avec la Programmation Orient Objet. Vous pensez comprendre un problme et un nouveau cas arrive : il dfie votre point de vue et vous conduit vers une analyse encore plus profonde. Je pensais comprendre la classe de log et que seule la premire page du tutorial l'utiliserait. Aprs a, je serais pass quelque chose de plus compliqu. Personne n'est plus surpris que moi de ne pas l'avoir boucle. En fait je pense que je viens peine de me rendre compte de ce qu'un loggueur fait.

    Variations sur un log

    Supposons que nous ne voulons plus seulement enregistrer les logs vers un fichier. Nous pourrions vouloir les afficher l'cran, les envoyer au daemon syslog d'Unix(tm) via un socket. Comment s'accommoder de tels changements ?

    Le plus simple est de crer des sous-classes de Log qui crasent la mthode message() avec les nouvelles versions. Ce systme fonctionne bien court terme, sauf qu'il a quelque chose de subtilement mais foncirement erron. Supposons que nous crions ces sous-classes et que nous ayons des loggueurs crivant vers un fichier, sur l'cran et via le rseau. Trois classes en tout : a fonctionne. Maintenant supposons que nous voulons ajouter une nouvelle classe de log qui ajoute un filtrage par priorit des messages, ne laissant passer que les messages d'un certain type, le tout suivant un fichier de configuration.

    Nous sommes coincs. Si nous crons de nouvelles sous-classes, nous devons le faire pour l'ensemble des trois classes, ce qui nous donnerait six classes. L'envergure de la duplication est horrible.

    Alors, est-ce que vous tes en train de souhaiter que PHP ait l'hritage multiple ? Effectivement, cela rduirait l'ampleur de la tche court terme, mais aussi compliquerait quelque chose qui devrait tre une classe trs simple. L'hritage multiple, mme support, devrait tre utilis avec le plus grand soin car toutes sortes d'enchevtrements peuvent en dcouler. En fait ce soudain besoin nous dit quelque chose d'autre - peut-tre que notre erreur si situe au niveau de la conception.

    Qu'est-ce que doit faire un loggueur ? Est-ce qu'il envoie un message vers un fichier ? A l'cran ? Via le rseau ? Non. Il envoie un message, point final. La cible de ses messages peut tre slectionne l'initialisation du log, mais aprs a pas touche : le loggueur doit pouvoir combiner et formater les lments du message puisque tel est son vritable boulot. Prsumer que la cible fut un nom de fichier tait une belle paire d'oeillres.

    Abstraire un fichier vers un scripteur

    La solution de cette mauvaise passe est un classique. Tout d'abord nous encapsulons la variation de la classe : cela ajoute un niveau d'indirection. Au lieu d'introduire le nom du fichier comme une chane, nous l'introduisons comme "cette chose vers laquelle on crit" et que nous appelons un Writer. Retour aux tests... require_once('../classes/writer.php'); Mock::generate('Clock'); class TestOfLogging extends UnitTestCase { function TestOfLogging() { $this->UnitTestCase('Log class test'); } function setUp() { @unlink('../temp/test.log'); } function tearDown() { @unlink('../temp/test.log'); } function getFileLine($filename, $index) { $messages = file($filename); return $messages[$index]; } function testCreatingNewFile() { $log = new Log(new FileWriter('../temp/test.log')); $this->assertFalse(file_exists('../temp/test.log'), 'Created before message'); $log->message('Should write this to a file'); $this->assertTrue(file_exists('../temp/test.log'), 'File created'); } function testAppendingToFile() { $log = new Log(new FileWriter('../temp/test.log')); $log->message('Test line 1'); $this->assertWantedPattern( '/Test line 1/', $this->getFileLine('../temp/test.log', 0)); $log->message('Test line 2'); $this->assertWantedPattern( '/Test line 2/', $this->getFileLine('../temp/test.log', 1)); } function testTimestamps() { $clock = &new MockClock($this); $clock->setReturnValue('now', 'Timestamp'); $log = new Log(new FileWriter('../temp/test.log')); $log->message('Test line', &$clock); $this->assertWantedPattern( '/Timestamp/', $this->getFileLine('../temp/test.log', 0), 'Found timestamp'); } } ?> ]]> Je vais parcourir ces tests pas pas pour ne pas ajouter trop de confusion. J'ai remplac les noms de fichier par une classe imaginaire FileWriter en provenance d'un fichier classes/writer.php. Par consquent les tests devraient planter puisque nous n'avons pas encore crit ce scripteur. Doit-on le faire maintenant ?

    Nous pourrions, mais ce n'est pas oblig. Par contre nous avons besoin de crer l'interface, ou alors il ne sera pas possible de la simuler. Au final classes/writer.php ressemble ... ]]> Nous avons aussi besoin de modifier la classe Log... require_once('../classes/writer.php'); class Log { var $_writer; function Log(&$writer) { $this->_writer = &$writer; } function message($message, $clock = false) { if (! is_object($clock)) { $clock = new Clock(); } $this->_writer->write("[" . $clock->now() . "] $message"); } } ?> ]]> Il n'y a pas grand chose qui n'ait pas chang y compris dans la plus petite de nos classes. Dsormais les tests s'excutent mais ne passent pas, moins que nous ajoutions du code dans le scripteur. Alors que faisons nous ?

    Nous pourrions commencer par crire des tests et dvelopper la classe FileWriter paralllement, mais lors de cette tape nos tests de Log continueraient d'chouer et de nous distraire. En fait nous n'en avons pas besoin.

    Une partie de notre objectif est de librer la classe du loggueur de l'emprise du systme de fichiers et il existe un moyen d'y arriver. Tout d'abord nous crons le fichier tests/writer_test.php de manire avoir un endroit pour placer notre code test en provenance de log_test.php et que nous allons brasser. Sauf que je ne vais pas l'ajouter dans le fichier all_tests.php pour l'instant puisque qu'il s'agit de la partie de log que nous sommes en train d'aborder.

    Nous enlevons tous les test de log_test.php qui ne sont pas strictement en lien avec le journal et nous les gardons bien prcieusement dans writer_test.php pour plus tard. Nous allons aussi simuler le scripteur pour qu'il n'crive pas rellement dans un fichier... Mock::generate('FileWriter'); class TestOfLogging extends UnitTestCase { function TestOfLogging() { $this->UnitTestCase('Log class test'); } function testWriting() { $clock = &new MockClock($this); $clock->setReturnValue('now', 'Timestamp'); $writer = &new MockFileWriter($this); $writer->expectArguments('write', array('[Timestamp] Test line')); $writer->expectCallCount('write', 1); $log = &new Log($writer); $log->message('Test line', &$clock); $writer->tally(); } } ?> ]]> Eh oui c'est tout : il s'agit bien de l'ensemble du scnario de test et c'est normal qu'il soit aussi court. Pas mal de choses se sont passes...

    1. La ncessit de crer le fichier uniquement si ncessaire a t dplace vers le FileWriter.
    2. tant donn que nous travaillons avec des objets fantaisie, aucun fichier n'a t cr et donc setUp() et tearDown() passent dans les tests du scripteur.
    3. Dsormais le test consiste simplement dans l'envoi d'un message type et du test de son format.
    Attendez un instant, o sont les assertions ?

    Les objets fantaisie font beaucoup plus que se comporter comme des objets, ils excutent aussi des test. L'appel expectArguments() dit l'objet fantaisie d'attendre un seul paramtre de la chane "[Timestamp] Test" quand la mthode fantaise write() est appele. Lorsque cette mthode est appele les paramtres attendus sont compars avec ceci et un succs ou un chec est renvoy comme rsultat au test unitaire. C'est pourquoi un nouvel objet fantaisie a une rfrence vers $this dans son constructeur, il a besoin de ce $this pour l'envoi de son propre rsultat.

    L'autre attente, c'est que le write ne soit appel qu'une seule et unique fois. Juste l'initialiser ne serait pas suffisant. L'objet fantaisie attendrait une ternit si la mthode n'tait jamais appele et par consquent n'enverrait jamais le message d'erreur la fin du test. Pour y faire face, l'appel tally() lui dit de vrifier le nombre d'appel ce moment l. Nous pouvons voir tout a en lanant les tests...

    All tests

    Pass: log_test.php->Log class test->testwriting->Arguments for [write] were [String: [Timestamp] Test line]
    Pass: log_test.php->Log class test->testwriting->Expected call count for [write] was [1], but got [1]
    Pass: clock_test.php->Clock class test->testclockadvance->Advancement
    Pass: clock_test.php->Clock class test->testclocktellstime->Now is the right time
    3/3 test cases complete. 4 passes and 0 fails.

    En fait nous pouvons encore raccourcir nos tests. L'attente de l'objet fantaisie expectOnce() peut combiner les deux attentes spares. setReturnValue('now', 'Timestamp'); $writer = &new MockFileWriter($this); $writer->expectOnce('write', array('[Timestamp] Test line')); $log = &new Log($writer); $log->message('Test line', &$clock); $writer->tally(); } ]]> Cela peut tre une abrviation utile.

    Classes frontires

    Quelque chose de trs agrable est arrive au loggueur en plus de devenir purement et simplement plus court.

    Les seules choses dont il dpend sont maintenant des classes que nous avons crites nous-mme et qui dans les tests sont simules : donc aucune dpendance hormis notre propre code PHP. Pas de fichier crire ni de dclenchement via une horloge attendre. Cela veut dire que le scnario de test log_test.php va s'excuter aussi vite que le processeur le permet. Par contraste les classes FileWriter et Clock sont trs proches du systme. Plus difficile tester puisque de vraies donnes doivent tre dplaces et valides avec soin, souvent par des astuces ad hoc.

    Notre dernire factorisation a beaucoup aid. Les classes aux frontires de l'application et du systme, celles qui sont difficiles tester, sont dsormais plus courtes tant donn que le code d'I/O a t loign encore plus de la logique applicative. Il existe des liens directs vers des oprations PHP : FileWriter::write() s'apparente l'quivalent PHP fwrite() avec le fichier ouvert pour l'ajout et Clock::now() s'apparente lui aussi un quivalent PHP time(). Primo le dbogage devient plus simple. Secundo ces classes devraient bouger moins souvent.

    Si elles ne changent pas beaucoup alors il n'y a aucune raison pour continuer en excuter les tests. Cela veut dire que les tests pour les classes frontires peuvent tre dplaces vers leur propre suite de tests, laissant les autres tourner plein rgime. En fait c'est comme a que j'ai tendance travailler et les scnarios de test de SimpleTest lui-mme sont diviss de cette manire.

    Peut-tre que a ne vous parat pas beaucoup avec un test unitaire et deux tests aux frontires, mais une application typique peut contenir vingt classes de frontire et deux cent classes d'application. Pour continuer leur excution toute vitesse, vous voudrez les tenir spares.

    De plus, un bon dveloppement passe par des dcisions de tri entre les composants utiliser. Peut-tre, qui sait, tous ces simulacres pourront amliorer votre conception.

    Variations sur un log Abstraire un niveau supplmentaire via une classe fantaisie d'un scripteur Sparer les tests des classes frontires pour un petit nettoyage Ce tutorial suit l'introduction aux objets fantaisies. Ensuite vient la conception pilote par les tests. Vous aurez besoin du framework de test SimpleTest pour essayer ces exemples. dveloppement logiciel, programmation php, outils de dveloppement logiciel, tutorial php, scripts php gratuits, organisation de tests unitaires, conseil de test, astuce de dveloppement, architecture logicielle pour des tests, exemple de code php, objets fantaisie, port de junit, exemples de scnarios de test, test php, outil de test unitaire, suite de test php
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/subclass_tutorial.xml0000664000175000017620000002262511157271050026743 0ustar davidpalepurple Tutorial de test unitaire en PHP - Sous classer un scnario de test

    Une assertion insensible au chronomtre

    Nous avions laiss notre test d'horloge avec un trou. Si la fonction time() de PHP avanait pendant cette comparaison... assertEqual($clock->now(), time(), 'Now is the right time'); } ]]> ...notre test aurait un cart d'une seconde et entranerait un faux chec. Un comportement erratique de notre suite de test n'est vraiment pas ce que nous souhaitons : nous pourrions la lancer une centaine de fois par jour.

    Nous pourrions r-crire notre test... $time1 = $clock->now(); $time2 = time(); $this->assertTrue(($time1 == $time2) || ($time1 + 1 == $time2), 'Now is the right time'); } ]]> Sauf que la conception n'est pas plus claire et que nous devrons le rpter pour chaque test de chronomtrage. Les rptitions sont un ennemi public n1 et donc un trs bon stimulant pour le remaniement de notre code de test. UnitTestCase('Clock class test'); } function assertSameTime($time1, $time2, $message) { $this->assertTrue( ($time1 == $time2) || ($time1 + 1 == $time2), $message); } function testClockTellsTime() { $clock = new Clock(); $this->assertSameTime($clock->now(), time(), 'Now is the right time'); } function testClockAdvance() { $clock = new Clock(); $clock->advance(10); $this->assertSameTime($clock->now(), time() + 10, 'Advancement'); } } ]]> Bien entendu chaque modification je relance les tests pour bien vrifier que nous sommes dans les clous. Remaniement au vert. C'est beaucoup plus sr.

    Rutiliser notre assertion

    Peut-tre voulons nous ajouter d'autres tests sensibles au temps. Peut-tre lisons nous des timestamps - en provenance d'une entre dans une base de donnes ou d'ailleurs - qui tiendraient compte d'une simple seconde pour basculer. Pour que ces nouvelles classes de test profitent de notre nouvelle assertion nous avons besoin de la placer dans une "super classe".

    Voici notre fichier clock_test.php au complet aprs la promotion de notre mthode assertSameTime() dans sa propre "super classe"... class TimeTestCase extends UnitTestCase { function TimeTestCase($test_name) { $this->UnitTestCase($test_name); } function assertSameTime($time1, $time2, $message) { $this->assertTrue( ($time1 == $time2) || ($time1 + 1 == $time2), $message); } } class TestOfClock extends TimeTestCase { function TestOfClock() { $this->TimeTestCase('Clock class test'); } function testClockTellsTime() { $clock = new Clock(); $this->assertSameTime($clock->now(), time(), 'Now is the right time'); } function testClockAdvance() { $clock = new Clock(); $clock->advance(10); $this->assertSameTime($clock->now(), time() + 10, 'Advancement'); } } ?> ]]> Dsormais nous bnficions de notre nouvelle assertion chaque fois que nous hritons de notre propre classe TimeTestCase plutt que de la classe par dfaut UnitTestCase. Nous retrouvons la conception de l'outil JUnit et SimpleTest est un portage en PHP de cette interface. Il s'agit d'un framework de test partir duquel votre propre systme de test peut s'agrandir.

    Si nous lanons les tests maintenant une lgre broutille survient...

    Warning: Missing argument 1 for timetestcase() in /home/marcus/projects/lastcraft/tutorial_tests/tests/clock_test.php on line 5

    All tests

    3/3 test cases complete. 6 passes and 0 fails.
    La raison est assez dlicate.

    Notre sous-classe exige un paramtre dans le constructeur qui n'a pas t fourni et pourtant il semblerait que nous l'ayons bel et bien fourni. Quand nous avons hrit de notre nouvelle casse nous lui avons pass notre propre constructeur. C'est juste l... TimeTestCase('Clock class test'); } ]]> En fait nous avons raison, l n'est pas le problme.

    Vous vous souvenez de quand nous avons construit le test de groupe all_tests.php en utilisant la mthode addTestFile(). Cette mthode recherche les classes de scnario de test, les instancie si elles sont nouvelles puis excute tous nos tests. Ce qui s'est pass ? Elle a aussi trouv notre extension de scnario de test. C'est sans consquence puisque qu'il n'y a pas de mthode de test l'intrieur - comprendre pas de mthode commenant par "test". Aucun test supplmentaire n'est excut.

    Le problme vient du fait qu'il instancie la classe et le fait sans le paramtre $test_name qui dclenche l'avertissement. Ce paramtre n'est gnralement ncessaire ni pour un scnario de test, ni pour son assertion. Pour que notre scnario de test tendu corresponde l'interface de UnitTestCase, nous avons besoin de le rendre optionnel... $test_name = false) { $this->UnitTestCase($test_name); } function assertSameTime($time1, $time2, $message = false) { if (! $message) { $message = "Time [$time1] should match time [$time2]"; } $this->assertTrue( ($time1 == $time2) || ($time1 + 1 == $time2), $message); } } ]]> Bien sr, que cette classe soit instancie sans raison par la suite de test devrait continuer vous ennuyer. Voici une modification pour l'empcher de s'excuter... SimpleTestOptions::ignore('TimeTestCase'); class TimeTestCase extends UnitTestCase { function TimeTestCase($test_name = false) { $this->UnitTestCase($test_name); } function assertSameTime($time1, $time2, $message = '') { if (!$message) { $message = "Time [$time1] should match time [$time2]"; } $this->assertTrue( ($time1 == $time2) || ($time1 + 1 == $time2), $message); } } ]]> Cette ligne ne fait que demander SimpleTest d'ignorer cette classe lors de la construction des suites de test. Elle peut tre ajoute n'importe o dans le fichier de scnario de test.

    Les six succs ont l'air bien mais ne disent pas un observateur peu attentif ce qui a t test. Pour cela il faut regarder dans le code. Si cela vous parat trop de boulot et que vous prfreriez lire ces informations directement alors vous devriez aller lire comment afficher les succs.

    Une assertion insensible au chronomtre qui permet de gagner une seconde. Sous classer un scnario de test afin de rutiliser la mthode de test. Section prcdente : contrler les variables de test. Section suivante : changer l'affichage des tests. Vous aurez besoin du testeur unitaire SimpleTest pour les exemples. dveloppement logiciel, programmation php, outils de dveloppement logiciel, tutorial php, scripts php gratuits, organisation de tests unitaires, cration de sous-classe, conseil de test, astuce de dveloppement, exemple de code php, objets fantaisie, junit, test php, outil de test unitaire, suite de test php
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/partial_mocks_documentation.xml0000664000175000017620000003543411157271050030764 0ustar davidpalepurple Documentation SimpleTest : les objets fantaisie partiels

    Un objet fantaisie partiel n'est ni plus ni moins qu'un modle de conception pour soulager un problme spcifique du test avec des objets fantaisie, celui de placer des objets fantaisie dans des coins serrs. Il s'agit d'un outil assez limit et peut-tre mme une ide pas si bonne que a. Elle est incluse dans SimpleTest pour la simple raison que je l'ai trouve utile plus d'une occasion et qu'elle m'a pargne pas mal de travail dans ces moments-l.

    Quand un objet en utilise un autre il est trs simple d'y faire circuler une version fantaisie dj prte avec ses attentes. Les choses deviennent un peu plus dlicates si un objet en cre un autre et que le crateur est celui que l'on souhaite tester. Cela revient dire que l'objet cr devrait tre une fantaisie, mais nous pouvons difficilement dire notre classe sous test de crer un objet fantaisie plutt qu'un "vrai" objet. La classe teste ne sait mme pas qu'elle travaille dans un environnement de test.

    Par exemple, supposons que nous sommes en train de construire un client telnet et qu'il a besoin de crer une socket rseau pour envoyer ses messages. La mthode de connexion pourrait ressemble quelque chose comme... read( ... ); ... } } ?> ]]> Nous voudrions vraiment avoir une version fantaisie de l'objet socket, que pouvons nous faire ?

    La premire solution est de passer la socket en tant que paramtre, ce qui force la cration au niveau infrieur. Charger le client de cette tche est effectivement une bonne approche si c'est possible et devrait conduire un remaniement -- de la cration partir de l'action. En fait, c'est l une des manires avec lesquels tester en s'appuyant sur des objets fantaisie vous force coder des solutions plus resserres sur leur objectif. Ils amliorent votre programmation.

    Voici ce que a devrait tre... function &connect(&$socket, $username, $password) { $socket->read( ... ); ... } } ?> ]]> Sous-entendu, votre code de test est typique d'un cas de test avec un objet fantaisie. $socket = &new MockSocket($this); ... $telnet = &new Telnet(); $telnet->connect($socket, 'Me', 'Secret'); ... } } ]]> C'est assez vident que vous ne pouvez descendre que d'un niveau. Vous ne voudriez pas que votre application de haut niveau cre tous les fichiers de bas niveau, sockets et autres connexions la base de donnes dont elle aurait besoin. Elle ne connatrait pas les paramtres du constructeur de toute faon.

    La solution suivante est de passer l'objet cr sous la forme d'un paramtre optionnel... function &connect($ip, $port, $username, $password, $socket = false) { if (!$socket) { $socket = &new Socket($ip, $port); } $socket->read( ... ); ... return $socket; } } ?> ]]> Pour une solution rapide, c'est gnralement suffisant. Ensuite le test est trs similaire : comme si le paramtre tait transmis formellement... $socket = &new MockSocket($this); ... $telnet = &new Telnet(); $telnet->connect('127.0.0.1', 21, 'Me', 'Secret', &$socket); ... } } ]]> Le problme de cette approche tient dans son manque de nettet. Il y a du code de test dans la classe principale et aussi des paramtres transmis dans le scnario de test qui ne sont jamais utiliss. Il s'agit l d'une approche rapide et sale, mais qui ne reste pas moins efficace dans la plupart des situations.

    Une autre solution encore est de laisser un objet fabrique s'occuper de la cration... function Telnet(&$network) { $this->_network = &$network; } ... function &connect($ip, $port, $username, $password) { $socket = &$this->_network->createSocket($ip, $port); $socket->read( ... ); ... return $socket; } } ?> ]]> Il s'agit l probablement de la rponse la plus travaille tant donn que la cration est maintenant situe dans une petite classe spcialise. La fabrique rseau peut tre teste sparment et utilise en tant que fantaisie quand nous testons la classe telnet... $socket = &new MockSocket($this); ... $network = &new MockNetwork($this); $network->setReturnReference('createSocket', $socket); $telnet = &new Telnet($network); $telnet->connect('127.0.0.1', 21, 'Me', 'Secret'); ... } } ]]> Le problme reste que nous ajoutons beaucoup de classes la bibliothque. Et aussi que nous utilisons beaucoup de fabriques ce qui rend notre code un peu moins intuitif. La solution la plus flexible, mais aussi la plus complexe.

    Peut-on trouver un juste milieu ?

    Il existe une technique pour palier ce problme sans crer de nouvelle classe dans l'application; par contre elle induit la cration d'une sous-classe au moment du test. Premirement nous dplaons la cration de la socket dans sa propre mthode... $socket = &$this->_createSocket($ip, $port); $socket->read( ... ); ... } function &_createSocket($ip, $port) { return new Socket($ip, $port); } } ?> ]]> Il s'agit l de la seule modification dans le code de l'application.

    Pour le scnario de test, nous devons crer une sous-classe de manire intercepter la cration de la socket... class TelnetTestVersion extends Telnet { var $_mock; function TelnetTestVersion(&$mock) { $this->_mock = &$mock; $this->Telnet(); } function &_createSocket() { return $this->_mock; } } ]]> Ici j'ai dplac la fantaisie dans le constructeur, mais un setter aurait fonctionn tout aussi bien. Notez bien que la fantaisie est place dans une variable d'objet avant que le constructeur ne soit attach. C'est ncessaire dans le cas o le constructeur appelle connect(). Autrement il pourrait donner un valeur nulle partir de _createSocket().

    Aprs la ralisation de tout ce travail supplmentaire le scnario de test est assez simple. Nous avons juste besoin de tester notre nouvelle classe la place... $socket = &new MockSocket($this); ... $telnet = &new TelnetTestVersion($socket); $telnet->connect('127.0.0.1', 21, 'Me', 'Secret'); ... } } ]]> Cette nouvelle classe est trs simple bien sr. Elle ne fait qu'initier une valeur renvoye, la manire d'une fantaisie. Ce serait pas mal non plus si elle pouvait vrifier les paramtres entrants. Exactement comme un objet fantaisie. Il se pourrait bien que nous ayons raliser cette astuce rgulirement : serait-il possible d'automatiser la cration de cette sous-classe ?

    Bien sr la rponse est "oui" ou alors j'aurais arrt d'crire depuis quelques temps dj ! Le test prcdent a reprsent beaucoup de travail, mais nous pouvons gnrer la sous-classe en utilisant une approche celle des objets fantaisie.

    Voici donc une version avec objet fantaisie partiel du test... Mock::generatePartial( 'Telnet', 'TelnetTestVersion', array('_createSocket')); class TelnetTest extends UnitTestCase { ... function testConnection() { $socket = &new MockSocket($this); ... $telnet = &new TelnetTestVersion($this); $telnet->setReturnReference('_createSocket', $socket); $telnet->Telnet(); $telnet->connect('127.0.0.1', 21, 'Me', 'Secret'); ... } } ]]> La fantaisie partielle est une sous-classe de l'original dont on aurait "remplac" les mthodes slectionnes avec des versions de test. L'appel generatePartial() ncessite trois paramtres : la classe sous classer, le nom de la nouvelle classe et une liste des mthodes simuler.

    Instancier les objets qui en rsultent est plutt dlicat. L'unique paramtre du constructeur d'un objet fantaisie partiel est la rfrence du testeur unitaire. Comme avec les objets fantaisie classiques c'est ncessaire pour l'envoi des rsultats de test en rponse la vrification des attentes.

    Une nouvelle fois le constructeur original n'est pas lanc. Indispensable dans le cas o le constructeur aurait besoin des mthodes fantaisie : elles n'ont pas encore t inities ! Nous initions les valeurs retournes cet instant et ensuite lanons le constructeur avec ses paramtres normaux. Cette construction en trois tapes de "new", suivie par la mise en place des mthodes et ensuite par la lancement du constructeur proprement dit est ce qui distingue le code d'un objet fantaisie partiel.

    A part pour leur construction, toutes ces mthodes fantaisie ont les mmes fonctionnalits que dans le cas des objets fantaisie et toutes les mthodes non fantaisie se comportent comme avant. Nous pouvons mettre en place des attentes trs facilement... setReturnReference('_createSocket', $socket); $telnet->expectOnce('_createSocket', array('127.0.0.1', 21)); $telnet->Telnet(); $telnet->connect('127.0.0.1', 21, 'Me', 'Secret'); ... $telnet->tally(); } } ]]>

    Les mthodes issues d'un objet fantaisie n'ont pas besoin d'tre des mthodes fabrique, Il peut s'agir de n'importe quelle sorte de mthode. Ainsi les objets fantaisie partiels nous permettent de prendre le contrle de n'importe quelle partie d'une classe, le constructeur except. Nous pourrions mme aller jusqu' crer des fantaisies sur toutes les mthodes part celle que nous voulons effectivement tester.

    Cette situation est assez hypothtique, tant donn que je ne l'ai jamais essaye. Je suis ouvert cette possibilit, mais je crains qu'en forant la granularit d'un objet on n'obtienne pas forcment un code de meilleur qualit. Personnellement j'utilise les objets fantaisie partiels comme moyen de passer outre la cration ou alors de temps en temps pour tester le modle de conception TemplateMethod.

    Pour choisir le mcanisme utiliser, on en revient toujours aux standards de code de votre projet.

    Le problme de l'injection d'un objet fantaisie. Dplacer la cration vers une mthode fabrique protge. L'objet fantaisie partiel gnre une sous-classe. Les objets fantaisie partiels testent moins qu'une classe. La page du projet SimpleTest sur SourceForge. L'API complte pour SimpleTest partir de PHPDoc. La mthode fabrique protge est dcrite dans cet article d'IBM. Il s'agit de l'unique papier formel que j'ai vu sur ce problme. dveloppement logiciel en php, dvelopement d'un scnario de test en php, programmation php avec base de donnes, outils de dveloppement logiciel, tutoriel avanc en php, scripts la manire de phpunit, architecture, ressources php, objets fantaisie, junit, framework de test en php, test unitaire, test en php
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/gain_control_tutorial.xml0000664000175000017620000002702211157271050027576 0ustar davidpalepurple Tutorial de test unitaire en PHP - Isoler les variables pendant le test

    Pour tester un module de code vous avez besoin d'avoir un contrle trs prcis sur son environnement. Si quelque chose change dans les coulisses, par exemple dans un fichier de configuration, alors les tests peuvent chouer de faon inattendue. Il ne s'agirait plus d'un test de code sans quivoque et pourrait vous faire perdre des heures prcieuses la recherche d'erreurs dans un code qui fonctionne. Alors qu'il s'agit d'un problme de configuration qui plante le test en question. Au mieux vos scnarios de test deviennent de plus en plus compliqus afin de prendre en compte toutes les variations possibles.

    Contrler le temps

    Il y a souvent beaucoup de variables videntes qui peuvent affecter un scnario de test unitaire, d'autant plus dans un environnement de dveloppement web dans lequel PHP a ses aises. Parmi celles-ci, on trouve les paramtres de connexion la base de donnes et ceux de configuration, les droits de fichier et les ressources rseau, etc. L'chec ou la mauvaise installation de l'un ou l'autre de ces composants cassera la suite de test. Est-ce que nous devons ajouter des tests pour valider l'installation de ces composants ? C'est une bonne ide mais si vous les placez dans les tests du module de code vous aller commencer encombrer votre code de test avec des dtails hors de propos avec la tche en cours. Ils doivent tre placs dans leur propre groupe de tests.

    Par contre un autre problme reste : nos machines de dveloppement doivent aussi avoir tous les composants systme d'installs avant l'excution de la suite de test. Et vos tests s'excuteront plus lentement.

    Devant un tel dilemme, nous crerons souvent des versions enveloppantes des classes qui grent ces ressources. Les vilains dtails de ces ressources sont ensuite cods une seule fois. J'aime bien appeler ces classes des "classes frontire" tant donn qu'elles existent en bordure de l'application, l'interface entre votre application et le reste du systme. Ces classes frontire sont - dans le meilleur des cas - simules pendant les tests par des versions de simulacre. Elles s'excutent plus rapidement et sont souvent appeles "bouchon serveur [Ndt : Server Stubs]" ou dans leur forme plus gnrique "objet fantaisie [Ndt : Mock Objects]". Envelopper et bouchonner chacune de ces ressources permet d'conomiser pas mal de temps.

    Un des facteurs souvent ngligs reste le temps. Par exemple, pour tester l'expiration d'une session des codeurs vont souvent temporairement en caler la dure une valeur trs courte, disons 2 secondes, et ensuite effectuer un sleep(3) : ils estiment alors que la session a expire. Sauf que cette opration ajoute 3 secondes la suite de test : il s'agit souvent de beaucoup de code en plus pour rendre la classe de session aussi mallable. Plus simple serait d'avoir un moyen d'avancer l'horloge arbitrairement. De contrler le temps.

    Une classe horloge

    Une nouvelle fois, nous allons effectuer notre conception d'une enveloppe d'horloge via l'criture de tests. Premirement nous ajoutons un scnario de test d'horloge dans notre suite de test tests/all_tests.php... require_once('clock_test.php'); $test = &new GroupTest('All tests'); $test->addTestCase(new TestOfLogging()); $test->addTestCase(new TestOfClock()); $test->run(new HtmlReporter()); ?> ]]> Ensuite nous crons le scnario de test dans un nouveau fichier tests/clock_test.php... UnitTestCase('Clock class test'); } function testClockTellsTime() { $clock = new Clock(); $this->assertEqual($clock->now(), time(), 'Now is the right time'); } function testClockAdvance() { } } ?> ]]> Notre unique test pour le moment, c'est que notre nouvelle class Clock se comporte comme un simple substitut de la fonction time() en PHP. L'autre mthode tient lieu d'emploi. C'est notre chose faire en quelque sorte. Nous ne lui avons pas donne de test parce que a casserait notre rythme. Nous crirons cette fonctionnalit de dcalage dans le temps une fois que nous serons au vert. Pour le moment nous ne sommes videmment pas dans le vert...

    Fatal error: Failed opening required '../classes/clock.php' (include_path='') in /home/marcus/projects/lastcraft/tutorial_tests/tests/clock_test.php on line 2
    Nous crons un fichier classes/clock.php comme ceci... ]]> De la sorte nous reprenons le cours du code.

    All tests

    Fail: Clock class test->testclocktellstime->[NULL: ] should be equal to [integer: 1050257362]
    3/3 test cases complete. 4 passes and 1 fails.
    Facile corriger... return time(); } } ]]> Et nous revoici dans le vert...

    All tests

    3/3 test cases complete. 5 passes and 0 fails.
    Il y a juste un petit problme. L'horloge pourrait basculer pendant l'assertion et crer un cart d'une seconde. Les probabilits sont assez faibles mais s'il devait y avoir beaucoup de tests de chronomtrage nous finirions avec une suite de test qui serait erratique et forcment presque inutile. Nous nous y attaquerons bientt et pour l'instant nous l'ajoutons dans la liste des "choses faire".

    Le test d'avancement ressemble ... UnitTestCase('Clock class test'); } function testClockTellsTime() { $clock = new Clock(); $this->assertEqual($clock->now(), time(), 'Now is the right time'); } function testClockAdvance() { $clock = new Clock(); $clock->advance(10); $this->assertEqual($clock->now(), time() + 10, 'Advancement'); } } ]]> Le code pour arriver au vert est direct : il suffit d'ajouter un dcalage de temps. var $_offset; function Clock() { $this->_offset = 0; } function now() { return time() + $this->_offset; } function advance($offset) { $this->_offset += $offset; } } ]]>

    Nettoyer le test de groupe

    Notre fichier all_tests.php contient des rptitions dont nous pourrions nous dbarrasser. Nous devons ajouter manuellement tous nos scnarios de test depuis chaque fichier inclus. C'est possible de les enlever mais avec les prcautions suivantes. La classe GroupTest inclue une mthode bien pratique appele addTestFile() qui prend un fichier PHP comme paramtre. Ce mcanisme prend note de toutes les classes : elle inclut le fichier et ensuite regarde toutes les classes nouvellement cres. S'il y a des filles de TestCase elles sont ajoutes au nouveau test de groupe.

    Voici notre suite de test remanie en appliquant cette mthode... require_once(SIMPLE_TEST . 'unit_tester.php'); require_once(SIMPLE_TEST . 'reporter.php'); $test = &new GroupTest('All tests'); $test->addTestFile('log_test.php'); $test->addTestFile('clock_test.php'); $test->run(new HtmlReporter()); ?> ]]> Les inconvniants sont les suivants...

    1. Si le fichier de test a dj t inclus, aucune nouvelle classe ne sera ajoute au groupe.
    2. Si le fichier de test contient d'autres classes relies TestCase alors celles-ci aussi seront ajout au test de groupe.
    Dans nos test nous n'avons que des scnarios dans les fichiers de test et en plus nous avons supprim leur inclusion du script all_tests.php : nous sommes donc en rgle. C'est la situation la plus commune.

    Nous devrions corriger au plus vite le petit problme de dcalage possible sur l'horloge : c'est ce que nous faisons ensuite.

    Le temps est souvent une variable nglige dans les tests. Une classe horloge nous permet de modifier le temps. Nettoyer le test de groupe. La section prcdente : grouper des tests unitaires. La section suivante : sous classer les scnarios de test. Vous aurez besoin du testeur unitaire SimpleTest pour les exemples. dveloppement logiciel, programmation php, outils de dveloppement logiciel, tutorial php, scripts php gratuits, organisation de tests unitaires, conseil de test, astuce de dveloppement, architecture logicielle pour des tests, exemple de code php, objets fantaisie, junit, test php, outil de test unitaire, suite de test php
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/overview.xml0000664000175000017620000004711611157271050025051 0ustar davidpalepurple Aperu et liste des fonctionnalits des testeurs unitaires PHP et web de SimpleTest PHP

    Le coeur de SimpleTest est un framework de test construit autour de classes de scnarios de test. Celles-ci sont crites comme des extensions des classes premires de scnarios de test, chacune largie avec des mthodes qui contiennent le code de test effectif. Les scripts de test de haut niveau invoque la mthode run() chaque scnario de test successivement. Chaque mthode de test est crite pour appeler des assertions diverses que le dveloppeur suppose tre vraies, assertEqual() par exemple. Si l'assertion est correcte, alors un succs est expdi au rapporteur observant le test, mais toute erreur dclenche une alerte et une description de la dissension.

    Un scnario de test ressemble ... MyTestCase extends UnitTestCase { function testLog() { $log = &new Log('my.log'); $log->message('Hello'); $this->assertTrue(file_exists('my.log')); } } ]]>

    Ces outils sont conus pour le dveloppeur. Les tests sont crits en PHP directement, plus ou moins simultanment avec la construction de l'application elle-mme. L'avantage d'utiliser PHP lui-mme comme langage de test est qu'il n'y a pas de nouveau langage apprendre, les tests peuvent commencer directement et le dveloppeur peut tester n'importe quelle partie du code. Plus simplement, toutes les parties qui peuvent tre accdes par le code de l'application peuvent aussi tre accdes par le code de test si ils sont tous les deux dans le mme langage.

    Le type de scnario de test le plus simple est le UnitTestCase. Cette classe de scnario de test inclut les tests standards pour l'galit, les rfrences et l'appariement de motifs (via les expressions rationnelles). Ceux-ci testent ce que vous seriez en droit d'attendre du rsultat d'une fonction ou d'une mthode. Il s'agit du type de test le plus commun pendant le quotidien du dveloppeur, peut-tre 95% des scnarios de test.

    La tche ultime d'une application web n'est cependant pas de produire une sortie correcte partir de mthodes ou d'objets, mais plutt de produire des pages web. La classe WebTestCase teste des pages web. Elle simule un navigateur web demandant une page, de faon exhaustive : cookies, proxies, connexions scurises, authentification, formulaires, cadres et la plupart des lments de navigation. Avec ce type de scnario de test, le dveloppeur peut garantir que telle ou telle information est prsente dans la page et que les formulaires ainsi que les sessions sont grs comme il faut.

    Un scnario de test web ressemble ... MySiteTest extends WebTestCase { function testHomePage() { $this->get('http://www.my-site.com/index.php'); $this->assertTitle('My Home Page'); $this->clickLink('Contact'); $this->assertTitle('Contact me'); $this->assertWantedPattern('/Email me at/'); } } ]]>

    Ci-dessous vous trouverez un canevas assez brut des fonctionnalits aujourd'hui et pour demain, sans oublier leur date approximative de publication. J'ai bien peur qu'il soit modifiable sans pr-avis tant donn que les jalons dpendent beaucoup sur le temps disponible. Les trucs en vert ont t cods, mais pas forcment dj rendus public. Si vous avez une besoin pressant pour une fonctionnalit verte mais pas encore publique alors vous devriez retirer le code directement sur le CVS chez SourceFourge. Une fonctionnalite publie est indiqu par "Fini".
    FonctionnalitDescriptionPublication
    Scnariot de test unitaire Les classes de test et assertions de base Fini
    Affichage HTML L'affichage le plus simple possible Fini
    Autochargement des scnarios de test Lire un fichier avec des scnarios de test et les charger dans un groupe de tests automatiquement Fini
    Gnrateur de code d'objets fantaisie Des objets capable de simuler d'autres objets, supprimant les dpendances dans les tests Fini
    Bouchons serveur Des objets fantaisie sans rsultat attendu utiliser l'extrieur des scnarios de test, pour le prototypage par exemple. Fini
    Intgration d'autres testeurs unitaires La capacit de lire et simuler d'autres scnarios de test en provenance de PHPUnit et de PEAR::Phpunit. Fini
    Scnario de test web Appariement basique de motifs dans une page tlcharge. Fini
    Analyse de page HTML Permet de suivre les liens et de trouver la balise de titre Fini
    Simulacre partiel Simuler des parties d'une classe pour tester moins qu'une classe ou dans des cas complexes. Fini
    Gestion des cookies Web Gestion correcte des cookies au tlchargement d'une page. Fini
    Suivi des redirections Le tlchargement d'une page suit automatiquement une redirection 300. Fini
    Analyse d'un formulaire La capacit de valider un formulaire simple et d'en lire les valeurs par dfaut. Fini
    Interface en ligne de commande Affiche le rsultat des tests sans navigateur web. Fini
    Mise nu des attentes d'une classe Peut crer des tests prcis avec des simulacres ainsi que des scnarios de test. Fini
    Sortie et analyse XML Permet de tester sur plusieurs htes et d'intgrer des extensions d'acceptation de test. Fini
    Scnario de test en ligne de commande Permet de tester des outils ou scripts en ligne de commande et de manier des fichiers. Fini
    Compatibilit avec PHP Documentor Gnration automatique et complte de la documentation au niveau des classes. Fini
    Interface navigateur Mise nu des niveaux bas de l'interface du navigateur web pour des scnarios de test plus prcis. Fini
    Authentification HTTP Tlchargement des pages web protges avec une authentification basique seulement. Fini
    Boutons de navigation d'un navigateur Arrire, avant et recommencer Fini
    Support de SSL Peut se connecter des pages de type https. Fini
    Support de proxy Peut se connecter via des proxys communs Fini
    Support des cadres Gre les cadres dans les scnarios de test web. Fini
    Test de l'upload de fichier Peut simuler la balise input de type file 1.0.1
    Amlioration sur la machinerie des rapports Retouche sur la transmission des messages pour une meilleur coopration avec les IDEs 1.1
    Amlioration de l'affichage des tests Une meilleure interface graphique web, avec un arbre des scnarios de test. 1.1
    Localisation Abstraction des messages et gnration du code partir de fichiers XML. 1.1
    Simulation d'interface Peut gnrer des objets fantaisie tant vers des interfaces que vers des classes. 2.0
    Test sur es exceptions Dans le mme esprit que sur les tests des erreurs PHP. 2.0
    Rercherche d'lments avec XPath Peut utiliser Tidy HTML pour un appariement plus rapide et plus souple. 2.0
    La migration vers PHP5 commencera juste aprs la srie des 1.0, partir de l PHP4 ne sera plus support. SimpleTest est actuellement compatible avec PHP5 mais n'utilisera aucune des nouvelles fonctionnalits avant la version 2.

    Le processus est au moins aussi important que les outils. Le type de procdure que fait un usage le plus intensif des outils de test pour dveloppeur est bien sr l'Extreme Programming. Il s'agit l d'une des mthodes agiles qui combinent plusieurs pratiques pour "lisser la courbe de cot" du dveloppement logiciel. La plus extrme reste le dveloppement pilot par les tests, o vous devez adhrer la rgle du pas de code avant d'avoir un test. Si vous tes plutt du genre planninficateur ou que vous estimez que l'exprience compte plus que l'volution, vous prfrerez peut-tre l'approche RUP. Je ne l'ai pas test mais je peux voir o vous aurez besoin d'outils de test (cf. illustration 9).

    La plupart des testeurs unitaires sont dans une certaine mesure un clone de JUnit, au moins dans l'interface. Il y a normment d'information sur le site de JUnit, commencer par la FAQ quie contient pas mal de conseils gnraux sur les tests. Une fois mordu par le bogue vous apprcierez srement la phrase infect par les tests trouve par Eric Gamma. Si vous tes encore en train de tergiverser sur un testeur unitaire, sachez que les choix principaux sont PHPUnit et Pear PHP::PHPUnit. De nombreuses fonctionnalits de SimpleTest leurs font dfaut, mais la version PEAR a d'ores et dj t mise jour pour PHP5. Elle est aussi recommande si vous portez des scnarios de test existant depuis JUnit.

    Les dveloppeurs de bibliothque n'ont pas l'air de livrer trs souvent des tests avec leur code : c'est bien dommage. Le code d'une bibliothque qui inclut des tests peut tre remani avec plus de scurit et le code de test sert de documentation additionnelle dans un format assez standard. Ceci peut pargner la pche aux indices dans le code source lorsque qu'un problme survient, en particulier lors de la mise jour d'une telle bibliothque. Parmi les bibliothques utilisant SimpleTest comme testeur unitaire on retrouve WACT et PEAR::XML_HTMLSax.

    Au jour d'aujourd'hui il manque tristement beaucoup de matire sur les objets fantaisie : dommage, surtout que tester unitairement sans eux reprsente pas mal de travail en plus. L'article original sur les objets fantaisie est trs orient Java, mais reste intressant lire. Etant donn qu'il s'agit d'une nouvelle technologie il y a beaucoup de discussions et de dbats sur comment les utiliser, souvent sur des wikis comme Extreme Tuesday ou www.mockobjects.comou the original C2 Wiki. Injecter des objets fantaisie dans une classe est un des champs principaux du dbat : cet article chez IBM en est un bon point de dpart.

    Il y a normement d'outils de test web mais la plupart sont crits en Java. De plus les tutoriels et autres conseils sont plutt rares. Votre seul espoir est de regarder directement la documentation pour HTTPUnit, HTMLUnit ou JWebUnit et d'esprer y trouver pour des indices. Il y a aussi des frameworks bass sur XML, mais de nouveau la plupart ont besoin de Java pour tourner.

    Rsum rapide de l'outil SimpleTest pour PHP. La liste des fonctionnalites, la fois prsentes et venir. Il y a beaucoup de ressources sur les tests unitaires sur le web. Documentation pour SimpleTest. Comment crire des scnarios de test en PHP est un tutoriel plutt avanc. L'API de SimpleTest par phpdoc. outils de dveloppement logiciel, programmation php, outils pour l'extreme programming, liens pour des outils de test, ressources pour test en php, objets fantaise, junit, jwebunit, htmlunit, itc, liens pour tests en php, conseil et documentation pour test unitaire, extreme programming en php Marcus Baker Dveloppeur principal{@link mailto:marcus@lastcraft.com marcus@lastcraft.com} Harry Fuecks Packageur{@link mailto:harryf@users.sourceforge.net harryf@users.sourceforge.net} Jason Sweat Documentation{@link mailto:jsweat_php@yahoo.com jsweat_php@yahoo.com} Perrick Penet Traduction{@link mailto:perrick@onpk.net perrick@onpk.net}
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/mock_objects_documentation.xml0000664000175000017620000006711311157271050030575 0ustar davidpalepurple Documentation SimpleTest : les objets fantaise

    Les objets fantaisie - ou "mock objects" en anglais - ont deux rles pendant un scnario de test : acteur et critique.

    Le comportement d'acteur est celui de simuler des objets difficiles initialiser ou trop consommateurs en temps pendant un test. Le cas classique est celui de la connexion une base de donnes. Mettre sur pied une base de donnes de test au lancement de chaque test ralentirait considrablement les tests et en plus exigerait l'installation d'un moteur de base de donnes ainsi que des donnes sur la machine de test. Si nous pouvons simuler la connexion et renvoyer des donnes notre guise alors non seulement nous gagnons en pragmatisme sur les tests mais en sus nous pouvons nourrir notre base avec des donnes falsifies et voir comment il rpond. Nous pouvons simuler une base de donnes en suspens ou d'autres cas extrmes sans avoir crer une vritable panne de base de donnes. En d'autres termes nous pouvons gagner en contrle sur l'environnement de test.

    Si les objets fantaisie ne se comportaient que comme des acteurs alors on les connatrait sous le nom de bouchons serveur.

    Cependant non seulement les objets fantaisie jouent un rle (en fournissant la demande les valeurs requises) mais en plus ils sont aussi sensibles aux messages qui leur sont envoys (par le biais d'attentes). En posant les paramtres attendus d'une mthode ils agissent comme des gardiens : un appel sur eux doit tre ralis correctement. Si les attentes ne sont pas atteintes ils nous pargnent l'effort de l'criture d'une assertion de test avec chec en ralisant cette tche notre place. Dans le cas d'une connexion une base de donnes imaginaire ils peuvent tester si la requte, disons SQL, a bien t form par l'objet qui utilise cette connexion. Mettez-les sur pied avec des attentes assez prcises et vous verrez que vous n'aurez presque plus d'assertion crire manuellement.

    Comme pour la cration des bouchons serveur, tout ce dont nous avons besoin c'est d'un classe existante. La fameuse connexion une base de donnes qui ressemblerait ... class DatabaseConnection { function DatabaseConnection() { } function query() { } function selectQuery() { } } ]]> Cette classe n'a pas encore besoin d'tre implmente. Pour en crer sa version fantaisie nous devons juste inclure la librairie d'objet fantaisie puis lancer le gnrateur... require_once('simpletest/unit_tester.php'); require_once('simpletest/mock_objects.php'); require_once('database_connection.php'); Mock::generate('DatabaseConnection'); ]]> Ceci gnre une classe clone appele MockDatabaseConnection. Nous pouvons dsormais crer des instances de cette nouvelle classe l'intrieur mme de notre scnario de test... class MyTestCase extends UnitTestCase { function testSomething() { $connection = &new MockDatabaseConnection($this); } } ]]> Contrairement aux bouchons, le constructeur d'une classe fantaisie a besoin d'une rfrence au scnario de test pour pouvoir transmettre les succs et les checs pendant qu'il vrifie les attentes. Concrtement a veut dire que les objets fantaisie ne peuvent tre utiliss qu'au sein d'un scnario de test. Malgr tout, cette puissance supplmentaire implique que les bouchons ne sont que rarement utiliss si des objets fantaisie sont disponibles.

    Objets fantaisie en action

    La version fantaisie d'une classe contient toutes les mthodes de l'originale. De la sorte une opration comme query()]]> est encore possible. Tout comme avec les bouchons, nous pouvons remplacer la valeur nulle renvoye par dfaut... $connection->setReturnValue('query', 37); ]]> Dsormais chaque appel de query()]]> nous recevons comme rsultat 37. Tout comme avec les bouchons nous pouvons utiliser des jokers et surcharger le paramtre joker. Nous pouvons aussi ajouter des mthodes supplmentaires l'objet fantaisie lors de sa gnration et lui choisir un nom de classe qui lui soit propre... Mock::generate('DatabaseConnection', 'MyMockDatabaseConnection', array('setOptions')); ]]> Ici l'objet fantaisie se comportera comme si setOptions() existait dans la classe originale. C'est pratique si une classe a utilis le mcanisme overload() de PHP pour ajouter des mthodes dynamiques. Vous pouvez crer des fantaisies spciales pour simuler cette situation.

    Tous les modles disponibles avec les bouchons serveur le sont galement avec les objets fantaisie... Une nouvelle fois, supposons que cet itrateur ne retourne que du texte jusqu'au moment o il atteint son terme, quand il renvoie false. Nous pouvons le simuler avec... $iterator = &new MockIterator($this); $iterator->setReturnValue('next', false); $iterator->setReturnValueAt(0, 'next', 'First string'); $iterator->setReturnValueAt(1, 'next', 'Second string'); ... } } ]]> Au moment du premier appel next() sur l'itrateur fantaisie il renverra tout d'abord "First string", puis ce sera au tour de "Second string" au deuxime appel et ensuite pour tout appel suivant false sera renvoy. Ces valeurs renvoyes successivement sont prioritaires sur la valeur constante retourne. Cette dernire est un genre de valeur par dfaut si vous voulez.

    Reprenons aussi le conteneur d'information bouchonn avec des pairs clef / valeur... Il s'agit l d'une situation classique d'utilisation d'objets fantaisie tant donn que la configuration peut varier grandement de machine machine : a contraint fortement la fiabilit de nos tests si nous l'utilisons directement. Le problme est que toutes les donnes nous parviennent travers la mthode getValue() et que nous voulons des rsultats diffrents pour des clefs diffrentes. Heureusement les objets fantaisie ont un systme de filtrage... $config = &new MockConfiguration($this); $config->setReturnValue('getValue', 'primary', array('db_host')); $config->setReturnValue('getValue', 'admin', array('db_user')); $config->setReturnValue('getValue', 'secret', array('db_password')); ]]> Le paramtre en plus est une liste d'arguments faire correspondre. Dans ce cas nous essayons de faire correspondre un unique argument : en l'occurrence la clef recherche. Maintenant que la mthode getValue() est invoque sur l'objet fantaisie... getValue('db_user') ]]> ...elle renverra "admin". Elle le trouve en essayant de faire correspondre les arguments entrants dans sa liste d'arguments sortants les uns aprs les autres jusqu'au moment o une correspondance exacte est atteinte.

    Il y a des fois o vous souhaitez qu'un objet spcifique soit servi par la fantaisie plutt qu'une copie. De nouveau c'est identique au mcanisme des bouchons serveur... Dans ce cas vous pouvez placer une rfrence dans la liste renvoye par l'objet fantaisie... $vector = &new MockVector($this); $vector->setReturnReference('get', $thing, array(12)); ]]> Avec cet arrangement vous savez qu' chaque appel de get(12)]]> le mme $thing sera renvoy.

    Mme si les bouchons serveur vous isolent du dsordre du monde rel, il ne s'agit l que de la moiti du bnfice potentiel. Vous pouvez avoir une classe de test recevant les messages ad hoc, mais est-ce que votre nouvelle classe renvoie bien les bons ? Le tester peut devenir cafouillis sans une librairie d'objets fantaisie.

    Pour l'exemple, prenons une classe SessionPool laquelle nous allons ajouter une fonction de log. Plutt que de complexifier la classe originale, nous souhaitons ajouter ce comportement avec un dcorateur (GOF). Pour l'instant le code de SessionPool ressemble ... class SessionPool { function SessionPool() { ... } function &findSession($cookie) { ... } ... } class Session { ... } ]]> Alors que pour notre code de log, nous avons... class Log { function Log() { ... } function message() { ... } } class LoggingSessionPool { function LoggingSessionPool(&$session_pool, &$log) { ... } function &findSession(\$cookie) { ... } ... } ]]> Dans tout ceci, la seule classe tester est LoggingSessionPool. En particulier, nous voulons vrifier que la mthode findSession() est appele avec le bon identifiant de session au sein du cookie et qu'elle renvoie bien le message "Starting session $cookie" au loggueur.

    Bien que nous ne testions que quelques lignes de code de production, voici la liste des choses faire dans un scnario de test conventionnel :

    1. Crer un objet de log.
    2. Indiquer le rpertoire d'criture du fichier de log.
    3. Modifier les droits sur le rpertoire pour pouvoir y crire le fichier.
    4. Crer un objet SessionPool.
    5. Lancer une session, ce qui demande probablement pas mal de choses.
    6. Invoquer findSession().
    7. Lire le nouvel identifiant de session (en esprant qu'il existe un accesseur !).
    8. Lever une assertion de test pour vrifier que cet identifiant correspond bien au cookie.
    9. Lire la dernire ligne du fichier de log.
    10. Supprimer avec une (ou plusieurs) expression rationnelle les timestamps de log en trop, etc.
    11. Vrifier que le message de session est bien dans le texte.
    Pas tonnant que les dveloppeurs dtestent crire des tests quand ils sont aussi ingrats. Pour rendre les choses encore pire, chaque fois que le format de log change ou bien que la mthode de cration des sessions change, nous devons rcrire une partie des tests alors mme qu'ils ne testent pas ces parties du systme. Nous sommes en train de prparer le cauchemar pour les dveloppeurs de ces autres classes.

    A la place, voici la mthode complte pour le test avec un peu de magie via les objets fantaisie... $session = &new MockSession($this); $pool = &new MockSessionPool($this); $pool->setReturnReference('findSession', $session); $pool->expectOnce('findSession', array('abc')); $log = &new MockLog($this); $log->expectOnce('message', array('Starting session abc')); $logging_pool = &new LoggingSessionPool($pool, $log); $this->assertReference($logging_pool->findSession('abc'), $session); $pool->tally(); $log->tally(); } } ]]> Commenons par crire une session simulacre. Pas la peine d'tre trop pointilleux avec celle-ci puisque la vrification de la session dsire est effectue ailleurs. Nous avons juste besoin de vrifier qu'il s'agit de la mme que celle qui vient du groupe commun des sessions.

    findSession() est un mthode fabrique dont la simulation est dcrite plus haut. Le point de dpart vient avec le premier appel expectOnce(). Cette ligne indique qu' chaque fois que findSession() est invoqu sur l'objet fantaisie, il vrifiera les arguments entrant. S'il ne reoit que la chane "abc" en tant qu'argument alors un succs est envoy au testeur unitaire, sinon c'est un chec qui est gnr. Il s'agit l de la partie qui teste si nous avons bien la bonne session. La liste des arguments suit une format identique celui qui prcise les valeurs renvoyes. Vous pouvez avoir des jokers et des squences et l'ordre de l'valuation restera le mme.

    Si l'appel n'est jamais effectu alors n'est gnr ni le succs, ni l'chec. Pour contourner cette limitation, nous devons dire l'objet fantaisie que le test est termin : il pourra alors dcider si les attentes ont t rpondues. L'assertion du testeur unitaire de ceci est dclenche par l'appel tally() la fin du test.

    Nous utilisons le mme modle pour mettre sur pied le loggueur fantaisie. Nous lui indiquons que message() devrait tre invoqu une fois et une fois seulement avec l'argument "Starting session abc". En testant les arguments d'appel, plutt que ceux de sortie du loggueur, nous isolons le test de tout modification dans le loggueur.

    Nous commenons le lancement nos tests la cration du nouveau LoggingSessionPool et nous l'alimentons avec nos objets fantaisie juste crs. Dsormais tout est sous contrle. Au final nous confirmons que le $session donn au dcorateur est bien celui reu et prions les objets fantaisie de lancer leurs tests de comptage d'appel interne avec les appels tally().

    Il y a encore pas mal de code de test, mais ce code est trs strict. S'il vous semble encore terrifiant il l'est bien moins que si nous avions essay sans les objets fantaisie et ce test en particulier, interactions plutt que rsultat, est toujours plus difficile mettre en place. Le plus souvent vous aurez besoin de tester des situations plus complexes sans ce niveau ni cette prcision. En outre une partie peut tre remanie avec la mthode de scnario de test setUp().

    Voici la liste complte des attentes que vous pouvez placer sur un objet fantaisie avec SimpleTest...
    AttenteNcessite tally()
    expectArguments($method, $args) Non
    expectArgumentsAt($timing, $method, $args) Non
    expectCallCount($method, $count) Oui
    expectMaximumCallCount($method, $count) Non
    expectMinimumCallCount($method, $count) Oui
    expectNever($method) Non
    expectOnce($method, $args) Oui
    expectAtLeastOnce($method, $args) Oui
    O les paramtres sont...

    $method
    Le nom de la mthode, sous la forme d'une chane, laquelle la condition doit tre applique.
    $args
    Les arguments sous la forme d'une liste. Les jokers peuvent tre inclus de la mme manire qu'avec setReturn(). Cet argument est optionnel pour expectOnce() et expectAtLeastOnce().
    $timing
    Le seul point dans le temps pour tester la condition. Le premier appel commence zro.
    $count
    Le nombre d'appels attendu.
    La mthode expectMaximumCallCount() est lgrement diffrente dans le sens o elle ne pourra gnrer qu'un chec. Elle reste silencieuse si la limite n'est jamais atteinte.

    Comme avec les assertions dans les scnarios de test, toutes ces attentes peuvent accepter une surcharge de message sous la forme d'un paramtre supplmentaire. Par ailleurs le message d'chec original peut tre inclus dans le rsultat avec "%s".

    Il existe trois approches pour crer des objets fantaisie en comprenant celle utilise par SimpleTest. Les coder la main en utilisant une classe de base, les gnrer dans un fichier ou les gnrer dynamiquement la vole.

    Les objets fantaisie gnrs avec SimpleTest sont dynamiques. Ils sont crs l'excution dans la mmoire, grce eval(), plutt qu'crits dans un fichier. Cette opration les rend facile crer, en une seule ligne, surtout par rapport leur cration la main dans une hirarchie de classe parallle. Le problme avec ce comportement tient gnralement dans la mise en place des tests proprement dits. Si les objets originaux changent les versions fantaisie sur lesquels reposent les tests, une dsynchronisation peut subvenir. Cela peut aussi arriver avec l'approche en hirarchie parallle, mais c'est dtect beaucoup plus vite.

    Bien sr, la solution est d'ajouter de vritables tests d'intgration. Vous n'en avez pas besoin de beaucoup et le ct pratique des objets fantaisie fait plus que compenser la petite dose de test supplmentaire. Vous ne pouvez pas avoir confiance dans du code qui ne serait test que par des objets fantaisie.

    Si vous restez dtermin de construire des librairies statiques d'objets fantaisie parce que vous souhaitez muler un comportement trs spcifique, vous pouvez y parvenir grce au gnrateur de classe de SimpleTest. Dans votre fichier librairie, par exemple mocks/connection.php pour une connexion une base de donnes, crer un objet fantaisie et provoquer l'hritage pour hriter pour surcharger des mthodes spciales ou ajouter des prrglages... Mock::generate('Connection', 'BasicMockConnection'); class MockConnection extends BasicMockConnection { function MockConnection(&$test, $wildcard = '*') { $this->BasicMockConnection($test, $wildcard); $this->setReturn('query', false); } } ?> ]]> L'appel generate dit au gnrateur de classe d'en crer une appele BasicMockConnection plutt que la plus courante MockConnection. Ensuite nous hritons partir de celle-ci pour obtenir notre version de MockConnection. En interceptant de cette manire nous pouvons ajouter un comportement, ici transformer la valeur par dfaut de query() en "false". En utilisant le nom par dfaut nous garantissons que le gnrateur de classe fantaisie n'en recrera pas une autre diffrente si il est invoqu ailleurs dans les tests. Il ne crera jamais de classe si elle existe dj. Aussi longtemps que le fichier ci-dessus est inclus avant alors tous les tests qui gnraient MockConnection devraient utiliser notre version prsent. Par contre si nous avons une erreur dans l'ordre et que la librairie de fantaisie en cre une d'abord alors la cration de la classe chouera tout simplement.

    Utiliser cette astuce si vous vous trouvez avec beaucoup de comportement en commun sur les objets fantaisie ou si vous avez de frquents problmes d'intgration plus tard dans les tapes de test.

    Mais au moment d'crire ces lignes c'est le seul grer les objets fantaisie, donc vous tes bloqu avec lui ?

    Non, pas du tout. SimpleTest est une bote outils et parmi ceux-ci on trouve les objets fantaisie qui peuvent tre utiliss indpendamment. Supposons que vous avez votre propre testeur unitaire favori et que tous vos tests actuels l'utilisent. Prtendez que vous avez appel votre tester unitaire PHPUnit (c'est ce que tout le monde a fait) et que la classe principale de test ressemble ... La seule chose que la mthode assertion() ralise, c'est de prparer une sortie embellie alors le paramtre boolien de l'assertion sert dterminer s'il s'agit d'une erreur ou d'un succs. Supposons qu'elle est utilise de la manire suivante... assertion('I hope this file exists', file_exists('my_file')); ]]> Comment utiliser les objets fantaisie avec ceci ?

    Il y a une mthode protge sur la classe de base des objets fantaisie : elle s'appelle _assertTrue(). En surchargeant cette mthode nous pouvons utiliser notre propre format d'assertion. Nous commenons avec une sous-classe, dans my_mock.php... SimpleMock($test, $wildcard); } function _assertTrue($assertion, $message) { $test = &$this->getTest(); $test->assertion($message, $assertion); } } ?> ]]> Maintenant une instance de MyMock crera un objet qui parle le mme langage que votre testeur. Bien sr le truc c'est que nous crons jamais un tel objet : le gnrateur s'en chargera. Nous avons juste besoin d'une ligne de code supplmentaire pour dire au gnrateur d'utiliser vos nouveaux objets fantaisie... SimpleMock(&$test, $wildcard); } function _assertTrue($assertion, $message , &$test) { $test->assertion($message, $assertion); } } SimpleTestOptions::setMockBaseClass('MyMock'); ?> ]]> A partir de maintenant vous avez juste inclure my_mock.php la place de la version par dfaut simple_mock.php et vous pouvez introduire des objets fantaisie dans votre suite de tests existants.

    Que sont les objets fantaisie ? Crer des objets fantaisie. L'objet fantaisie - acteur ou bouchon. L'objet fantaisie - critique avec des attentes. D'autres approches y compris des librairies d'objets fantaisie. Utiliser les objets fantaisie avec d'autres testeurs unitaires. L'article originel sur les objets fantaisie. La page du projet SimpleTest sur SourceForge. La page d'accueil de SimpleTest sur LastCraft. dveloppement logiciel, programmation en php, outils de dveloppement logiciel, tutoriel php, scripts php gratuits, architecture, ressources php, mock objects, objets fantaisie, junit, test php, test unitaire, tester en php
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/group_test_tutorial.xml0000664000175000017620000002162711157271050027320 0ustar davidpalepurple Tutorial de test unitaire PHP - Grouper des tests unitaires et exemples d'criture de scnarios de tests

    Pour enchaner nous allons remplir des blancs et crer une suite de tests.

    Un autre test

    Ajouter un autre test peut tre aussi simple qu'ajouter une nouvelle mthode un scnario de test... UnitTestCase('Log class test'); } function testCreatingNewFile() { @unlink('../temp/test.log'); $log = new Log('../temp/test.log'); $this->assertFalse(file_exists('../temp/test.log'), 'Created before message'); $log->message('Should write this to a file'); $this->assertTrue(file_exists('../temp/test.log'), 'File created'); @unlink('../temp/test.log'); } function testAppendingToFile() { @unlink('../temp/test.log'); $log = new Log('../temp/test.log'); $log->message('Test line 1'); $messages = file('../temp/test.log'); $this->assertWantedPattern('/Test line 1/', $messages[0]); $log->message('Test line 2'); $messages = file('../temp/test.log'); $this->assertWantedPattern('/Test line 2/', $messages[1]); @unlink('../temp/test.log'); } } ]]> La mthode du scnario de test assertWantedPattern() utilise les expressions rationnelles Perl pour vrifier qu'une chane respecte un certain motif.

    Tout ce que nous faisons dans ce nouveau test, c'est crire une ligne dans un fichier, puis la lire, le tout deux fois de suite. Nous souhaitons simplement vrifier que le loggueur ajoute le texte la fin plutt qu'craser les donnes dj existantes. Quelque peu pdant, mais aprs tout il s'agit d'un tutorial !

    De toute faon ce test passe directement...

    Log class test

    1/1 test cases complete. 4 passes and 0 fails.
    Notre code contient actuellement beaucoup de rptitions, nous devons effacer le fichier de test avant et aprs chaque test. De mme que JUnit, SimpleTest utilise les mthodes setUp() et tearDown() qui sont excutes respectivement avant et aprs chaque test. La suppression du fichier est commune tous les tests : nous devrions donc y mettre cette opration.

    Nos tests sont verts donc nous pouvons faire un peu de remaniement... UnitTestCase('Log class test'); } function setUp() { @unlink('../temp/test.log'); } function tearDown() { @unlink('../temp/test.log'); } function testCreatingNewFile() { $log = new Log('../temp/test.log'); $this->assertFalse(file_exists('../temp/test.log'), 'Created before message'); $log->message('Should write this to a file'); $this->assertTrue(file_exists('../temp/test.log'), 'File created'); } function testAppendingToFile() { $log = new Log('../temp/test.log'); $log->message('Test line 1'); $messages = file('../temp/test.log'); $this->assertWantedPattern('/Test line 1/', $messages[0]); $log->message('Test line 2'); $messages = file('../temp/test.log'); $this->assertWantedPattern('/Test line 2/', $messages[1]); } } ]]> Le test reste vert. Nous pouvons continuer ajouter des mthodes sans test au scnario, il suffit que leur nom ne commence pas par la chane "test". Seules les mthodes commenant par "test" sont excutes. Nous pouvons donc continuer le remaniement... UnitTestCase('Log class test'); } function setUp() { @unlink('../temp/test.log'); } function tearDown() { @unlink('../temp/test.log'); } function getFileLine($filename, $index) { $messages = file($filename); return $messages[$index]; } function testCreatingNewFile() { $log = new Log('../temp/test.log'); $this->assertFalse(file_exists('../temp/test.log'), 'Created before message'); $log->message('Should write this to a file'); $this->assertTrue(file_exists('../temp/test.log'), 'File created'); } function testAppendingToFile() { $log = new Log('../temp/test.log'); $log->message('Test line 1'); $this->assertWantedPattern('/Test line 1/', $this->getFileLine('../temp/test.log', 0)); $log->message('Test line 2'); $this->assertWantedPattern('/Test line 2/', $this->getFileLine('../temp/test.log', 1)); } } ]]> Que vous prfriez cette version ou la prcdente ne dpend que de votre got personnel. Il y a un peu plus de code dans cette dernire mais la logique du test est plus claire.

    Un groupe de tests

    Un scnario de test ne fonctionne pas tout seul pendant trs longtemps. Quand on code pour de vrai nous souhaitons excuter un maximum de tests aussi souvent et aussi rapidement que possible. a veut dire les grouper dans des suites de tests qui incluent l'ensemble des tests de l'application.

    Premirement nous devons supprimer le code d'excution des tests se trouvant dans notre scnario de test. require_once('../classes/log.php'); class TestOfLogging extends UnitTestCase { ... } ?> ]]> Nous n'avons plus besoin de la constante SIMPLE_TEST. Ensuite nous crons un groupe de tests appel all_tests.php dans le rpertoire tests... addTestCase(new TestOfLogging()); $test->run(new HtmlReporter()); ?> ]]> Il n'y a presque de pas de diffrence tant que les choses marchent...

    All tests

    1/1 test cases complete. 4 passes and 0 fails.
    Les tests du groupe s'ajoutent au compteur des scnarios de test. Ajouter des nouveaux scnarios de test est trs simple. Il suffit d'inclure le fichier d'un scnario et d'ajouter individuellement tous les scnarios autonomes. Vous pouvez aussi emboter les groupes de test les uns dans les autres (tout en faisant bien attention d'viter les boucles).

    Dans la page suivante nous les ajouterons encore plus rapidement.

    Ajouter un autres test au scnario existant et remanier. La technique brute pour grouper des tests unitaires. Ensuite vient le contrle de comment la classe sous le test interagit avec le reste du systme. Avant il y a la cration du premier test. Vous aurez besoin de SimpleTest pour excuter ces exemples. dveloppement logiciel, programmation php, outils de dveloppement logiciel, tutorial php, scripts php gratuits, pilotage par les tests, architecture, ressouces php, objets fantaisie, junit, test php, test unitaire, phpunit, test unitaire php
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/support_website.xml0000664000175000017620000000240711157271050026433 0ustar davidpalepurple Mailing-list de support

    La mailing-list simpletest-support est probablement l'endroit le plus actif autour de SimpleTest : aide, conseil, bugs et détours, c'est là que tout se passe la plupart du temps. Attention tout de même : les échanges ont lieu en anglais.

    C'est vraiment simple de s'y abonner et en plus, on peut aussi l'utiliser pour ses recherches.

    Au dernier pointage, il y avait 114 abonnés et 1908 messages envoyés. Cela fait de 1 à 4 messages par jour en moyenne.

    SimpleTest, download, source code, stable release, eclipse release, eclipse plugin, debian package, drupal module, pear channel, pearified package
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/reporter_documentation.xml0000664000175000017620000004574411157271050030003 0ustar davidpalepurple Documentation SimpleTest : le rapporteur de test

    SimpleTest suit plutt plus que moins le modle MVC (Modle-Vue-Contrleur). Les classes "reporter" sont les vues et les modles sont vos scnarios de test et leur hirarchie. Le contrleur est le plus souvent masqu l'utilisateur de SimpleTest moins de vouloir changer la faon dont les tests sont effectivement excuts, auquel cas il est possible de surcharger les objets "runner" (ceux de l'excuteur) depuis l'intrieur d'un scnario de test. Comme d'habitude avec MVC, le contrleur est plutt indfini et il existe d'autres endroits pour contrler l'excution des tests.

    L'affichage par dfaut est minimal l'extrme. Il renvoie le succs ou l'chec avec les barres conventionnelles - rouge et verte - et affichent une trace d'arborescence des groupes de test pour chaque assertion errone. Voici un tel chec...

    File test

    Fail: createnewfile->True assertion failed.
    1/1 test cases complete. 0 passes, 1 fails and 0 exceptions.
    Alors qu'ici tous les tests passent...

    File test

    1/1 test cases complete. 1 passes, 0 fails and 0 exceptions.
    La bonne nouvelle, c'est qu'il existe pas mal de points dans la hirarchie de l'affichage pour crer des sous-classes.

    Pour l'affichage bas sur des pages web, il y a la classe HtmlReporter avec la signature suivante... Voici ce que certaines de ces mthodes veulent dire. Premirement les mthodes d'affichage que vous voudrez probablement surcharger...

    • HtmlReporter(string $encoding)
      est le constructeur. Notez que le test unitaire initie le lien l'affichage plutt que l'oppos. L'affichage est principalement un receveur passif des vnements de tests. Cela permet d'adapter facilement l'affichage pour d'autres systmes en dehors des tests unitaires, tel le suivi de la charge de serveurs. L'"encoding" est le type d'encodage que vous souhaitez utiliser pour l'affichage du test. Pour pouvoir effectuer un rendu correct de la sortie de dbogage quand on utilise le testeur web, il doit correspondre l'encodage du site test. Les chanes de caractres disponibles sont indiques dans la fonction PHP html_entities().
    • void paintHeader(string $test_name)
      est appel une fois, au dbut du test quand l'vnement de dmarrage survient. Le premier vnement de dmarrage est souvent dlivr par le groupe de tests du niveau le plus haut et donc c'est de l que le $test_name arrive. Il peint les titres de la page, CSS, la balise "body", etc. Il ne renvoie rien du tout (void).
    • void paintFooter(string $test_name)
      est appel la toute fin du test pour fermer les balises ouvertes par l'entte de la page. Par dfaut il affiche aussi la barre rouge ou verte et le dcompte final des rsultats. En fait la fin des tests arrive quand l'vnement de fin de test arrive avec le mme nom que celui qui l'a initi au mme niveau. Le nid des tests en quelque sorte. Fermer le dernier test finit l'affichage.
    • void paintMethodStart(string $test_name)
      est appel au dbut de chaque mthode de test. Normalement le nom vient de celui de la mthode. Les autres vnements de dpart de test se comportent de la mme manire sauf que celui du groupe de tests indique au rapporteur le nombre de scnarios de test qu'il contient. De la sorte le rapporteur peut afficher une barre de progrs au fur et mesure que l'excuteur passe en revue les scnarios de test.
    • void paintMethodEnd(string $test_name)
      clt le test lanc avec le mme nom.
    • void paintFail(string $message)
      peint un chec. Par dfaut il ne fait qu'afficher le mot "fail", une trace d'arborescence affichant la position du test en cours et le message transmis par l'assertion.
    • void paintPass(string $message)
      ne fait rien, par dfaut.
    • string _getCss()
      renvoie les styles CSS sous la forme d'une chane l'attention de la mthode d'enttes d'une page. Des styles additionnels peuvent tre ajouts ici si vous ne surchargez pas les enttes de la page. Vous ne voudrez pas utiliser cette mthode dans des enttes d'une page surcharge si vous souhaitez inclure le feuille de style CSS d'origine.
    Il y a aussi des accesseurs pour aller chercher l'information sur l'tat courant de la suite de test. Vous les utiliserez pour enrichir l'affichage...
    • array getTestList()
      est la premire mthode trs commode pour les sous-classes. Elle liste l'arborescence courante des tests sous la forme d'une liste de noms de tests. Le premier test -- celui le plus proche du coeur -- sera le premier dans la liste et la mthode de test en cours sera la dernire.
    • integer getPassCount()
      renvoie le nombre de succs atteint. Il est ncessaire pour l'affichage la fin.
    • integer getFailCount()
      renvoie de la mme manire le nombre d'checs.
    • integer getExceptionCount()
      renvoie quant lui le nombre d'erreurs.
    • integer getTestCaseCount()
      est le nombre total de scnarios lors de l'excution des tests. Il comprend aussi les tests groups.
    • integer getTestCaseProgress()
      est le nombre de scnarios raliss jusqu' prsent.
    Une modification simple : demander l'HtmlReporter d'afficher aussi bien les succs que les checs et les erreurs... class ShowPasses extends HtmlReporter { function paintPass($message) { parent::paintPass($message); print "&Pass: "; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); print implode("->", $breadcrumb); print "->$message
    \n"; } function _getCss() { return parent::_getCss() . ' .pass { color: green; }'; } } ]]>

    Une mthode qui a beaucoup fait jaser reste la mthode makeDry(). Si vous lancez cette mthode, sans paramtre, sur le rapporteur avant que la suite de test ne soit excute alors aucune mthode de test ne sera appele. Vous continuerez avoir les vnements entrants et sortants des mthodes et scnarios de test, mais aucun succs ni chec ou erreur, parce que le code de test ne sera pas excut.

    La raison ? Pour permettre un affichage complexe d'une IHM (ou GUI) qui permettrait la slection de scnarios de test individuels. Afin de construire une liste de tests possibles, ils ont besoin d'un rapport sur la structure du test pour l'affichage, par exemple, d'une vue en arbre de la suite de test. Avec un rapporteur lanc sur une excution sche qui ne renverrait que les vnements d'affichage, cela devient facilement ralisable.

    Plutt que de modifier l'affichage existant, vous voudrez peut-tre produire une prsentation HTML compltement diffrente, ou mme gnrer une version texte ou XML. Plutt que de surcharger chaque mthode dans HtmlReporter nous pouvons nous rendre une tape plus haut dans la hirarchie de classe vers SimpleReporter dans le fichier source simple_test.php.

    Un affichage sans rien, un canevas vierge pour votre propre cration, serait... require_once('simpletest/simple_test.php'); class MyDisplay extends SimpleReporter { function paintHeader($test_name) { } function paintFooter($test_name) { } function paintStart($test_name, $size) { parent::paintStart($test_name, $size); } function paintEnd($test_name, $size) { parent::paintEnd($test_name, $size); } function paintPass($message) { parent::paintPass($message); } function paintFail($message) { parent::paintFail($message); } } ]]> Aucune sortie ne viendrait de cette classe jusqu' un ajout de votre part.

    SimpleTest est aussi livr avec un rapporteur en ligne de commande, minime lui aussi. L'interface imite celle de JUnit, sauf qu'elle envoie les messages d'erreur au fur et mesure de leur arrive. Pour utiliser le rapporteur en ligne de commande, il suffit de l'intervertir avec celui de la version HTML... addTestFile('tests/file_test.php'); $test->run(new TextReporter()); ?> ]]> Et ensuite d'invoquer la suite de test partir d'une ligne de commande...

    php file_test.php
    
    Bien sr vous aurez besoin d'installer PHP en ligne de commande. Une suite de test qui passerait toutes ses assertions ressemble ...
    File test
    OK
    Test cases run: 1/1, Failures: 0, Exceptions: 0
    
    Un chec dclenche un affichage comme...
    File test
    1) True assertion failed.
    	in createnewfile
    FAILURES!!!
    Test cases run: 1/1, Failures: 1, Exceptions: 0
    

    Une des principales raisons pour utiliser une suite de test en ligne de commande tient dans l'utilisation possible du testeur avec un processus automatis. Pour fonctionner comme il faut dans des scripts shell le script de test devrait renvoyer un code de sortie non-nul suite un chec. Si une suite de test choue la valeur false est renvoye par la mthode SimpleTest::run(). Nous pouvons utiliser ce rsultat pour terminer le script avec la bonne valeur renvoye... addTestFile('tests/file_test.php'); exit ($test->run(new TextReporter()) ? 0 : 1); ?> ]]> Bien sr l'objectif n'est pas de crer deux scripts de test, l'un en ligne de commande et l'autre pour un navigateur web, pour chaque suite de test. Le rapporteur en ligne de commande inclut une mthode pour dterminer l'environnement d'excution... addTestFile('tests/file_test.php'); if (TextReporter::inCli()) { exit ($test->run(new TextReporter()) ? 0 : 1); } $test->run(new HtmlReporter()); ?> ]]> Il s'agit l de la forme utilise par SimpleTest lui-mme.

    SimpleTest est livr avec une classe XmlReporter utilise pour de la communication interne. Lors de son excution, le rsultat ressemble ...

    
    
      
        Remote tests
        
          Visual test with 48 passes, 48 fails and 4 exceptions
          
            testofunittestcaseoutput
            
              testofresults
              This assertion passed
              This assertion failed
            
            
              ...
            
          
        
      
    
    ]]>
    Vous pouvez utiliser ce format avec le parseur fourni dans SimpleTest lui-mme. Il s'agit de SimpleTestXmlParser et se trouve xml.php l'intrieur du paquet SimpleTest... parse($test_output); ?> ]]> $test_output devrait tre au format XML, partir du rapporteur XML, et pourrait venir d'une excution en ligne de commande d'un scnario de test. Le parseur envoie des vnements au rapporteur exactement comme tout autre excution de test. Il y a des occasions bizarres dans lesquelles c'est en fait trs utile.

    Un problme des trs grandes suites de test , c'est qu'elles peuvent venir bout de la limite de mmoire par dfaut d'un process PHP - 8Mb. En plaant la sortie des groupes de test dans du XML et leur excution dans des process diffrents, le rsultat peut tre pars nouveau pour agrger les rsultats avec moins d'impact sur le test au premier niveau.

    Parce que la sortie XML peut venir de n'importe o, a ouvre des possibilits d'agrgation d'excutions de test depuis des serveur distants. Un scnario de test pour le raliser existe dj l'intrieur du framework SimpleTest, mais il est encore exprimental... require_once('../remote.php'); require_once('../reporter.php'); $test_url = ...; $dry_url = ...; $test = &new GroupTest('Remote tests'); $test->addTestCase(new RemoteTestCase($test_url, $dry_url)); $test->run(new HtmlReporter()); ?> ]]> RemoteTestCase prend la localisation relle du lanceur de test, tout simplement un page web au format XML. Il prend aussi l'URL d'un rapporteur initi pour effectuer une excution sche. Cette technique est employe pour que les progrs soient correctement rapports vers le haut. RemoteTestCase peut tre ajout une suite de test comme n'importe quel autre groupe de tests.

    Afficher les rsultats en HTML Afficher et rapporter les rsultats dans d'autres formats Utilis SimpleTest depuis la ligne de commande Utiliser XML pour des tests distants La page du projet SimpleTest sur SourceForge. La page de tlchargement de SimpleTest sur LastCraft. L'API pour dveloppeur de SimpleTest donne tous les dtails sur les classes et les assertions disponibles. test unitaire en php, documentation, marcus baker, perrick penet test simple, simpletest, test distant, tests xml, test automatis
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/intro.xml0000664000175000017620000000371011157271050024326 0ustar davidpalepurple Les articles de :: onpk :: sur php / simpletest : traductions en franais des articles publis sur Lastcraft.com

    Le testeur unitaire SimpleTest PHP a enfin atteint la dlicate version 1.0 : il est disponible au tlchargement chez votre SourceForge le plus proche.

    Il s'agit d'un testeur unitaire PHP et aussi d'un testeur web. Il est construit pour tre extensible de plusieurs manires. Les utilisateurs de JUnit seront familiers avec la plupart des interfaces. L'affichage des tests est largement modifiable tout comme le scnario de test de base. Par ailleurs les objets fantaisie peuvent tre utiliss avec d'autres testeurs unitaires.

    Les fonctionnalits -la-JWebUnit sont plus compltes aussi. Il y a le support pour SSL, les fentres, les proxies, l'authentification simple et un large choix de contrles HTML. L'ide est que les tches fastidieuses en PHP, se connecter un site par exemple, puissent tre testes facilement.

    dveloppement logiciel, programmation php, outils de dveloppement logiciel, tutorial php, scripts php gratuits, conseil de test, architecture logicielle pour des tests, exemple de code php, junit, test php, outil de test unitaire, suite de test php Des articles (documentations et tutoriels) pour dcouvrir le dveloppement agile en PHP avec le framework de tests unitaires SimpleTest.
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/display_subclass_tutorial.xml0000664000175000017620000002615311157271050030470 0ustar davidpalepurple Tutorial de test unitaire en PHP - Sous-classer l'affichage du test

    Le composant affichage de SimpleTest est en fait la dernire partie dvelopper. Des morceaux de la section suivante changeront prochainement et -- avec optimisme -- des composants d'affichage plus sophistiqus seront crits, mais pour l'instant si un affichage minime n'est pas suffisant, voici comment raliser le votre.

    Je veux voir les succs !

    Bon d'accord, voici comment.

    Nous devons crer une sous-classe de l'affichage utilise, dans notre cas il s'agit de HtmlReporter. La classe HtmlReporter est situ dans le fichier simpletest/reporter.php : pour l'instant elle a l'interface suivante... Voici ce que les mthodes pertinentes veulent dire. Vous pouvez consulter la liste complte ici si cela vous intresse.

    • HtmlReporter()
      est le constructeur. Notez qu'un test unitaire initie le lien vers l'affichage plutt que l'inverse. L'affichage est un rceptacle passif des vnements de test. Cela permet une adaptation facile de l'affichage pour d'autres systmes de test en dehors des tests unitaires comme la surveillance de serveurs par exemple. Autre avantage, un test unitaire peut crire vers plus d'un affichage la fois.
    • void paintFail(string $message)
      peint un chec. Voir ci-dessous.
    • void paintPass(string \$message)
      ne fait rien par dfaut. C'est cette mthode que nous allons modifier.
    • string _getCss()
      renvoie le style CSS - via une chane - pour la mthode d'entte de la page. Des styles complmentaires peuvent tre ajouts ici.
    • array getTestList()
      est une mthode commode pour des sous-classes. Elle liste l'embotement courant des tests via une liste de noms de test. Le premier, le test embot le plus profondment, est le premier dans la liste et la mthode du test courant sera la dernire.

    Pour afficher les succs nous avons juste besoin que la mthode paintPass() se comporte comme paintFail(). Bien sr nous n'allons pas modifier l'original. Nous allons juste crer une sous-classe.

    Une sous-classe d'affichage

    Premirement nous allons crer un fichier tests/show_passes.php dans notre projet de log et y placer cette classe vide... HtmlReporter(); } } ?> ]]> Une rapide mais attentive lecture du code de SimpleTest indique que l'implmentation de paintFail() ressemble ... Fail: "; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); print implode("->", $breadcrumb); print "->$message
    \n"; } ]]>
    Essentiellement elle s'enchane la version du parent, que nous devons aussi raliser pour garantir le mnage, et ensuite imprime une trace calcule partir de la liste des tests courants. Par contre elle perd au passage le nom du test du premier niveau. Etant donn qu'il est identique pour chaque test, ce serait un peu trop d'informations. En la transposant dans notre nouvelle classe... HtmlReporter(); } function paintPass($message) { parent::paintPass($message); print "Pass: "; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); print implode("->", $breadcrumb); print "->$message
    \n"; }
    } ]]>
    Pour l'instant tout roule. Maintenant pour utiliser notre nouvelle classe, nous allons modifier notre fichier tests/all_tests.php... require_once('show_passes.php'); $test = &new GroupTest('All tests'); $test->addTestFile('log_test.php'); $test->addTestFile('clock_test.php'); $test->run(new ShowPasses()); ?> ]]> Nous pouvons le lancer pour voir le rsultat de notre bricolage...

    All tests

    Pass: log_test.php->Log class test->testappendingtofile->Expecting [/Test line 1/] in [Test line 1]
    Pass: log_test.php->Log class test->testappendingtofile->Expecting [/Test line 2/] in [Test line 2]
    Pass: log_test.php->Log class test->testcreatingnewfile->Created before message
    Pass: log_test.php->Log class test->testcreatingnewfile->File created
    Pass: clock_test.php->Clock class test->testclockadvance->Advancement
    Pass: clock_test.php->Clock class test->testclocktellstime->Now is the right time
    3/3 test cases complete. 6 passes and 0 fails.
    Joli, mais pas encore digne d'une mdaille d'or. Nous avons perdu un peu d'information au passage. L'affichage du span.pass n'est pas styl en CSS, mais nous pouvons l'ajouter en modifiant une autre mthode... HtmlReporter(); } function paintPass($message) { parent::paintPass($message); print "Pass: "; $breadcrumb = $this->getTestList(); array_shift($breadcrumb); print implode("->", $breadcrumb); print "->$message
    \n"; } function _getCss() { return parent::_getCss() . ' .pass { color: green; }'; } } ]]>
    Si vous ajoutez le code au fur et mesure, vous verrez l'ajout du style dans le code source du rsultat via le navigateur. A l'oeil, l'affichage devrait ressembler ...

    All tests

    Pass: log_test.php->Log class test->testappendingtofile->Expecting [/Test line 1/] in [Test line 1]
    Pass: log_test.php->Log class test->testappendingtofile->Expecting [/Test line 2/] in [Test line 2]
    Pass: log_test.php->Log class test->testcreatingnewfile->Created before message
    Pass: log_test.php->Log class test->testcreatingnewfile->File created
    Pass: clock_test.php->Clock class test->testclockadvance->Advancement
    Pass: clock_test.php->Clock class test->testclocktellstime->Now is the right time
    3/3 test cases complete. 6 passes and 0 fails.
    Certains prfrent voir les succs quand ils travaillent sur le code; le sentiment de travail achev est sympathique aprs tout. Une fois que vous commencez naviguer de haut en bas pour trouver les erreurs, assez vite vous en comprendrez le ct obscur.

    Essayez les deux mthodes pour dterminer votre prfrence. Nous allons le laisser tel que pour l'tape qui approche : les objets fantaisie. Il s'agit du premier outil de test qui ajoute des tests additionnels : il sera utile de voir ce qui se passe dans les coulisses.

    Comment changer l'affichage pour afficher les passages avec succs. Sous classer la classe HtmlReporter. La section prcdente : sous-classer les scnarios de test Cette section est trs spcifique SimpleTest. Si vous utilisez un autre outil, n'hsitez pas sauter pardessus. dveloppement logiciel pilot par les tests, conseil pour programmer en php, programmation php, outils de dveloppement logiciel, tutorial php, scripts php gratuits, architecture, exemple de scnario de test, framework de tests unitaires, ressources php, exemple de code php, junit, phpunit, simpletest, test php, outil de test unitaire, suite de test php
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/simple_test.xml0000664000175000017620000004307511157271050025533 0ustar davidpalepurple Prise en main rapide de SimpleTest pour PHP - Tests unitaire et objets fantaisie pour PHP

    Le prsent article prsuppose que vous soyez familier avec le concept de tests unitaires ainsi que celui de dveloppement web avec le langage PHP. Il s'agit d'un guide pour le nouvel et impatient utilisateur de SimpleTest. Pour une documentation plus complte, particulirement si vous dcouvrez les tests unitaires, consultez la documentation en cours, et pour des exemples de scnarios de test, consultez le tutorial sur les tests unitaires.

    Parmi les outils de test pour logiciel, le testeur unitaire est le plus proche du dveloppeur. Dans un contexte de dveloppement agile, le code de test se place juste ct du code source tant donn que tous les deux sont crits simultanment. Dans ce contexte, SimpleTest aspire tre une solution complte de test pour un dveloppeur PHP et s'appelle "Simple" parce qu'elle devrait tre simple utiliser et tendre. Ce nom n'tait pas vraiment un bon choix. Non seulement cette solution inclut toutes les fonctions classiques qu'on est en droit d'attendre de la part des portages de JUnit et des PHPUnit, mais elle inclut aussi les objets fantaisie ou "mock objects". Sans compter quelques fonctionnalits de JWebUnit : parmi celles-ci la navigation sur des pages web, les tests sur les cookies et l'envoi de formulaire.

    La dmonstration la plus rapide : l'exemple

    Supposons que nous sommes en train de tester une simple classe de log dans un fichier : elle s'appelle Log dans classes/Log.php. Commenons par crer un script de test, appel tests/log_test.php. Son contenu est le suivant... ]]> Ici le rpertoire simpletest est soit dans le dossier courant, soit dans les dossiers pour fichiers inclus. Vous auriez diter ces arborescences suivant l'endroit o vous avez install SimpleTest. Ensuite crons un scnario de test... class TestOfLogging extends UnitTestCase { } ?> ]]> A prsent il y a 5 lignes de code d'chafaudage et toujours pas de test. Cependant partir de cet instant le retour sur investissement arrive trs rapidement. Supposons que la classe Log prenne le nom du fichier crire dans le constructeur et que nous ayons un rpertoire temporaire dans lequel placer ce fichier... function testCreatingNewFile() { @unlink('/temp/test.log'); $log = new Log('/temp/test.log'); $this->assertFalse(file_exists('/temp/test.log')); $log->message('Should write this to a file'); $this->assertTrue(file_exists('/temp/test.log')); } } ?> ]]> Au lancement du scnario de test, toutes les mthodes qui commencent avec la chane test sont identifies puis excutes. D'ordinaire nous avons bien plusieurs mthodes de tests. Les assertions dans les mthodes de test envoient des messages vers le framework de test qui affiche immdiatement le rsultat. Cette rponse immdiate est importante, non seulement lors d'un crash caus par le code, mais aussi de manire rapprocher l'affichage de l'erreur au plus prs du scnario de test concern.

    Pour voir ces rsultats lanons effectivement les tests. S'il s'agit de l'unique scnario de test lancer, on peut y arriver avec... assertFalse(file_exists('/temp/test.log')); $log->message('Should write this to a file'); $this->assertTrue(file_exists('/temp/test.log')); } } $test = &new TestOfLogging(); $test->run(new HtmlReporter()); ?> ]]>

    En cas chec, l'affichage ressemble ...

    testoflogging

    Fail: testcreatingnewfile->True assertion failed.
    1/1 test cases complete. 1 passes and 1 fails.
    ...et si a passe, on obtient...

    testoflogging

    1/1 test cases complete. 2 passes and 0 fails.
    Et si vous obtenez a...
    Fatal error: Failed opening required '../classes/log.php' (include_path='') in /home/marcus/projects/lastcraft/tutorial_tests/Log/tests/log_test.php on line 7
    c'est qu'il vous manque le fichier classes/Log.php qui pourrait ressembler : ; ]]>

    Il est peu probable que dans une vritable application on ait uniquement besoin de passer un seul scnario de test. Cela veut dire que nous avons besoin de grouper les scnarios dans un script de test qui peut, si ncessaire, lancer tous les tests de l'application.

    Notre premire tape est de supprimer les includes et de dfaire notre hack prcdent... require_once('../classes/log.php'); class TestOfLogging extends UnitTestCase { function testCreatingNewFile() { @unlink('/temp/test.log'); $log = new Log('/temp/test.log'); $this->assertFalse(file_exists('/temp/test.log')); $log->message('Should write this to a file'); $this->assertTrue(file_exists('/temp/test.log')); } } ?> ]]> Ensuite nous crons un nouveau fichier appel tests/all_tests.php. On y insre le code suivant... addTestFile('log_test.php'); $test->run(new HtmlReporter()); ?> ]]> Cette mthode GroupTest::addTestFile() va inclure le fichier de scnarios de test et lire parmi toutes les nouvelles classes cres celles qui sont issues de TestCase. Dans un premier temps, seuls les noms sont stocks, de la sorte le lanceur de test peut instancier la classe au fur et mesure qu'il excute votre suite de tests.

    Pour que a puisse marcher proprement le fichier de suite de tests ne devrait pas inclure aveuglement d'autres extensions de scnarios de test qui n'excuteraient pas effectivement de test. Le rsultat pourrait tre que des tests supplmentaires soient alors comptabiliss pendant l'excution des tests. Ce n'est pas un problme grave mais pour viter ce dsagrment, il suffit d'ajouter la commande SimpleTestOptions::ignore() quelque part dans le fichier de scnario de test. Par ailleurs le scnario de test ne devrait pas avoir t inclus ailleurs ou alors aucun scnario ne sera ajout aux groupes de test. Il s'agirait l d'une erreur autrement srieuse : si toutes les classes de scnario de test sont charges par PHP, alors la mthode GroupTest::addTestFile() ne pourra pas les dtecter.

    Pour afficher les rsultats, il est seulement ncessaire d'invoquer tests/all_tests.php partir du serveur web.

    Avanons un peu plus dans le futur.

    Supposons que notre class logging soit teste et termine. Supposons aussi que nous testons une autre classe qui ait besoin d'crire des messages de log, disons SessionPool. Nous voulons tester une mthode qui ressemblera probablement quelque chose comme... class SessionPool { ... function logIn($username) { ... $this->_log->message('User $username logged in.'); ... } ... } ]]> Avec le concept de "rutilisation de code" comme fil conducteur, nous utilisons notre class Log. Un scnario de test classique ressemblera peut-tre ... logIn('fred'); $messages = file('/temp/test.log'); $this->assertEqual($messages[0], "User fred logged in.\n"); } } ?> ]]> Le design de ce scnario de test n'est pas compltement mauvais, mais on peut l'amliorer. Nous passons du temps tripoter les fichiers de log qui ne font pas partie de notre test. Pire, nous avons cr des liens de proximit entre la classe Log et ce test. Que se passerait-il si nous n'utilisions plus de fichiers, mais la bibliothque syslog la place ? Avez-vous remarqu le retour chariot supplmentaire la fin du message ? A-t-il t ajout par le loggueur ? Et si il ajoutait aussi un timestamp ou d'autres donnes ?

    L'unique partie tester rellement est l'envoi d'un message prcis au loggueur. Nous rduisons le couplage en crant une fausse classe de logging : elle ne fait qu'enregistrer le message pour le test, mais ne produit aucun rsultat. Sauf qu'elle doit ressembler exactement l'original.

    Si l'objet fantaisie n'crit pas dans un fichier alors nous nous pargnons la suppression du fichier avant et aprs le test. Nous pourrions mme nous pargner quelques lignes de code supplmentaires si l'objet fantaisie pouvait excuter l'assertion.

    Trop beau pour tre vrai ? Par chance on peut crer un tel objet trs facilement... Mock::generate('Log'); class TestOfSessionLogging extends UnitTestCase { function testLogInIsLogged() { $log = &new MockLog($this); $log->expectOnce('message', array('User fred logged in.')); $session_pool = &new SessionPool($log); $session_pool->logIn('fred'); $log->tally(); } } ?> ]]> L'appel tally() est ncessaire pour annoncer l'objet fantaisie qu'il n'y aura plus d'appels ultrieurs. Sans a l'objet fantaisie pourrait attendre pendant une ternit l'appel de la mthode sans jamais prvenir le scnario de test. Les autres tests sont dclenchs automatiquement quand l'appel message() est invoqu sur l'objet MockLog. L'appel mock va dclencher une comparaison des paramtres et ensuite envoyer le message "pass" ou "fail" au test pour l'affichage. Des jokers peuvent tre inclus ici aussi afin d'empcher que les tests ne deviennent trop spcifiques.

    Les objets fantaisie dans la suite SimpleTest peuvent avoir un ensemble de valeurs de sortie arbitraires, des squences de sorties, des valeurs de sortie slectionnes partir des arguments d'entre, des squences de paramtres attendus et des limites sur le nombre de fois qu'une mthode peut tre invoque.

    Pour que ce test fonctionne la librairie avec les objets fantaisie doit tre incluse dans la suite de tests, par exemple dans all_tests.php.

    Une des exigences des sites web, c'est qu'ils produisent des pages web. Si vous construisez un projet de A Z et que vous voulez intgrer des tests au fur et mesure alors vous voulez un outil qui puisse effectuer une navigation automatique et en examiner le rsultat. C'est le boulot d'un testeur web.

    Effectuer un test web via SimpleTest reste assez primitif : il n'y a pas de javascript par exemple. Pour vous donner une ide, voici un exemple assez trivial : aller chercher une page web, partir de l naviguer vers la page "about" et finalement tester un contenu dtermin par le client. require_once('simpletest/web_tester.php'); require_once('simpletest/reporter.php'); class TestOfAbout extends WebTestCase { function setUp() { $this->get('http://test-server/index.php'); $this->clickLink('About'); } function testSearchEngineOptimisations() { $this->assertTitle('A long title about us for search engines'); $this->assertWantedPattern('/a popular keyphrase/i'); } } $test = &new TestOfAbout(); $test->run(new HtmlReporter()); ?> ]]> Avec ce code comme test de recette, vous pouvez vous assurer que le contenu corresponde toujours aux spcifications la fois des dveloppeurs et des autres parties prenantes au projet.

    SourceForge.net Logo

    Utiliser le testeur rapidement avec un exemple. Groupes de tests pour tester en un seul clic. Utiliser les objets fantaisie pour faciliter les tests et gagner en contrle. Tester des pages web au niveau de l'HTML. Tlcharger PHP Simple Test depuis SourceForge. L'API de SimpleTest pour dveloppeur donne tous les dtails sur les classes et assertions existantes. dveloppement logiciel, programmation php, outils de dveloppement logiciel, tutorial php, scripts php gratuits, architecture, ressources php, objets fantaise, junit, php testing, php unit, mthodologie, dveloppement pilot par les tests, sourceforge, open source, unit test, web tester, web testing, outils tests html, tester des web pages, php objets fantaise, naviguer automatiquement sur des sites web, test automatis, scripting web, wget, test curl, jmock pour php, jwebunit, phpunit, php unit testing, php web testing, jason sweat, marcus baker, perrick penet, topstyle plug in, phpedit plug in
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/group_test_documentation.xml0000664000175000017620000002707211157271050030326 0ustar davidpalepurple Documentation SimpleTest : Grouper des tests

    Pour lancer les scnarios de tests en tant que groupe, ils devraient tre placs dans des fichiers sans le code du lanceur... ]]> Autant de scnarios que ncessaires peuvent tre mis dans un fichier unique. Ils doivent contenir tout le code ncessaire, entre autres la bibliothque teste, mais aucune des bibliothques de SimpleTest.

    Si vous avez tendu l'un ou l'autre des scnarios de test, vous pouvez aussi les inclure. class MyFileTestCase extends UnitTestCase { ... } SimpleTestOptions::ignore('MyFileTestCase'); class FileTester extends MyFileTestCase { ... } class SocketTester extends UnitTestCase { ... } ?> ]]> La classe FileTester ne contient aucun test vritable, il s'agit d'une classe de base pour d'autres scnarios de test. Pour cette raison nous utilisons la directive SimpleTestOptions::ignore() pour indiquer au prochain groupe de tests de l'ignorer. Cette directive peut se placer n'importe o dans le fichier et fonctionne quand un fichier complet des scnarios de test est charg (cf. ci-dessous). Nous l'appelons file_test.php.

    Ensuite nous crons un fichier de groupe de tests, disons group_test.php. Vous penserez un nom plus convaincant, j'en suis sr. Nous lui ajoutons le fichier de test avec une mthode sans risque... require_once('file_test.php'); $test = &new GroupTest('All file tests'); $test->addTestCase(new FileTestCase()); $test->run(new HtmlReporter()); ?> ]]> Ceci instancie le scnario de test avant que la suite de test ne soit lance. a pourrait devenir assez onreux avec un grand nombre de scnarios de test : il existe donc une autre mthode qui instancie la classe uniquement quand elle devient ncessaire... $test->addTestClass('FileTestCase'); $test->run(new HtmlReporter()); ?> ]]> Le problme de cette technique est que pour chaque scnario de test supplmentaire nous aurons importer (via require_once()) le fichier de code de test et instancier manuellement chaque scnario de test. Nous pouvons nous pargner beaucoup de dactylographie avec... $test->addTestFile('file_test.php'); $test->run(new HtmlReporter()); ?> ]]> Voici ce qui vient de se passer : la classe GroupTest a ralis le require_once() pour nous. Ensuite elle vrifie si de nouvelles classes de scnario de test ont t cres par ce nouveau fichier et les ajoute automatiquement au groupe de tests. Dsormais tout ce qu'il nous reste faire, c'est d'ajouter chaque nouveau fichier.

    Il y a deux choses qui peuvent planter et qui demandent un minimum d'attention...

    1. Le fichier peut dj avoir t analys par PHP et dans ce cas aucune classe ne sera ajoute. Pensez bien vrifier que les scnarios de test ne sont inclus que dans ce fichier et dans aucun autre.
    2. Les nouvelles classes d'extension de scnario de test qui sont incluses seront places dans le groupe de tests et excutes par la mme occasion. Vous aurez ajouter une directive SimpleTestOptions::ignore() pour ces classes ou alors pensez les ajouter avant la ligne GroupTest::addTestFile().

    La technique ci-dessus place tous les scnarios de test dans un unique et grand groupe. Sauf que pour des projets plus consquents, ce n'est probablement pas assez souple ; vous voudriez peut-tre grouper les tests tout fait diffremment.

    Pour obtenir un groupe de tests plus souple nous pouvons sous classer GroupTest et ensuite l'instancier au cas par cas... class FileGroupTest extends GroupTest { function FileGroupTest() { $this->GroupTest('All file tests'); $this->addTestFile('file_test.php'); } } ?> ]]> Ceci nomme le test dans le constructeur et ensuite ajoute la fois nos scnarios de test et un unique groupe en dessous. Bien sr nous pouvons ajouter plus d'un groupe cet instant. Nous pouvons maintenant invoquer les tests partir d'un autre fichier d'excution... $test = &new FileGroupTest(); $test->run(new HtmlReporter()); ?> ]]> ...ou alors nous pouvons les grouper dans un groupe de tests encore plus grand... $test = &new BigGroupTest('Big group'); $test->addTestCase(new FileGroupTest()); $test->addTestCase(...); $test->run(new HtmlReporter()); ?> ]]> Si nous souhaitons lancer le groupe de tests original sans utiliser ses petits fichiers d'excution, nous pouvons mettre le code du lanceur de test derrire des barreaux quand nous crons chaque groupe. GroupTest('All file tests'); $test->addTestFile('file_test.php'); } } if (! defined('RUNNER')) { define('RUNNER', true); $test = &new FileGroupTest(); $test->run(new HtmlReporter()); } ?> ]]> Cette approche exige aux barrires d'tre actives l'inclusion du fichier de groupe de tests, mais c'est quand mme moins de tracas que beaucoup de fichiers de lancement parpills. Reste inclure des barreaux identiques au niveau suprieur afin de s'assurer que le run() ne sera lanc qu'une seule fois partir du script de haut niveau qui l'a invoqu. addTestCase(new FileGroupTest()); $test->addTestCase(...); $test->run(new HtmlReporter()); ?> ]]> Comme les scnarios de test normaux, un GroupTest peut tre charg avec la mthode GroupTest::addTestFile(). $test->addTestFile('file_group_test.php'); $test->addTestFile(...); $test->run(new HtmlReporter()); ?> ]]>

    Si vous avez dj des tests unitaires pour votre code ou alors si vous tendez des classes externes qui ont dj leurs propres tests, il y a peu de chances pour que ceux-ci soient dj au format SimpleTest. Heureusement il est possible d'incorporer ces scnarios de test en provenance d'autres testeurs unitaires directement dans des groupes de test SimpleTest.

    Par exemple, supposons que nous ayons ce scnario de test prvu pour PhpUnit dans le fichier config_test.php... class ConfigFileTest extends TestCase { function ConfigFileTest() { $this->TestCase('Config file test'); } function testContents() { $config = new ConfigFile('test.conf'); $this->assertRegexp('/me/', $config->getValue('username')); } } ]]> Le groupe de tests peut le reconnatre partir du moment o nous mettons l'adaptateur appropri avant d'ajouter le fichier de test... require_once('simpletest/adapters/phpunit_test_case.php'); $test = &new GroupTest('All file tests'); $test->addTestFile('config_test.php'); $test->run(new HtmlReporter()); ?> ]]> Il n'y a que deux adaptateurs, l'autre est pour le paquet testeur unitaire de PEAR... require_once('simpletest/adapters/pear_test_case.php'); $test = &new GroupTest('All file tests'); $test->addTestFile('some_pear_test_cases.php'); $test->run(new HtmlReporter()); ?> ]]> Les scnarios de test de PEAR peuvent tre librement mlangs avec ceux de SimpleTest mais vous ne pouvez pas utiliser les assertions de SimpleTest au sein des versions hrites des scnarios de test. La raison ? Une simple vrification que vous ne rendez pas par accident vos scnarios de test compltement dpendants de SimpleTest. Peut-tre que vous souhaitez publier votre bibliothque sur PEAR par exemple : a voudrait dire la livrer avec des scnarios de test compatibles avec PEAR::PhpUnit.

    Plusieurs approches pour grouper des tests ensemble. Combiner des groupes des tests dans des groupes plus grands. Intgrer des scnarios de test hrits d'un autre type de PHPUnit. La page du projet SimpleTest sur SourceForge. La page de tlchargement de SimpleTest sur LastCraft. test unitaire en php, intgration de test, documentation, marcus baker, perrick penet, test simple, documentation simpletest, phpunit, pear
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/authentication_documentation.xml0000664000175000017620000002643111157271050031150 0ustar davidpalepurple Documentation Simple Test : tester l'authentification

    Un des secteurs la fois dlicat et important lors d'un test de site web reste la scurit. Tester ces schmas est au coeur des objectifs du testeur web de SimpleTest.

    Si vous allez chercher une page web protge par une authentification basique, vous hriterez d'une entte 401. Nous pouvons reprsenter ceci par ce test... function test401Header() { $this->get('http://www.lastcraft.com/protected/'); $this->showHeaders(); } } ]]> Ce qui nous permet de voir les enttes reues...

    File test

    1/1 test cases complete. 0 passes, 0 fails and 0 exceptions.
    Sauf que nous voulons viter l'inspection visuelle, on souhaite que SimpleTest puisse nous dire si oui ou non la page est protge. Voici un test en profondeur sur nos enttes... get('http://www.lastcraft.com/protected/'); $this->assertAuthentication('Basic'); $this->assertResponse(401); $this->assertRealm('SimpleTest basic authentication'); } } ]]> N'importe laquelle de ces assertions suffirait, tout dpend de la masse de dtails que vous souhaitez voir.

    La plupart du temps, nous ne souhaitons pas tester l'authentification en elle-mme, mais plutt les pages protges par cette authentification. Ds que la tentative d'authentification est reue, nous pouvons y rpondre l'aide d'une rponse d'authentification : get('http://www.lastcraft.com/protected/'); $this->authenticate('Me', 'Secret'); $this->assertTitle(...); } } ]]> Le nom d'utilisateur et le mot de passe seront dsormais envoys chaque requte vers ce rpertoire et ses sous rpertoires. En revanche vous devrez vous authentifier nouveau si vous sortez de ce rpertoire.

    Vous pouvez gagner une ligne en dfinissant l'authentification au niveau de l'URL... get('http://Me:Secret@www.lastcraft.com/protected/'); $this->assertTitle(...); } } ]]> Si votre nom d'utilisateur ou mot de passe comporte des caractres spciaux, alors n'oubliez pas de les encoder, sinon la requte ne sera pas analyse correctement. De plus cette entte ne sera pas envoye aux sous requtes si vous la dfinissez avec une URL absolue. Par contre si vous naviguez avec des URL relatives, l'information d'authentification sera prserve.

    Pour l'instant, seule l'authentification de base est implmente et elle n'est rellement fiable qu'en tandem avec une connexion HTTPS. C'est gnralement suffisant pour protger le serveur test des regards malveillants. Les authentifications Digest et NTLM pourraient tre ajoutes prochainement.

    L'authentification de base ne donne pas assez de contrle au dveloppeur Web sur l'interface utilisateur. Il y a de forte chance pour que cette fonctionnalit soit code directement dans l'architecture web grand renfort de cookies et de timeouts compliqus.

    Commenons par un simple formulaire de connexion...

    
        Username:
        
    Password:
    ]]>
    Lequel doit ressembler ...

    Username:
    Password:

    Supposons que, durant le chargement de la page, un cookie ait t inscrit avec un numro d'identifiant de session. Nous n'allons pas encore remplir le formulaire, juste tester que nous pistons bien l'utilisateur. Voici le test... get('http://www.my-site.com/login.php'); $this->assertCookie('SID'); } } ]]> Nous nous contentons ici de vrifier que le cookie a bien t dfini. Etant donn que sa valeur est plutt nigmatique, elle ne vaut pas la peine d'tre teste.

    Le reste du test est le mme que dans n'importe quel autre formulaire, mais nous pourrions souhaiter nous assurer que le cookie n'a pas t modifi depuis la phase de connexion. Voici comment cela pourrait tre test : get('http://www.my-site.com/login.php'); $session = $this->getCookie('SID'); $this->setField('u', 'Me'); $this->setField('p', 'Secret'); $this->clickSubmit('Log in'); $this->assertWantedPattern('/Welcome Me/'); $this->assertCookie('SID', $session); } } ]]> Ceci confirme que l'identifiant de session est identique avant et aprs la connexion.

    Nous pouvons mme essayer de duper notre propre systme en crant un cookie arbitraire pour se connecter... get('http://www.my-site.com/login.php'); $this->setCookie('SID', 'Some other session'); $this->get('http://www.my-site.com/restricted.php'); $this->assertWantedPattern('/Access denied/'); } } ]]> Votre site est-il protg contre ce type d'attaque ?

    Si vous testez un systme d'authentification, la reconnexion par un utilisateur est un point sensible. Essayons de simuler ce qui se passe dans ce cas : get('http://www.my-site.com/login.php'); $this->setField('u', 'Me'); $this->setField('p', 'Secret'); $this->clickSubmit('Log in'); $this->assertWantedPattern('/Welcome Me/'); $this->restart(); $this->get('http://www.my-site.com/restricted.php'); $this->assertWantedPattern('/Access denied/'); } } ]]> La mthode WebTestCase::restart() prserve les cookies dont le timeout a expir, mais conserve les cookies temporaires ou expirs. Vous pouvez spcifier l'heure et la date de leur ractivation.

    L'expiration des cookies peut tre un problme. Si vous avez un cookie qui doit expirer au bout d'une heure, nous n'allons pas mettre le test en veille en attendant que le cookie expire...

    Afin de provoquer leur expiration, vous pouvez dater manuellement les cookies, avant le dbut de la session. get('http://www.my-site.com/login.php'); $this->setField('u', 'Me'); $this->setField('p', 'Secret'); $this->clickSubmit('Log in'); $this->assertWantedPattern('/Welcome Me/'); $this->ageCookies(3600); $this->restart(); $this->get('http://www.my-site.com/restricted.php'); $this->assertWantedPattern('/Access denied/'); } } ]]> Aprs le redmarrage, les cookies seront plus vieux d'une heure et que tous ceux dont la date d'expiration sera passe auront disparus.

    Passer au travers d'une authentification HTTP basique Tester l'authentification base sur des cookies Grer les sessions du navigateur et les timeouts La page du projet SimpleTest sur SourceForge. La page de tlchargement de SimpleTest sur LastCraft. L'API du dveloppeur pour SimpleTest donne tous les dtails sur les classes et les assertions disponibles. dveloppement logiciel, programmation php, php orient client, outils de dveloppement logiciel, tutorial php, scripts php gratuits, architecture, ressources php, objets fantaise, php testing, php unit, mthodologie, dveloppement pilot par les tests, outils tests html, tester des web pages, php objets fantaise, naviguer automatiquement sur des sites web, test automatis, scripting web, HTMLUnit, JWebUnit, phpunit, php unit testing, php web testing, test unitaire de systme d'authentification, authentification HTTP, test de connexion, test d'authentification, test de scurit
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/first_test_tutorial.xml0000664000175000017620000004727411157271050027321 0ustar davidpalepurple Tutorial sur les tests unitaires en PHP - Crer un exemple de scnario de test en PHP

    Si vous dbutez avec les tests unitaires, il est recommand d'essayer le code au fur et mesure. Il n'y pas grand chose taper et vous sentirez le rythme de la programmation pilote par les tests.

    Pour excuter les exemples tels quels, vous aurez besoin de crer un nouveau rpertoire et d'y installer trois dossiers : classes, tests et temp. Dzippez le framework SimpleTest dans le dossier tests et assurez vous que votre serveur web puisse atteindre ces endroits.

    Un nouveau scnario de test

    L'exemple dans l'introduction rapide comprenait les tests unitaires d'une simple classe de log. Dans ce tutorial propos de Simple Test, je vais essayer de raconter toute l'histoire du dveloppement de cette classe. Cette classe PHP est courte et simple : au cours de cette introduction, elle recevra beaucoup plus d'attention que dans le cadre d'un dveloppement de production. Nous verrons que derrire son apparente simplicit se cachent des choix de conception tonnamment difficiles.

    Peut-tre que ces choix sont trop difficiles ? Plutt que d'essayer de penser tout en amont, je vais commencer par poser une exigence : nous voulons crire des messages dans un fichier. Ces messages doivent tre ajouts en fin de fichier s'il existe. Plus tard nous aurons besoin de priorits, de filtres et d'autres choses encore, mais nous plaons l'criture dans un fichier au coeur de nos proccupations. Nous ne penserons rien d'autres par peur de confusion. OK, commenons par crire un test... UnitTestCase(); } function testCreatingNewFile() { } } $test = &new TestOfLogging(); $test->run(new HtmlReporter()); ?> ]]> Pas pas, voici ce qu'il veut dire.

    La constante SIMPLE_TEST contient le chemin vers les classes de Simple Test partir de ce fichier. Les classes pourraient tre places dans le path du fichier php.ini mais si vous tes sur un serveur mutualis, vous n'y aurez probablement pas accs. Pour que tout le monde soit content, le chemin est dclar explicitement dans le script de test. Plus tard nous verrons comment tout finira au mme endroit.

    Demander la librairie unit_tester.php est assez vident mais qu'est-ce que ce fichier reporter.php ? Les librairies Simple Test sont une bote outils pour crer votre propre suite de tests standardiss. Elles peuvent tre utilises "telles quelles" sans problme, mais elles sont constitues de plusieurs lments qui ont besoin d'tre assembls les uns aux autres. Le composant pour l'affichage est situ dans reporter.php. Probablement qu'un jour vous crirez le vtre : c'est pourquoi son inclusion est optionnelle. Simple Test contient une classe d'affichage, fonctionnelle mais basique : elle s'appelle HtmlReporter. Elle peut enregistrer des informations sur les tests : dbut, fin, erreur, russite ou chec. Elle affiche cette information le plus rapidement possible au cas o le code de test planterait et masquerait le lieu de l'chec.

    Les tests eux-mmes sont rassembls dans une classe de scnario de test. Cette dernire est typiquement une extension de la classe UnitTestCase. Quand le test est excut, elle cherche les mthodes commenant par "test" et les lancent. Notre seule mthode de test pour l'instant est appelle testCreatingNewFile() mais elle est encore vide.

    Une mthode vide ne fait rien. Nous avons besoin d'y placer du code. La classe UnitTestCase gnre des vnements de test son excution : ces vnements sont envoys vers un observateur. La mthode UnitTestCase::run() lancent tous les tests de la classe.

    Et pour ajouter du code de test... require_once('../classes/log.php'); class TestOfLogging extends UnitTestCase { function TestOfLogging() { $this->UnitTestCase(); } function testCreatingNewFile() { @unlink('../temp/test.log'); $log = new Log('../temp/test.log'); $log->message('Should write this to a file'); $this->assertTrue(file_exists('../temp/test.log')); } } $test = &new TestOfLogging(); $test->run(new HtmlReporter()); ?> ]]>

    Vous pensez probablement que a reprsente beaucoup de code pour un unique test et je suis d'accord avec vous. Ne vous inquitez pas. Il s'agit d'un cot fixe et partir de maintenant nous pouvons ajouter des tests : une ligne ou presque chaque fois. Parfois moins en utilisant des artefacts de test que nous dcouvrirons plus tard.

    Nous devons maintenant prendre nos premires dcisions. Notre fichier de test s'appelle log_test.php (n'importe quel nom ferait l'affaire) : nous le plaons dans un dossier appel tests (partout ailleurs serait aussi bien). Notre fichier de code s'appelle log.php : c'est son contenu que nous allons tester. Je l'ai plac dans notre dossier classes : cela veut-il dire que nous construisons une classe ?

    Pour cet exemple, la rponse est oui, mais le testeur unitaire n'est pas restreint aux tests de classe. C'est juste que le code orient objet est plus facile dpecer et remodeler. Ce n'est pas par hasard si la conduite de tests fins via les tests unitaires est apparue au sein de la communaut OO.

    Le test en lui-mme est minimal. Tout d'abord il limine tout autre fichier de test qui serait encore prsent. Les dcisions de conception arrivent ensuite en rafale. Notre classe s'appelle Log : elle passe le chemin du fichier au constructeur. Nous crons le log et nous lui envoyons aussitt un message en utilisant la mthode message(). L'originalit dans le nommage n'est pas une caractristique dsirable chez un dveloppeur informatique : c'est triste mais c'est comme a.

    La plus petite unit d'un test mmm... heu... unitaire est l'assertion. Ici nous voulons nous assurer que le fichier log auquel nous venons d'envoyer un message a bel et bien t cr. UnitTestCase::assertTrue() enverra un vnement russite si la condition value est vraie ou un chec dans le cas contraire. Nous pouvons avoir un ensemble d'assertions diffrentes et encore plus si nous tendons nos scnarios de test classique. Voici la liste...
    assertTrue($x)Echoue si $x est faux
    assertFalse($x)Echoue si $x est vrai
    assertNull($x)Echoue si $x est initialis
    assertNotNull($x)Echoue si $x n'est pas initialis
    assertIsA($x, $t)Echoue si $x n'est pas de la classe ou du type $t
    assertEqual($x, $y)Echoue si $x == $y est faux
    assertNotEqual($x, $y)Echoue si $x == $y est vrai
    assertIdentical($x, $y)Echoue si $x === $y est faux
    assertNotIdentical($x, $y)Echoue si $x === $y est vrai
    assertReference($x, $y)Echoue sauf si $x et $y sont la mme variable
    assertCopy($x, $y)Echoue si $x et $y sont la mme variable
    assertWantedPattern($p, $x)Echoue sauf si l'expression rationnelle $p capture $x
    assertNoUnwantedPattern($p, $x)Echoue si l'expression rationnelle $p capture $x
    assertNoErrors()Echoue si une erreur PHP arrive
    assertError($x)Echoue si aucune erreur ou message incorrect de PHP n'arrive

    Nous sommes dsormais prt lancer notre script de test en le passant dans le navigateur. Qu'est-ce qui devrait arriver ? Il devrait planter...

    Fatal error: Failed opening required '../classes/log.php' (include_path='') in /home/marcus/projects/lastcraft/tutorial_tests/Log/tests/log_test.php on line 7
    La raison ? Nous n'avons pas encore cr log.php.

    Mais attendez une minute, c'est idiot ! Ne me dites pas qu'il faut crer un test sans crire le code tester auparavant...

    Dveloppement pilot par les tests

    Co-inventeur de l'Extreme Programming, Kent Beck a lanc un autre manifeste. Le livre est appel Test Driven Development (Dveloppement Pilot par les Tests) ou TDD et lve les tests unitaires une position leve de la conception. En quelques mots, vous crivez d'abord un petit test et seulement ensuite le code qui passe ce test. N'importe quel bout de code. Juste pour qu'il passe.

    Vous crivez un autre test et puis de nouveau du code qui passe. Vous aurez alors un peu de duplication et gnralement du code pas trs propre. Vous remaniez (factorisez) ce code-l en vous assurant que les tests continuent passer : vous ne pouvez rien casser. Une fois que le code est le plus propre possible vous tes prt ajouter des nouvelles fonctionnalits. Il suffit juste de rajouter des nouveaux tests et de recommencer le cycle une nouvelle fois.

    Il s'agit d'une approche assez radicale et j'ai parfois l'impression qu'elle est incomplte. Mais il s'agit d'un moyen efficace pour expliquer un testeur unitaire ! Il se trouve que nous avons un test qui choue, pour ne pas dire qu'il plante : l'heure est venue d'crire du code dans log.php... ]]> Il s'agit l du minimum que nous puissions faire pour viter une erreur fatale de PHP. Et maintenant la rponse devient...

    testoflogging

    Fail: testcreatingnewfile->True assertion failed.
    1/1 test cases complete. 0 passes and 1 fails.
    "testoflogging" a chou. Parmi les dfauts de PHP on trouve cette fcheuse tendance transformer intrieurement les noms de classes et de mthodes en minuscules. SimpleTest utilise ces noms par dfaut pour dcrire les tests mais nous pouvons les remplacer par nos propres noms. $this->UnitTestCase('Log class test'); } function testCreatingNewFile() { @unlink('../temp/test.log'); $log = new Log('../temp/test.log'); $log->message('Should write this to a file'); $this->assertTrue(file_exists('../temp/test.log'), 'File created'); } } ]]> Ce qui donne...

    Log class test

    Fail: testcreatingnewfile->File created.
    1/1 test cases complete. 0 passes and 1 fails.
    Par contre pour le nom des mthodes il n'y a rien faire, dsol.

    Les messages d'un test comme ceux-ci ressemblent bien des gards des commentaires de code. Certains ne jurent que par eux, d'autres au contraire les bannissent purement et simplement en les considrant aussi encombrants qu'inutiles. Pour ma part, je me situe quelque part au milieu.

    Pour que le test passe, nous pourrions nous contenter de crer le fichier dans le constructeur de Log. Cette technique "en faisant semblant" est trs utile pour vrifier que le test fonctionne pendant les passages difficiles. Elle le devient encore plus si vous sortez d'un passage avec des tests ayant chous et que vous voulez juste vrifier de ne pas avoir oubli un truc bte. Nous n'allons pas aussi lentement donc... var $_file_path; function Log($file_path) { $this->_file_path = $file_path; } function message($message) { $file = fopen($this->_file_path, 'a'); fwrite($file, $message . "\n"); fclose($file); } } ?> ]]> Au total, pas moins de 4 checs ont t ncessaire pour passer l'tape suivante. Je n'avais pas cr le rpertoire temporaire, je ne lui avais pas donn les droits d'criture, j'avais une coquille et je n'avais pas non plus ajout ce nouveau rpertoire dans CVS. N'importe laquelle de ces erreurs aurait pu m'occuper pendant plusieurs heures si elle tait apparue plus tard mais c'est bien pour ces cas l qu'on teste. Avec les corrections adquates, a donne...

    Log class test

    1/1 test cases complete. 1 passes and 0 fails.
    a marche!

    Peut-tre n'aimez-vous pas le style plutt minimal de l'affichage. Les succs ne sont pas montrs par dfaut puisque gnralement vous n'avez pas besoin de plus d'information quand vous comprenez effectivement ce qui se passe. Dans le cas contraire, pensez crire d'autres tests.

    D'accord, c'est assez strict. Si vous voulez aussi voir les succs alors vous pouvez crer une sous-classe de HtmlReporter et l'utiliser pour les tests. Mme moi j'aime bien ce confort parfois.

    Les tests comme documentation

    Il y a une nuance ici. Nous ne voulons pas crer de fichier avant d'avoir effectivement envoy de message. Plutt que d'y rflchir trop longtemps, nous allons juste ajouter un test pour a. UnitTestCase('Log class test'); } function testCreatingNewFile() { @unlink('../temp/test.log'); $log = new Log('../temp/test.log'); $this->assertFalse(file_exists('../temp/test.log'), 'No file created before first message'); $log->message('Should write this to a file'); $this->assertTrue(file_exists('../temp/test.log'), 'File created'); } } ]]> ...et dcouvrir que a marche dj...

    Log class test

    1/1 test cases complete. 2 passes and 0 fails.
    En fait je savais que a allait tre le cas. J'ajoute ce test de confirmation tout d'abord pour garder l'esprit tranquille, mais aussi pour documenter ce comportement. Ce petit test supplmentaire dans son contexte en dit plus long qu'un scnario utilisateur d'une douzaine de lignes ou qu'un diagramme UML complet. Que la suite de tests devienne une source de documentation est un effet secondaire assez agrable.

    Devrions-nous supprimer le fichier temporaire la fin du test ? Par habitude, je le fais une fois que j'en ai termin avec la mthode de test et qu'elle marche. Je n'ai pas envie de valider du code qui laisse des restes de fichiers de test traner aprs un test. Mais je ne le fais pas non plus pendant que j'cris le code. Peut-tre devrais-je, mais parfois j'ai besoin de voir ce qui se passe : on retrouve cet aspect confort voqu plus haut.

    Dans un vritable projet, nous avons habituellement plus qu'un unique scnario de test : c'est pourquoi nous allons regarder comment grouper des tests dans des suites de tests.

    Crer un nouveau scnario de test. Le Dveloppement Pilot par les Tests en PHP. Les tests comme documentation est un des nombreux effets secondaires. La FAQ de JUnit contient plein de conseils judicieux sur les tests. Ensuite vient "comment grouper des scnarios de tests ensemble". Vous aurez besoin du framework de test SimpleTest pour ces exemples. dveloppement logiciel, programmation php, outils de dveloppement logiciel, tutorial php, scripts php gratuits, architecture, ressouces php, objets fantaisie, junit, test php, test unitaire, test php automatis, tutorial de scnarios de test, explication d'un scnario de test unitaire, exemple de test unitaire
    postfixadmin-2.3.7/tests/simpletest/docs/source/fr/expectation_documentation.xml0000664000175000017620000003071411157271050030453 0ustar davidpalepurple Documentation SimpleTest : tendre le testeur unitaire avec des classes d'attentes supplmentaires

    Le comportement par dfaut des objets fantaisie dans SimpleTest est soit une correspondance identique sur l'argument, soit l'acceptation de n'importe quel argument. Pour la plupart des tests, c'est suffisant. Cependant il est parfois ncessaire de ramollir un scnario de test.

    Un des endroits o un test peut tre trop serr est la reconnaissance textuelle. Prenons l'exemple d'un composant qui produirait un message d'erreur utile lorsque quelque chose plante. Il serait utile de tester que l'erreur correcte est renvoye, mais le texte proprement dit risque d'tre plutt long. Si vous testez le texte dans son ensemble alors chaque modification de ce mme message -- mme un point ou une virgule -- vous aurez revenir sur la suite de test pour la modifier.

    Voici un cas concret, nous avons un service d'actualits qui a chou dans sa tentative de connexion sa source distante. class NewsService { ... function publish(&$writer) { if (! $this->isConnected()) { $writer->write('Cannot connect to news service "' . $this->_name . '" at this time. ' . 'Please try again later.'); } ... } } ]]> L il envoie son contenu vers un classe Writer. Nous pourrions tester ce comportement avec un MockWriter... $writer = &new MockWriter($this); $writer->expectOnce('write', array( 'Cannot connect to news service ' . '"BBC News" at this time. ' . 'Please try again later.')); $service = &new NewsService('BBC News'); $service->publish($writer); $writer->tally(); } } ]]> C'est un bon exemple d'un test fragile. Si nous dcidons d'ajouter des instructions complmentaires, par exemple proposer une source d'actualits alternative, nous casserons nos tests par la mme occasion sans pourtant avoir modifi une seule fonctionnalit.

    Pour contourner ce problme, nous voudrions utiliser un test avec une expression rationnelle plutt qu'une correspondance exacte. Nous pouvons y parvenir avec... $writer->expectOnce( 'write', array(new WantedPatternExpectation('/cannot connect/i'))); $service = &new NewsService('BBC News'); $service->publish($writer); $writer->tally(); } } ]]> Plutt que de transmettre le paramtre attendu au MockWriter, nous envoyons une classe d'attente appele WantedPatternExpectation. L'objet fantaisie est suffisamment lgant pour reconnatre qu'il s'agit d'un truc spcial et pour le traiter diffremment. Plutt que de comparer l'argument entrant cet objet, il utilise l'objet attente lui-mme pour excuter le test.

    WantedPatternExpectation utilise l'expression rationnelle pour la comparaison avec son constructeur. A chaque fois qu'une comparaison est fait travers MockWriter par rapport cette classe attente, elle fera un preg_match() avec ce motif. Dans notre scnario de test ci-dessus, aussi longtemps que la chane "cannot connect" apparat dans le texte, la fantaisie transmettra un succs au testeur unitaire. Peu importe le reste du texte.

    Les classes attente possibles sont...
    EqualExpectationUne galit, plutt que la plus forte comparaison l'identique
    NotEqualExpectationUne comparaison sur la non-galit
    IndenticalExpectationLa vrification par dfaut de l'objet fantaisie qui doit correspondre exactement
    NotIndenticalExpectationInverse la logique de l'objet fantaisie
    WantedPatternExpectationUtilise une expression rationnelle Perl pour comparer une chane
    NoUnwantedPatternExpectationPasse seulement si l'expression rationnelle Perl choue
    IsAExpectationVrifie le type ou le nom de la classe uniquement
    NotAExpectationL'oppos de IsAExpectation
    MethodExistsExpectationVrifie si la mthode est disponible sur un objet
    La plupart utilisent la valeur attendue dans le constructeur. Les exceptions sont les vrifications sur motif, qui utilisent une expression rationnelle, ainsi que IsAExpectation et NotAExpectation, qui prennent un type ou un nom de classe comme chane.

    Les classes attente peuvent servir autre chose que l'envoi d'assertions depuis les objets fantaisie, afin de choisir le comportement d'un objet fantaisie ou celui d'un bouchon serveur. A chaque fois qu'une liste d'arguments est donne, une liste d'objets d'attente peut tre insre la place.

    Mettons que nous voulons qu'un bouchon serveur d'autorisation simule une connexion russie seulement si il reoit un objet de session valide. Nous pouvons y arriver avec ce qui suit... $authorisation = new StubAuthorisation(); $authorisation->setReturnValue( 'isAllowed', true, array(new IsAExpectation('Session', 'Must be a session'))); $authorisation->setReturnValue('isAllowed', false); ]]> Le comportement par dfaut du bouchon serveur est dfini pour renvoyer false quand isAllowed est appel. Lorsque nous appelons cette mthode avec un unique paramtre qui est un objet Session, il renverra true. Nous avons aussi ajout un deuxime paramtre comme message. Il sera affich dans le message d'erreur de l'objet fantaisie si l'attente est la cause de l'chec.

    Ce niveau de sophistication est rarement utile : il n'est inclut que pour tre complet.

    Les classes d'attentes ont une structure trs simple. Tellement simple qu'il devient trs simple de crer vos propres version de logique pour des tests utiliss couramment.

    Par exemple voici la cration d'une classe pour tester la validit d'adresses IP. Pour fonctionner correctement avec les bouchons serveurs et les objets fantaisie, cette nouvelle classe d'attente devrait tendre SimpleExpectation... class ValidIp extends SimpleExpectation { function test($ip) { return (ip2long($ip) != -1); } function testMessage($ip) { return "Address [$ip] should be a valid IP address"; } } ]]> Il n'y a vritablement que deux mthodes mettre en place. La mthode test() devrait renvoyer un true si l'attente doit passer, et une erreur false dans le cas contraire. La mthode testMessage() ne devrait renvoyer que du texte utile la comprhension du test en lui-mme.

    Cette classe peut dsormais tre employe la place des classes d'attente prcdentes.

    Le framework de test unitaire SimpleTest utilise aussi dans son coeur des classes d'attente pour la classe UnitTestCase. Nous pouvons aussi tirer parti de ces mcanismes pour rutiliser nos propres classes attente l'intrieur mme des suites de test.

    La mthode la plus directe est d'utiliser la mthode SimpleTest::assertExpectation() pour effectuer le test... class TestOfNetworking extends UnitTestCase { ... function testGetValidIp() { $server = &new Server(); $this->assertExpectation( new ValidIp(), $server->getIp(), 'Server IP address->%s'); } } ]]> C'est plutt sale par rapport notre syntaxe habituelle du type assert...().

    Pour un cas aussi simple, nous crons d'ordinaire une mthode d'assertion distincte en utilisant la classe d'attente. Supposons un instant que notre attente soit un peu plus complique et que par consquent nous souhaitions la rutiliser, nous obtenons... function assertValidIp($ip, $message = '%s') { $this->assertExpectation(new ValidIp(), $ip, $message); } function testGetValidIp() { $server = &new Server(); $this->assertValidIp( $server->getIp(), 'Server IP address->%s'); } } ]]> Il est peu probable que nous ayons besoin de ce niveau de contrle sur la machinerie de test. Il est assez rare que le besoin d'une attente dpasse le stade de la reconnaissance d'un motif. De plus, les classes d'attente complexes peuvent rendre les tests difficiles lire et dboguer. Ces mcanismes sont vritablement l pour les auteurs de systme qui tendront le framework de test pour leurs propres outils de test.

    Utiliser les attentes pour des tests plus prcis avec des objets fantaisie Changer le comportement d'un objet fantaisie avec des attentes Crer des attentes Par dessous SimpleTest utilise des classes d'attente La page du projet SimpleTest sur SourceForge. La page de tlchargement de SimpleTest sur LastCraft. Les attentes imitent les contraintes dans JMock. L'API complte pour SimpleTest ralis avec PHPDoc. objets fantaisie, dveloppement pilot par les tests, hritage des attentes, contraintes d'objet fantaisie, test unitaire avanc en PHP, test en premier, architecture de framework de test
    postfixadmin-2.3.7/tests/simpletest/docs/lastcraft/0000775000175000017620000000000012301477470022532 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/docs/lastcraft/README0000664000175000017620000000007311157271050023404 0ustar davidpalepurpleOutput folder for Lastcraft site versions of documentation.postfixadmin-2.3.7/tests/simpletest/docs/fr/0000775000175000017620000000000012301477470021156 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/docs/fr/docs.css0000664000175000017620000000260611157271050022616 0ustar davidpalepurplebody { padding-left: 3%; padding-right: 3%; } pre { font-family: courier; font-size: 80%; border: 1px solid; background-color: #cccccc; padding: 5px; margin-left: 5%; margin-right: 8%; } .code, .new_code, pre.new_code { font-weight: bold; } div.copyright { font-size: 80%; color: gray; } div.copyright a { color: gray; } ul.api { padding-left: 0em; padding-right: 25%; } ul.api li { margin-top: 0.2em; margin-bottom: 0.2em; list-style: none; text-indent: -3em; padding-left: 3em; } div.demo { border: 4px ridge; border-color: gray; padding: 10px; margin: 5px; margin-left: 20px; margin-right: 40px; background-color: white; } div.demo span.fail { color: red; } div.demo span.pass { color: green; } div.demo h1 { font-size: 12pt; text-align: left; font-weight: bold; } table { border: 2px outset; border-color: gray; background-color: white; margin: 5px; margin-left: 5%; margin-right: 5%; } td { font-size: 80%; } .shell { color: white; } pre.shell { border: 4px ridge; border-color: gray; padding: 10px; margin: 5px; margin-left: 20px; margin-right: 40px; background-color: black; } form.demo { background-color: lightgray; border: 4px outset; border-color: lightgray; padding: 10px; margin-right: 40%; } postfixadmin-2.3.7/tests/simpletest/docs/simpletest.org/0000775000175000017620000000000012301477470023526 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/docs/simpletest.org/simpletest.css0000664000175000017620000000232111157271050026421 0ustar davidpalepurple/* SimpleTest - Unit Testing for PHP */ body { font-family : georgia, serif; } img { border : 0; } h1 { color : #009933; } blockquote { background: transparent url('images/quote.png') left top no-repeat; font-style : italic; padding-left : 40px; margin-left : 10px; } #logo { margin-bottom : 20px; } #credits { margin-top : 40px; } #actions { position : absolute; top : 20px; left : 40px; width : 335px; } #actions div { width : 305px; } #content { position : absolute; top : 20px; left : 400px; padding-bottom : 50px; width : 491px; } #news { border : 2px solid #009933; padding : 20px; font-weight : bold; font-size : 18pt; width : 451px; } #news a { color : #009933; } .screenshot { border : 1px solid #cccccc;} div.demo { border: 4px ridge; border-color: gray; padding: 10px; margin: 5px; margin-left: 20px; margin-right: 40px; background-color: white; } div.demo span.fail { color: red; } div.demo span.pass { color: green; } div.demo h1 { color: black; font-size: 12pt; text-align: left; font-weight: bold; } pre { font-family: monospaced; border-left: 1px solid #999999; background-color: white; padding: 5px; margin-left: 5px; font-size : 10pt; }postfixadmin-2.3.7/tests/simpletest/docs/simpletest.org/README0000664000175000017620000000012411157271050024375 0ustar davidpalepurpleOutput folder for SimpleTest.org site versions of content, documentation & tutorial.postfixadmin-2.3.7/tests/simpletest/docs/simpletest.org/images/0000775000175000017620000000000012301477470024773 5ustar davidpalepurplepostfixadmin-2.3.7/tests/simpletest/docs/simpletest.org/images/book-guide-to-php-design-patterns.jpg0000664000175000017620000001303111157271050034024 0ustar davidpalepurpleJFIFddDuckyAdobed   #%'%#//33//@@@@@@@@@@@@@@@&&0##0+.'''.+550055@@?@@@@@@@@@@@@" !1AQ"aq2B#b3RrT$S%!1QAa"q2RBbS ?f>?,yfA LHf2";Cw}6u\<24RIّ>DR/q"ܳI5iW6b K7zGK )xX ώ,6Rך=; e;T̋n1Fe$z)77S'*f 򥅎i#  `zj\^8)W|:I*$dd T)dXH;fHi\HKͭ=.k~>M0lb7Y-mR4PK,* ;w=&mϥ3"7sy~K3 |Xg?.ۏqէ\T0㋌Ippo@ZH ;FK zfEy1+8KVj֙l<B@H:iMq#"(251`Ya"х@mUQZQ.4no3IE;sm:IO(d#,rsf)Z$tRF*U#ﭼOIAmU"تT][^k'b6)DѐSo#pji'b-/o̾hMl6WqW'V%Mێݠzt֞܎$61$1 Y$Mn}ȱsqr '=KAP ӱXQeVv .B]@k6Lib>cN$4%@ {=loamk\\X43D#'o@Nv$ 맾v2|IFq{)xI 0cou쬗#yJ > H_ʝg/%t鿅(p]ڒ 7 OUG q]Iw.a^XDk+̋( V b?kJ3i(PGAF'!@:6mqc*8hT_@H><><,3wm7>/[Mn-LlSzpO^LR'YXvm3q+ g>wJ<>.1LG$Yg`-cN;*fMmǯ_ byO)mWSRvneD[4VF$|2N(,De}M Ѭ;NOmH^Kqf љשb_">1a-: o/܊O`7yULfuF`ۑ\QQ[KDQEQ/>hx4Qnji05dp&<#콍PnFhoj#tڲzoܸ~֖+agQk3_K^[Jnokypw}e21 (QH~gexe,-qRz::?cO\LKM1IDH:{ɧ'۱Ǔa ^x3z6Jxy{Q]/ûd/ q7+q{7:_š?slɕrl +_n74lOfR͹TӥOq|OTh[ҶVLS?_д 2L/%sY4m`=+T|%`mѩۈ:+#<91DIy}+_Q9AopkE>#_ j`ro >ICr[1I DP|+iN&<ݴ7RǥZbf~"Ŭv[|!8+"_JǠTx wg?PKYwnzWf,=9mԹkf>wF׈`|}5Yyw|:f^wN$oPڦVܸP2dh?iU>׆9p64򣶤vur|jF(JbB ۼ XLR NRW9l'`{;1b[XW!x+5Rj.ūԐggcZ?#\ET Mrg%$QB=R,\7nC3>ؿM`6I@t#5.@c`<$*G:Qz~>| *`4甝9 rSs}M/#Klue<<XY+}  R@I戎x M3:dCjsgML;t>ڰ2 !FDLV|_/a|K.m~_2^3ȁ kj+ˌp bPR*.+:N +-pmEl}b/|oҊHnuκ~[N҅)bvZ\;H ѝ|NV)%*(46I.-/nV#KR"$r+2ya IY@NwPջCm9Qet֌\,pgRrX#Yglo|65j9,ӛr}BBa݆j)FTi.ԅa,н6LF!˱,O[XĄ:k:J$12[Әh?M6IqEɪb;/Hԯ8T [2oOO*jR\uHT2$#=8sCz[D!_*)R5>&Zp+Q HX,j-1# ZG.LԻU9~LwU][2eodpQco-kkyL`^@)S=?C{+HuyokEG&Co[-jڏ#1*=Nt"9\q'qoouμY\-VޗPޥHֳ"Ǘ>MNA|+AJ rhdج6UqTtc{{k37O*eWhZ#z#P$F6n,rc˵uE#>>>rTI2oҪL\-\AMӧ FjS C1N4`I̻!44\QY;7/>Wؽ|:NܗUuYcu$RəƊ [ӠVZ_ 0k ,gE(xih̝MG+폂11P!E>a@]O|"8{cx!ZHՇQ};b*E:E\| tX#آ` E:E:pVv_R?_ؿʬQN)>?_ؿʏ֋U,K,$Y,,n7C2dw̲>Px18</VB!Ynzۭi{lSm4u0vjd-鏒}_~hstq:xY#P:Oo׽/Wg ث>袊涊(((((;2'?snעn x]7򿦜6QE (8%+*postfixadmin-2.3.7/tests/simpletest/docs/simpletest.org/images/test-in-cli.png0000664000175000017620000013170711157271050027634 0ustar davidpalepurplePNG  IHDR`qsBIT|d pHYs B4tEXtCreation Time25/11/06b$ZtEXtSoftwareMacromedia Fireworks 8hxgprVWxk0 ŐN2U6ѵwftjp49`,l_?d}o0 45 }Cu^ W.,lZ_13S7`R5 e\[89[ji)F*)Qiiy"q:X2JxR|: GNC\hΦc隗cHc*7` !tMHK!_p{r͠_eU'@_$ż)U<0\lqyDk.ˇȣQ;F2oiA6~%y4C;JXi1nhuۓ%>mR]:<".qFܙ{@_wݏVswG˱!Lv,}Ľ渶 O$ՑVFwramdzSDgK@һx/SlZ..e4շ_9-&ݝL7~nܟοY>hϖ_vkR36~6ϋagh0l,6e 0xi e8y=j.|Π۝;F &4Zn4%MBS4wF 2 cijy>.nh=غ}|2d4hMi}TҵР]N`/~3C;6a4#?YwRRzl]8 i- rcXE%iZg A3ht~#%*d-\+q]SvB5PF ]k_hݙ`rL.)<0mB7:cV n3~.@HE p7B&Cf !9|(֘LJA (b_1/Ieohr(a,CY}. s()އ/Ї7e ƈurcX5珐ɇ`Zzc<*]cC 4j^nx:7,);Xh{E1Yj{}Rjq NWweL=XHmow @Iβ#˼'V3ȒAbzb'!vP7 ԶhD䲍4 SҾ[+c./kd;3XKDN#( ,"\c&јȉbڇ'#^(=}h%?2֛0~:tY\Cۭf23PK4v 'o w[}a`6zB2E4dic# #D2~!HnHp<=P"lM4ƑAeChXXCJJ2]0CcCO*,˧ 9Uzvyڑ\suQ%'d&szG庽ʁЕ@ߪ?[3oQ2O$r;1pV{3mUGJbeˀT-X>{L_=nϨcc s!4rI3%qysC S=Λ#ۑbClC( y9u~="|p i%ѱp,Nl2r:poKäAo2@8v&S3RUA(n:8PA_#4So[*GR:Ӓ>o^B |gH 4L(@I3 x;X:SY)v>E[bA ZjlM2>ʯaIVϴ [`(d*d۲s`ԓ,^A?c}"a| }|Kxfc7sypSk̆ ->iѸF8|XFa2Z*efڨGh8 О ᓔyiɽ`sS7$V%U d{>LEI0HcG+S CUXrL-6H܏of>=l:jVLZOZ<$M'#"/\(3ǩ5SD٦tHvYqŴXr_HM֔kɚNآW/|ň3e} ) =Wp*:;?[{װt+VtF Q߿uoNuUӉ&#<kL+z~Yn=^R5f1Y܊9[i1Z^PFcsSN.[IDÞ- D uu$g3ٕE&K^R_TsaT"-"ҙm{f)SWVIdDz)IըUFZBd!2&-Vi=kT?Eg\>#QNM&f%"|e٢Ԉp?ݜN[NNWɩB {Yjd|VSNf#&Q%2J4lqrJZel&.C0ZwQWNr\kP|mIhPDŅs5^,FNی}bا^u:ݡv5}ghR;WUf5<ҏ<: Pԣ&;LǶh9 jk@eYjUn*xHTY @߸;4GHjNٕ}nj n4PGVh`  wI cIe9G4YtZ;\ú|n=FƩ"Y2mJ yJa'W3Taa P5|;OjTF rr)ŝnb+E^mxM5hZM7pMMqXZC# GIqGߜjpj5 Vذ\+#Ǔ=7%E&J1%9f#v *h^IuĤ8kP7]Iqfv(xeS>SF6oj-N6fZu^FFist_"< <3 _q*$f2aˑ (Nڷgm_DwӾlw">sЂIa ~y?'m+8![';GpEctFjw0b,yܖc:+lѕ}ZC: (RgBUz~cgcȖ w+|͕ߗ=^9M5~u~m795}5: O]fRT`wl#ڛK?+lQgE9sZM:gW}()G!M{ߓoD]gX3k.@Ҏ0{_ťӟI2VF'_֜'`I6;J/ׯgYlDW*5{49_G{Oߥ+/l]Ul*puWqmqu;){ɒx)R¾CR=7岼lQNu>H=$zZfȓfF\ao}c lcLA}{mbG1ϕ#['Ծ\#l>De439}1}ڱAtylPm*{-S9VmVYpeh˴Wc6˲N\}N*V\WP_m̾4٭GVtߒ=0D粯+d%o{Mn<Xˀmxք_=^܇ Bb"ԧiaK\19}?mLKӘN.?2gHM`ZƝ 5nd٠Ӏ_/K y1~%iⓘ&^u@7 C Hx-C,J#rŀ8'ܩO2yOvN=7|:Н7oւ[4Wӯq-}1x z?Q߈QYK҂Ǒ{^XL#b P1IhQ8aO'BGj|qa@G~8Wtyvq(SKI876a/AF\dxJkos F@ KbI|=1Sw=Xk>?I_CxQX:҇cj@mE5Ccvi9V>׆logb){N"ԣQ>zY>NiO}׏?˔NwTyw|D"ݞHGjGխq0~}hdwZ!!ߣJ%fȔWĸ>/Ӧp YxH>ȈIу舌(,q[d:N"n{;pEǻ4_qw9%yO,>ʣ{ gұ/ =U$WH,mY6+xFXCMt uҸs:2$UYe _S[{#P֝:Jg/;]Nwp=9¯}ˊlY1M\+}|:z'blU wZ~ǽ2cUS1US1y0(w%;H6xkg HSe>RѲ/Z.M3QMۊA'%Ny"c=aAwrHW9A\B?9NAt#hL"_LˑM`Pka\W+R21~NO$< QX =oa~ݵ6)c=Wxm|F& 4bмiO1'G6p5y)Q|\y޳)cߥ>*{ɲVvj+ӌxi_2z'ПFOI$diFphn9R_ eA/q&x_Eƾ -X'{\]M{y֔u( 2,LCgQx<3s f* Q.Sߕ>>Bf}8cwc*&w GW`M3οZCѽ}PP<|1lmMnP#4w6ڷJm\}~negcYM#^/W'șV& l1Y*'LA|p㊢Em8.7.fdQO'C dfVOvriG |+^4V2W.޲tHD]V4ާ2~bSY iHg[ cDwT!,q5Z.6Qڥ89w4W<\]a'7+“!XpsGq˚mߒb9(fIS׳uZyL8Ԣk/@.g N㼾1> \iO1k'`d4?78,Bs0Gaݧ'n.VE0}V77f>\Ƈ#x^TxRò>tǸPnO%Dq;}ܷ?Ƣ͊>I`moa~>"u6!vߨTIxr@rp&'Mx.M OS*VХSRj}`sn}C7džB!ppئMozc8QD#K''T:`Adon;N:"Il?dt9Qestb{d5mx m7|ө|;pG9l{4p{f/1PlPYn٭\'n5鵯';G'[*ɪCgaivگ13Olv$_֑"mkBSx]N0ܣ'# ! cenÃsfd+6O`=j'T&с+~*5:/=H 3H [IYm|#qo0 /ǘ [c,~FsUm<7v'UXtD{TiC`~+mkBT~(TxA 0ׁ9IP u;;;;;;;;;;;;]w*@p#mkBT~-xIK$YJ+u­ FPP(88޻/30B,177gggqssMMMQ__ qOOOqwwqrr&}<ڢ\%{{ E/wyM333gQWWE/Qb罜WWWmׯgñsg_h.{0?ki~uu5677coo< rM[vXYYbg@k7?===1==]r__\\w| P՟hoo/Z,sahhsRq0Km ,WyIkjj_ۙjkkc}}/A>ѽK_ g~>r'}Of~>{;󧦦%' ?22R1ǿ{mW>?z~鿻/> U3f!VymkBT8x횉m0]HI!)$FR?6c>>~sm+vuՑνYu8uN?WP>1JsWiV_uKEϸ/rˆ_gKW]ױEYcl,[TYHT}xL#}A GV7^}>iҞ-i;}LJX&TP3T#ߨgJl e'=?͘ona|7>?ǐU%;/mN/IfQփz{G}?v✽3X~j{zTAO^ʰ>?sy|G)P׻gI@XjjgiЃ`0 `0 ?ϟ|:seQ3|ӧO|:2|.};7eGFO6_Qv]T]^ˮg{>pjzkuo{yye?{-x/ D:3D&򈼹e^Hyi#/OGzϪ߯_~ :sMe#M3Y#=2 QЙ[\s=E8}E>GȩT ڲTg-}VfoSVwzV}./>~!?U1<#}=F[ ~QڋBN..+푹^edLo+[\-k dW(}6q$#?z6Bөi?L7!3O_Q}Пuo[=tkȋM!'}/Ƈdr2_Cﲨ: `0 :8o=+8-4}۞cĥXdq{bUq©ήm!ƶg*ΪU\z[GA=^+ru{LV U?)V>ғ)x|Yҁgi\yi^cUo*= !TY?rfgWsʽVn*VX#=Fϫ+[F~yH\L~[O҇h5ݵTow|Sfӟ+);F;:x )/OS yUo2e)Ve3'wgGg=J^`0  ľu kU,Ksؑ5nY,bXw{ w&3QהNQev ]ƷgcH˞i{A3I8hwduwUIWq8I>+@pQşGcZ\ƪUߝ]/:3d;ɫ:gB9R|GW~w2;fzt|+i5nΟgZY|<1NyŬ|E7k?z/k><=Α}N΅>uWydʬdz `0 *\?W8GY:Dgcg< 2+'W6qn؟{ru"wU쏘~c#T?+y{Q,,^qF/Xv8.֩g3}ȸOP ~n%hUG4(_sn|W}Tg&x^c,Fѭ+ <#+}/Uw8BRh_|33!mr\7U9m({ѝpvew[xG]߱?g;,nҽow8]וb?OV=Z_#ve?vN_WrYLo;1g9pV^G~>[_vNOS3 `0Q[ veO\k^8֔v<Zbz\Opbn$~}oz3ј mK vU]^iNWA#x딫jt q :E= z%օq)CcYEqyRG-+u (K\hP'*^ء^q=m=y|Kvūe\rȊ4={W1;=ݷxp;o@>ȘT\Ԏ+C=*ɫ|GJOCW]x1.ﵠ9_Eб Vq)v(ʑ}[GwǺ{-oSdו_˞׃2;iT&w*w:g׭SOsj%Z[~_˯d֮+w]7 `0]kIu+eL]ւoA^;=GR?v쯱;<y o$N1紈=:ߥPVu< <&3KyC/4r)i=*/|Ύ^]QNН1qGw>ù{ ?Kv:A}E:_n+{u=rq͓̳]>>d}+|L01`0 leg:׺񶊝`W,3O?]\9P~[kOWiGc~)-<w.3q}'vuw$Vnv(r52S;Wk_Kϔ8B/hEՠ'9w?K;x:x<|@cϽVyc@ۖSw8Bq]=2lBe6V}eR( VeZT4ade2ޒ+nYBTqSߔ<[&=f[|szP)G}{Zׅ3n7jpWwftEw[ǽ;`l? `0 `0 `{~i`oLy>uoi\qK|}7Svu9G쯿c¾#>,jow{ՆݲL=mW2u_8دjo?kD߱mw>#}E:OۡO;y`$j?tU mkBT~x흍8 FSHI!)$FRHnw HYx3ꇤsaaaaxIǏ'U{o_ھgW9 o'GW {>~Jlo߾)*/N\ϱov[iZ_ձaJΝ/:6O- 92b?Tlk%?_21B sY5>:>c=1Ow y^- ڶ,XzusM#גU]>H_yYv!ۉ_mi Rus]Xm_g)YY)m]y,m z1aaaxEߓGקo/Y\k6xjgH|yu.\aæM&wk#ϐ$?]Mo\Ⱦ,/ڥQ@~6s?)}, l gX #vQg Bٙ^uのuhm?}{].~}v_J;xogJY]޳@.)oqC?}>@Xߘ'-(W? źvƔOʙRv[K?[A}?-wmՑ}g\=c}M ggg DŽ-B^k_g?F? v0||؎=ǧHPgs/hؑI t~{n^}ZyD5XWvO)"c0vY Z|~_%/,p\ɹyΰZ/;/xs_9?Pܯ5ݻ\[y|č8gʱL{? 0 0 _k3>z_\S |<)b|7aaaxn.ta?l^Cvkؽ#~e)3<3^kdlc&jK+o"e<.ʞ`^(3zu l+6v<ï k7]/lc[`On}򚄫 G뎱zt^v2)?;Wmr5ocIz?Ozx{&!ez."ѯ 1Gg{+ҏlw<=}GݽFƨ^)zIpG K֜{{e G12ۭqiumf>.}~a? 0 0 [u+7Svq֭y΅ ?ނ}XwŶv?ߩDZۓ-q/?߳=<~#>Fk"qzrQo 9r,nY[;o:)@-`ק-7({߯S@µK9֠ɸ>:n3 _[_*mtcmC>qSL=<6;ǫsaaa{xˌ\ފpx?0׋#5zяc]x^l򼠕(f:~٣^lin59W~\;?vn6erUbS~v^U O7O(|;+SG4|?f*?rW~2oNٟS9~daևmH6mX[J~s.ym4ٶO|Bd/b5ɿyU? 0 0 0 0 0 0 0.P~*1@G\⟿KrKXs2(ߥ纎J8'>X@▼QQbqwx b)_K|v 1M6kee-2Ǜ59?K^E~9ϱQﱮYF8N?~;:=J<-tĒyNAgC \NXKs)'^Kg\~2}6}Գ)n]Or^j~"{p29w6/.z-v:+M{WJYZ굢`% Ҥl9ힶկ#OUz+U?;sd~vND7*.Y+v:ye;8}~|+ÑޅN9}{Bƞ#txխsXɿkSV/uJ=o G<ջL'L:D]6jfgLz/+ؽ[{rCMYq~[{yy czA;w9zszWHVax3 ף*mkBTx}+(H,"H$"#X$,QԈZs>U{ ..T}6ڳ-F`p]k߅~b  О$wݓٱ|sCoA+q3lOx@(0a+? T,_7s\Ϙ^Bl1)C+k(FyN"8dPC_9>O0&l4Im+nwGrŰ)/tihf ѸX>E)<,6s45zb?J\<OM%O#(76:= ӋYAƒH Ls6MXBcX&ǘJte. 3.je(??Lj=%wZizFTx$kP8Em jAOހ>~؆B9 ֤8UKCvjbL Cy ;mj P. DkwUE€3ܨ8xUJs\ɟ+;}sFQ(KIXݛƨ 1 +KdX];Jģcx$D׷X`i @l̏rnm$^9΄zBGϞQ=nfkDe; <a>,⢞jk0B[p($Ǡp4 nq`XƓ vϵ.xHnorJ5Hu뇗 f a[Z:>36[g RL؍?( &w.7C#~B{] UW 71jk~ecGrD.=K@WDZM0倐0\xvqNZ ># BE )&yA}t?B Ym(WIpɱ |2+\2 )l8tl@Z.Be񅋍RSƃm>dIl'N adĢG3%#)?$s _5=YBR#-k"qGP-e"f%֩-ϓ378M9ϊ,_*n;HEBƱcl~ ˝[/sagIE2,z1t:kLș壋G){7ond{@rP>kwk׽ #kXfyEAB9uM4P=_lgW؇N#_nGpp ,ZUu6ȓVӰ0EK7*|]{75F\ԶzQz! uH>upT٣o3P)[^6` -d&*=%fY<^ط`_6|h3ء>2 Pq7ώ ,NsjF=B` 큳CiU)R鐏@LҮǧmb<2FHRqùFXi䎲OmGA}:*u f:@ʫRH.66jcGOpO- 6HKJU:Jǃv,3DZEƮqq7p?ȌK%ȧ$;?Qr6pP7`a^=R_)m>D3#£ _' Iɭu͋C-Rne㯄ssL<ȭ/R)|Lt_1Lk=rr 4/gEr~PnB[\g[{gYvRW' {Fem1{ wL;7&$xc0 n&u@5sCCձm8Heft x{q(aтa?Q%l4ςxmWI׆GC1kQ3iJh,KRO`ʲ4)%b6B8\pe;u)ko)#WSncRx{[sXv195_0Kՙ7>Tp5ٴl3S"؝LX睫[5m Q="u}pϘ*xbՉ#iM+@Z! Ϯ~jYݬ$?5mtu] %@݅:4h8ۃtu3; ΑO1A/r R*5i&j#Y2:$Z(ad@>'z L뇶6Z8|`6"X1_z' F-я?X^ A:?1;h/KVB' vOnFS ƤQ{=kh7MwXQp\v͓O/. N3HKRlK"q^Wh1wt h@3e6N|I;y?8t[[! $,ήLe"z%IކAkRl!3u8ځy?_W)AbCO!rza5Sn֗#<43y6"R߃CQ&>[# BHǽ{vekOTlq(UH͵h ݔ8,@tՂL{p/*L"d_y k,4 G̖bD>,.ok"D;|7[.DCA#ilϟI֬Dq]+eE _-- ڰc^Lq1~CCC9gNH8BkhJ#Z-`VoMa 9r$պZ-hkh ?C$ ^tď9d(8P݅]ڶw[wl;dn׆oKd Hބ(DInI M_(5)6H/Y1 QRk,nXHʉ?>df&6^EJmt{CCc`0ʅv5x<\9Yc}106"״!֏9dl:' 1H"z'7QqɌ#KR./CVgQȬ\ `?d1yuM6Ƶ8ZX]8^pwQE &1frRKi$GݜЕh3'{;;~FK37ku<pdʎ+C RMzƏ7)nҀ lEGyl:̑IoBS%|ЕsTulebA}Aʹ10A{KʘӺtjdLI=r PRg_LbR Şl?␔)![Fo wi&k^CV(t@pW2{hxHGRn͉eCbxԉ6GQd27\ثdS=\Ff*0ۣOP5(rZߙxQZ>~GAeN-jY7Ҿn;n?ӹ"Px}/NW:݊&׾:x" ꭥу;R펔 c䛅љElmG§a= h¨BG_uYnZ쫭FYs U"zM&:Gnu.DX5Xn;}ԫ%XO?~2&Frjj8 yA*W I9/ub)Zl: s 85J>~iI3Yԕ;:#hELם[ROd^GA˩f~Y!En0~/A Km>^WYq"<цF*c:xw|͞w%ehRgd9̕v3v Dgh>>?3hYDkgC(ʹƒԕSԜ| 2Q94(?OGQ34 fccPopTYaW(>@tX4`LGٞpɄaŰl\[9c26U M6f,'C4i?W~psϠ?kAKrŵk@I|>^xs?\`,D̒5W^w DMXf_8<%|8_왉pP1Wlm߃f?4:́_Ԕv M;k:p_sj؎qw]$F}y ,b'N=o0, ~M YR46+!}@~ujctCP.Y(x׎z?70WXFܣo3z0c8RGg0 TU򄽻w"/4֏CQ`[{Ocn]+{{ N!33+5]qpj' r9FDȬ)~: 9Gmx2-?sraG"yvUpa;Ră A\& ?#n 0eed~oq嶭!!DzP^H)>oȑ.ļԶ=Hy7S-M ?8ycߧq|#5"2Б lm#UeΤVbM͘jAc7Z ]> 4gb s 2WRsKg6 's8qzTT[R[w)I95xWj #!nN+zPڔ KgTE,?{^RDݥ=Ru^zîc&D'i74SJߔ&HUG[crͦ<׿~4}څh;lpAZ%XZ;tQ?yk1+Ƴu6[ Dc4Ɯ*dB#!}e>samhG3c^8u9󼵕⸈߂UyB;f "Yi=D =4&|C3g]~WgjhSIXU"1A5Fr4{AljwTt6</N \Rta| i>T.Wo>>xϯY{緷m,J{gg}v~)]s!?wXGFl!7U|Cnfﳅ:.@mq%臔Ru?.:aBֺE#Gg'yXDuSWNJD)21ѵVagWPqȒ s?¶@g")s\T{f3go^w:^"{d#!φt},nyWFKv„X4|VB~,˘_&fjp/WԍwaO H 3I`u1ͤ+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_Wݚw) mkBTx\NM%y^DdnXqC"b@$4⅘iSm?w]zfgK*眾TU7]S3\kkknuu}$c)=Ǐ&Kܯ_T9f'.c:񟣋cKM__+Ϝrμ_dLR6b0_?Wue& ƿn9N+mr:Gנ<'&H߱ !៛tPҼ-r}޻p `Knؚ5In uI~@ӫY۩:3bq5ԆP[ 9*بIsuc{N־! `y?AW0 _7ݐiNmjj]ޟ^m;P )9V*oñ[џ?XW70u &? d| ߸ ƿnX ;t _70u w{t.<@R`BNK!_tJ 3>w̗jg9yP^m9yoH7UN$*_Zg>^O:>RW~J|jN)Pg7Շj)9O/ LLd)şP[c_O/1?Qr tu_/ _7c`` ( y/u/hZiNn\ǽ_4 *Ih]NDڞS^퓊qľc>J@sjK؜W&VN ٭{{Q.YbCv5 \1)pP嘝XjS5sSbv}_/bd<CQ?1a~JK(pZ\50u {cHƿnaƿnaƿnaƿnaƿjI mkBT~xoM'BH p" Q9 s9ӟ~%ʚo5kֆ]ߓJΚ_׫ {Y8ydسgO8}t(A*Xx捬۷Ç6v߿_U?.{Exex߇{ \KV_:;v ǏVb?A1"OЈ޽+6&6&6&6&6&6&Ӷ ê¿8 FP{tڵ"Bpڮ/K3D:9fgjy/1y[޹])7ɻn\kWrN._ycc{ԑו1Xt;U c]_=ʽ.+ӊr>jq<Ό?:797E+];9y}J?'YtfW/^߿4W9n{?ߙ_պn):S_Gc޿B,3?m?vX~}XjsٴiSXn۶mz:p@8z;w\x?^/T8W^suVpBtRqzz<8>x@[n~pӧg;x>~}=/ͦt/_s6|1|-BrN?{o3Z;>ϟmKΝ;Ù3g͛W\1=zd1A8:r0w0mڴ0~0}tp!KÇÜ9sBccchjj +Vh3^Ϛ5+]A_pBs }:O}y! M =}'L`u;¹gl 2zI9}yn{/ }Z \o͵?={4ݐ:uiC:zaON_^߃~>~8'H>O hS?{F9x,?~5Xst?~xy7[nƿ?~PeGǘSa=9ޟg]Hql_ @zeKͳp}^ 'Я_?`sրY{+߿"`XhQ8p`:tb?~p|r=zt6l'/1bDݻw>|剿q==ߟF  }  #G=byu_0 WżεL~J7ho6I tVy>].ܨv2U6U,Y2ߢ<H3?4Rz f3u]u uܡqlڞ%ey[u/W}H̶̑5Azh2ANJ>e_z;mC7DSGr2nI3XUlڞ 21%,SWg`u~oWuoe0[r"͏AѮ N:kgxߢgJq99L{u~3NS&m<<'Y?+뿫LJ}mjvܷyp_+_@u`YEgOOO0 o&l>e{<ߜ A3lWߥ}|ڭ-K\%Kq\{_n㼞yYboXjg/5?_jՃEO=ַ!_7XW~>X">sk {-|Xџ5֠~97k?O{k/=Z~~5V\+~8YO7ytfg|duTbrS>U^~>?{16tz{2=}M/9vUe0ۜgfsޑSo?}i\TUH{{{^'!4Iα3rwJ 5rAi>} %=:Wr'N]M}v[6Nu폮b/n~kmͧo29ʷOo@ =wz췝Bv|ϕedb<0M 2|~{6dwIz΄ H~]&:kq㞟_~7i/1^o r~?O-g$Ż^W7Ȟ [y}#s!JX䱇{> wBD?$T:ysbHoA[9"'OfP܃q#,O5_Sqx|߮ zA#ElÉ#IDATxy՝'oU]՗ZR u%:AϚ&0 ,x3 1xl A;l1FIdցtK-UgGwKYUuxˬ˗R0 @>hll̙3"""9'O .7_0uOOك  C4dq""" $ h;v@{{;Z[[Ga`߾}Xt)t]O3 g @e{hmm w_ DDDT: ҥKo̘1p8oKعs'8GZZZ0g̟?gv]jIT̖v4Eww7z0/M6a׮]GkkkƳ=zeZ$*ő̘OWʣe'd^߲e ZGz81o:f\3O V/֮~KWE߃k{Gƻpi)]к w}z|}M3뺎ZȭE %嶶6aҤIOСP&MB[[8v؁6̚5˲Ւ&ƴ9C,8WxszjTjJFc8Yg;?zYLKA ŧU~~ܻN8X$̸ ,[@8Fkk+t]O7 "CCC Ւ&؀%_ ^\mT*H!,bJAOB!hןe1S%u4y1˔)@G-6ezȪ.|AL>H(\>%*$IBmm-:,:L hW`ŷD@>u+_ "j "`0pfǵp޵߱Mc+ƻoaո%Nwh'6<fow)$aqaBUhuF!F-&?'[?ou8*ઇpwQAUU OXc?_<)!Q9%I466"# ! " p555鵵hjjB*iRF-xh*s2[$ ^II gZ< q=oQ3kًuO+{bŊ; ;CcyhEFDZ8;obAxeXxKŁ+pC+wb޷J7֮Eֻʷ ?D46wx+W>[`3:D +W}wߍt_](:\8o]M>U?}?ޏg܇e-A@+{7HݧWkp$ȣD@'5dUJ$뇪C]]jkk 2@9lr2D"@< IZҤ$(Ae{*޳o ꘃaiNT1) IJA.ƽo;uE4u)AU-hF_6w]DзX;{;6$I5$@Gf>NiO[+∧fܙvGG}MNDUU06֨+_}Q\}N`=XK"X|UD>A8I t-;Kct}BinCT֩O7|1i\)  ;{}bDlCԷ- tjLE2 #/`M)8+QBvW*Mc(BQAHI='5 #=ڊwssH*aVu @;3ŀLϊ1 &jLӶ2T)"3׿6tvcF{; Lq-z@g(Mb89V2Z R@S <h[F@+{#)<0K9 ۝%I<drS5vSo /ӿy<#?AGC?|Ǔ׍l+ {n */IkxxCǵ?/SEg=ydqH?3Hĥ:A@<ɓm%M*?Ma4oL0 xj,9QUUGN8ʀA3 1AӌSye3g n@4j _g~z>L-? %`9_ttfvܤ<<a`d/|p5N gXŸ C's[ӿ;Vwc:^58Xo8xw͋ss2:s1D.s6*A>떖bt T%}yYEȲ EQ I8bXzjO*Spp u#F١=82ࢷQ?}Rd2IHbx?| OC9K~CCw_λ Àݺهxm{@[6m!H+-c a놷\j9ڏh"eM@"WYN߼e@`*=I&a4$)n|5Ќk{_<>%=+&ː91$DAEGV( }HX 2Ӗ AQ(I,71s3x3o /i@ w2:mU^0w)kJڿ~~r:<8SxLkegyǞ0cr|Z݄;OWs7n^ ynXk;&;COg@|h?YS |jL/9 ɓy_%2mۆX,zL28q( /^ M64Qtp(e"qDH%" [>TJG BOO!GGʤǣ#ةx)C)R!DS:@u.˝GO#p"±c30 CCC0 ---hnnv8TIDDTN5p-0H$feYiT%M""rqt<0U&Q)|Z$""*%y͚5.ِ;NADDD9?~O+U:k"" ƗM7h~g &f'"`^<ȸϪz *%89 1;R\g˵;]ϯzڮr}?K_2usǶ{}^Ss_n]:#lA:?qΰw|3LM.s^3\3Ys4v{Jt/.o\XK*? nqUVϵmv-Vmf>oWkrk;lW}n^m]e:=o )'_Bg!?AfUBwش~ldA//~n/7ߣ|ǡzռBUڹ>-uݞviY֫|M- mݜdx[i};= .4}YKgBOZ mWnt;Nn*LiT#3\*%@=szqX_Wn볒L8,GNt&W:o~,XtϠ<\ggSf._̏@\;^7epʖ+|~rg/cvͷ9긲[M=Tm}Z国N1UyI._/*m3\Ų:;[<'\bNW^X;ir2^H=;-<4?/G'e+&|ܶbʓ.#_dzsw\器J+\*/ռ(?[ĕbn[u3EFk""roT*&b1R)P(EQ(JoIib̙`MDD7Y1{lAE$I #BE(`0f]'""$I(smm-0<<@ QGe$AHϺ\ ZyD""NmA n^i NDDTiq7ƩK3v>k3B`itcCN'"3Gf NR8vFFF7eUu],@FԲ6;V#g\fG}Ab1b1a455aXp!"Hzݼ}֕lrdbLfys9/љKu躎>v킪D"K/H$sN|gXt):H@m>e^M$ơCphY}uݴ|zV^&>UUQSS~<˼'"$I먩A8emVvx/nh""ʦj:P˲lYJs$d2 e=Q.DDDTa -k3XYs$T*U\o;JLqfANTA-jsP-kQ!TU75̡F@m7jmQ<5Vv NDDt&1[͙-f6o6?slp"" ;mm~6TU.^[H^=sN릐k3;Qyqlp"" f968Uk"" fgm7&g"""^G;ÉWp55Q DDDSDDDTZȃ}V-"xPфc"|oMb&"",-k'oFb&""o0#""` 0XU0>gMDDT*sֹ=)o>U|u+nTzՅU4Mi0 a@u躞>&r},6WUnGjT9/9Q~S <:2y}rMKuR)0je(Ymbufk9i$_pRve$&`0sӱ[V|PH lM#  Xh^xb1.[T^Ŵ8#z(덨x#`ڴi$ $0 H4kRxMM bR?Sv0RoRB@ R%IdY$IE$AQBuRb""3S_ALaﳦpM7ϗ$DDdEtp6 ([+VǼ͠= ֞YWڳt;*FgB:73`gKRTU3[uVX tyt2ː/}7nWg'ە5.X"it]G4MUUi4 aɼTnmgٺ*0{4e,oNvG-ʷrFʕWekhbd~)LQJiTUE2wx4M?e>kGr.fONa5m1fk5 U&={H$=I @2(u$a*n\-]es]ho{U&sX,?OhhhHCt6[[nE8FSSS>gmx9C.~GN/Qu1߮588EQnY:6oތ}aܹhmm&˹ӭK';/dDk[-?ۛ<70w\|8qD:Xfz۶mD]].]z>koM8>78)Woa&"AiӰdlٲBcc#( ӃL>W^y%̪͛5 "dYŋЀNbF(ɓ|r\tEsb lu0D{{;144A ӯǬCMM E.3*XOd re 1sL app,# @笩zZDD/aQАE?+E555N#i$flp"""9w曷K\?5Q e{{{;a@^^'?0 Z&""*̛L{Eoo/A@?gMDDT.}d[n7m۶m9`MDDTAxΝ8:;;O笉J \p.B`(`-k""j>k""*`MDDT5Q fDDD>K$ɓ'!BzpUUqk2kjjD( @,( DDD~ D"hllD H'jP(BU NDDTgMDDT*&""Dqn݊N躎!Ȳ I`|_J$G$7x(¢E868Q9jE\0nڒ%K N{J@u>ny睇f&̝;765Q 亼/| /\}DDD%jnnn%\qÐL2[͆a`̙0 #}<3Xٲ&""i9[̩T2Hgs3X,1CCCପ*4MK:4M,˼ NDD73꺎d2d2aDQAoE15M>k"""ߩX T  AQ([$hX,9s0XK/-j}k"""rq7U8|jA׿5nv NDDTi8nCCC|zxpm!`߾}&""{M꺺:YR>{7ߎtuuϚRd@aÆq} DDD>SU5]vW_7 D"ٳʸϪ2XCWWxty;3>k"""eYwuuaƍ>˲ _6,&""",_?ƧMIENDB`postfixadmin-2.3.7/tests/simpletest/docs/simpletest.org/images/simpletest-start-testing.png0000664000175000017620000001335211157271050032476 0ustar davidpalepurplePNG  IHDR1m^VPsBIT|d pHYs  ~tEXtSoftwareMacromedia Fireworks 8hxtEXtCreation Time25/11/06b$Z?IDATx}teǿK M/+paEByb^("Ϲ{TZ=z u]hk֫ * B yI'$OϜg~y7Fq Rk D USkRasasӋa 01,&Ɛk 1|s\݆mxiM,\wAy%bMlnR11<]VE&WBļ^ ˞uh+ @EHb\$EDJ&`hǖ6TĚ-Y!h(0Lļ6wcZl r&bBeGD~3kutȞ6 "Dĺ<8}.ɞA%'"ǭ0)"A䎜w@Dˋ }|; 7w 38-fy脤RCGthQ"HS 4#0FsFjǥ_e\AbM!d)p~AHG?-PB[B0 E- /0(bgai 1&X8k>l'2Ј&(AhЍZKXϠӌJY+BB<"ԲՊE ƀ-o`߹PpA,WE FGL>A(E) P%( SU$WCK$+ft(WJ_ Mf$ /3ϑudYRN6A@Nh6bXDAZ@a09q`,i욵za!]HLViU ~0{'YV31V5ثK0υ.#)kVa*m "{dV SeXY%qCVG;9: hb Xfzis3&"s4r8L/RnP݆]N`(* uh0ʼnWǁ嶦ciW8pΑ"?I%juc9 ^zeT!bbi"*m%!#<9GW'.!k%G|^Ĝ>VwnܮeT Ջd{6OyEsF#o-=f Q)!0ADZĔx7!!"3T+bJS:H>AjEbyy~""=T+bJ͵ A@"&ڹO (\A/1%'ib EDzM<ĸ_UCCd#"3r&bހBBdb gEce=ooe`ԱAD(aswt|M'NN0mI Fe9'"sq[loI[xv9m&:?Tա^j7DBW(&bfaM1!r+ȶz({1 ED,"`R -YVVk{,+]%"3d1oJ>oM֛a0t! d-2\nk;"d;z1j$Mt\v8}hH򮪶:ڱiƑ^Eh3MVTMVln.-j{ތ&++Qe-֨؀8}.lnm^աj:QeڮB[%6r c2T 6{tR.\fsݐ[5"Zz3p:mnV'doA'74vnĖ&ٴ}IZ:NK,Pe9)7?m]'bqcKd7y5l'p,+2~iÂkE & $+E y4ؚx+={A4=SګڱdH`Z*}9`6GʳAN[ݹ!M/m̓ã\+ ٵY,;7&ku]wϣh-Mhu[)PV{\T_]fwODhutdu;,7[c>7<ϛnl5J:;7]!&Mv8qee3${UD!pಮF~&/æMڭ5Xpf>*1Y_;s~.k?dgyv4䵑1$<8ȌS$7vZ3#âp9N2,5RZI_>[Mcԍ;u0eZFr#3NpPW,5\SM\l:IĀǤZv#iEwӌX:QcƩ~j!uPN1n9o:^Kowh f{][^LkW!RfĖ?ݤamvm#~ԥXA!+*|\ŎTÝEW7T)iU^a,z$[BΗɀ׶ߎ'z^H[d!CH'tbl߮[t߇B)MΉ!`a|=sqsFύnQx>LқQա0W|>Y5܇asq!o/_9vOz%fy!k'ږ]xbe6ހOt) p~N !scpc,KW<OM\}ws>/b16[)l]˟W qpe3CΦ]HU/b-6ض1z<&Xb9` ^[|#! ΉEDq2Џ<+ܛt>b0T !^9xx}7{s:=KG<?7,){#]ϋIi۝{1m1s.k|;ʝi:;Qo7CKCK?BłCU?nXO34}p8?M\"3z?'F{V/꥘0R޴;Dp13~xS q)~Es:"ݿ~~迯7}%ooފ?|4z3޵g=BŃ=Rk_ms6_}~s`KH'}Q> ϧ 4!8P?u,~C^h=X/{,z-OF]ʛ{l it!koZq a%.52%xюT&t*tsO;F$A&#Oόx}S?Tb$EHYNCmpG35Rķl ~O,7 ;!3D;<._jx$E悏=pۿ?pLi ,l{TrUEdH+AGlj?L'=Ly 9嵪Є-jBxzO:QRKJ1bB:u@_밈 } F d>|n=QFLYP NP pQ?J\~tN,ąpN b F>AjbA"FHJI E Ev%BDĂٕ  u XhN Us~u$A#>1 TLB(#B]PdW TM!AA BQ#4Zz 1BS"chjpAhɵOA(ҢUE&8A^\ؿ W.@1 pM1coEA ;,,xpYyB ######sߢ@FFFFFF淑}edddddsde-#####s#+kYYZFFFFF>GV2222229ϑ}N7ejta%o' NEEEP2'tw[n_r-tttcw˼b .^>FFF̜9)A9_|;ͼ;lڴ8lقϟ* @GG翭Kaa!3fà 6`hhxt| DPK/1r]9x >>>jjDEE1e˙>}:lܸcc㿫y(//gɒ%TVVG}m(((7ߤ޽{۷𠬬2"##y|s"##?qZV ###@ޝLuIyfR=dff &.^(1eakk+W_rd˖-b2ݲeĉ'r}B駟ݻw-e !Ğ={.,,_pA,^X+ ߱cDrrBF#V\)e!dqӰ_]7_pAYYYW^d.]/ok׮rdddd~:::0i$z_M߿#FP(0`jp9ŤIxٽ{7~!ӦMSvٳihhtw߽믿N[[_.ɓ'j*{ilj5ӧO'--MJBϞ=~w[Z-+VАpX`O<555;5kw^ \VWWcGッt͍}w^zL+Wd՘2dddd sϱl2>LFF@? &pAttt$tUtuuQ(477Iee%ץZΝ;@ii)ݻBZ-( j5T*R"""ѡ3g`ddvvv0qD4 %%%^צO<cgg') .PXXȀpvv9nnnۓΤIBիWGW͍j5YYYގTVVbddDkk+NNNTVVhӧP(q>}:YYYxxxpymr% BMM |X[[oSSSCKK 999-++R))sHdd$F*'Nj;v,zzz888K/Iiۻ7?f͢===8y$---3=##,\\\Ύ Obb"aaaxzzSF_olldƌXXXjٸqt/66p,--k+GHHH9B0aӜ:u > 9w>>>glذ`ƌG}ݻlùp<l޼+WPPPٳgٳg]dhooĉX9t(I&h"jjj:t(GɓߟׯE駟HMMRwQZ@Φ)SoV%&&gy֮]+TWWErr27n`˖-ܾ}ĉ̙3(BCCi%066&007ڵk'88C"O????h4<33}t,Xĉ6l>(駟߾};MMM<3d,X@4i---d|.]DHHgϞ%..!CP]]Mhhd-Mׯ_O>8p˗/3p@JJJXv-<UUUP_~Y!DUU5kj3ftEX[[ @lܸQ!ıc$䫯*,Y"lmmEll1cDUUB׋UV !شiӯʄRHHHGB1l0aff&Đ!CRҾ{B$ufeeIx!s4iÏ߿uBYf @̘1C*Axxx@L:U_"88XS )1 Ł4ǏYYY]E\zU\vM@KP̟?_O>sЙA !XrB 6@V"<==$ |nl3 STshB鉇~X466 @ 6LJ㏋|!AQQѯɯb^|E~RSSJ-s~@Rqq>NÏhP* >>;@3gPWWGjj*&LOOOO2CwΕT1cѣdmiiqK/I7nK֏ξӓƳӥH@@zL#GG]RIۙGGG Y6:@TD^^$%%q!v!)))@||Ȋ+pwwg…(JRRR|4VX5kPܼy蘐=z .'&mڻw/2AfR\E⋜>}D Η9O>$ׯg#cvYr%˗/Wu3wwwnݺ9<֭[G||RPP5k 44h|}}Yx䃿K[YY3mgv[[͈;˽:j^~eiBeʕdzrJƌ)###o^RF'9st[!D-B=:::ˠNs+ReYutȡCq/Znٳg#;;!ؕJ%B)N Ą [Ji8{,|/dggw1w;###z)wP}qCCCIweffFLL W\r?p@)2=~:v"tO0t.u4׳e)ߑ#GRmJ7|#]c|#ڶmDKKTN@@9s(++7nXnBÇKAJ/u'555QbbY?~\ 1bxSO=%rssx뭷DyyHNNB @sv9n222طo#V^ZJR… ;vL!ŋ'|R:uJ\vMJ7{l ^{5څ pMOOOq!QYY)nݺ%|A*ZK.9x𠨫 .W\̟?_466JR:Ld޼ybb͚5zo---gʺx@kӧO&M/jZqKvvҭXB bdٲe'|RL:UҥKTٳGTVV?\|QPP 5jXlhnnձ;P|ܩsss9y$}dذa !CWWxK{ݥMuZZ*AѧO $))^z1x`pwwڵk3x`!j8t3g^ $$f1c\Eaeek31!uuub ijj8N:ܹs>}Tgkk+j`ddɓ122BP`mm͸q@ZRRRdРA(JBCC [[[Fɓ9rz|ޅDDD0p@Jeuuu8::2zhN<ŋIKKӓ͛7cffFcc#.\_~ <SSS gbooOAAnnn <KKK\]]y&ѣGILL$""Aq ƍqvvdgg3p@=OOOtttc,\PZI766gw~!CH2dZBAcc#G%//k^^^( 7oޯeddd.t{-czjFI>}*!g4'wrw{j>`> &EoA`g={6.]bڵ455wWэ{{݊:Vб]M[*ߎs!44#G0cƌqJMʕ+O?edddd fpP;WFNjkkQTjihhoi[$邬edddddsde-#####s#+kYYZFFFFF>GV2222229ϑ}eddddds5s'TT͛p"x{Ýg}8ư?M8u xxx`ddΝ; NJJ NNNAۇ#FFFҵ$\t>|c2p@ހ_prr",,0^ɓ'⥗^`ooyc_H+Ꚛ{9BGLL O>&&&Rptt,T&&&ٓ>o]v1h ٳ'---P(ɓ3gv tL?c  ]xD,,,8zjmۆ7>(vvvE'#;WZmJ._[:Vp6TW.473iX+#B..Ziii0abccɉ JKK eܸq_`(,,$447o3tPV\ #;;*3gB>}:yyy8qxM?lmmeڴi477Ѐ;wQFR֭[1j(N:FښtvEss3\zOOO;իW1bN}}=3f̙3̜9|ʨ>\|sssΞ=Kbb"}!-- 777FӧQTRw瑩ѣ)//ɉP CFF۷oGGGp9r$8::bnn/N7o2{lijjb֬Y8;;ľ} k׮SǦlf̘Avv6---Myy9Æ ^`ӦMlذ)Sڵkؘ w&""k׮QSS۷;w.6wc|}}6l===222F___jåHcwmٳٴi9&M"44իWKco+(( -- ooo>#\]]yXbE&+k]]02(?a((-?RٱV*A333\066Q.~ccc~mRRRpssc…,_qahh#AAApM KKK|}}177GPP\\Lcc#QQQlذA_c'M@@k׮eذaKX'O%%NNNRh4bmm1FFF`ff555?J.@100oUUeee >Ck4 UUUHЫW. t իҒjT*(JƍǺuprrwZreff%Rё@]KK xٹs'%%%sB}}=r<^'@߾eG'OKJёrkkqrrdgg( (//'22éٙV)HZ9;;H~puuΎD~iN:Eaa!---466{n&Oݻiii_~Y1cpQ122"77v9{,Z~QVVիqvvƍߟ۷oO`` xyyctttj0|pN8 }ӌ1,^sss_5 QQQ\xdƍ?O9s cǎ%((;v0m4 ~~~~ &L 2F 1daĈCXXda011aɒ sңG‚0?~<GGGݻ7aaaATT( ֭[\|brssinn&22 Jp9C !""~Reȑ닋 8::2ydJJJӧ=z[[[ϗ &M:V 777 ۣP(F0h 9~~~@FFښ3fjG2l0ݻ7~~~TTTAXX3f,,,gϞL:;;;022{]]] ???sww'$$SSSFЧOT*!!!) ƍ';B4 666DEEIc9F;WW.&~}?~~ߌ; >iӦb m\p7y(xYhnnndggjz}ϼ3gg̘1IZMRRjRFaĈ7x___fϞ}{!115k%y'.\7| ~BFÜ9s:u*F7K(##}e'HOOrQ*h]inn&)) {{{z쉥%б-$..N644(**RmwS\\9...ܼy&ZM~~-[PP@MM\z"tuu׾J())++?,{}}= .]BANNj"LLLHIIV˹sP(2K{Bp-j5555ܺu .gS;PTKj $7Pss3XZZv?{FlfViINNJU*2]]]pB {fÆ y.7:Ne7o歷ޢ7xT*$000`Ŋk.z-c?,ERWWɓ'%/t(>4T*W&.._UPPO~v%D9s ׯ6;;O>DRD[l .p{;[pAۻ~/ ,YzRSS:u=#ʺkgBMii)/&??f}nݺtӧc+}6/ɓjOOOJ%1M61n8'88===F_|Ann.raB 99x=!!!xxx?Lbb"|G$$$PTTԩS9~8 >#Fpy̙#ۙ6mմexG|2Vb̘1ҁ1F.]J^8~8mmmRPP۷/}ۛ|ZͦM;v,阙1df444p틛o>-Zillg}kkkN<ɵkװ|7ol2-[ƩShnnɉ'r5N8رcӧ׏b???ˉۛLrrr"66GysQVVFh40}n>sq &NH>}swwH*++qssCWWW򗷵ŋ1b111>>]C)<㤤H ggg*++$773p@OgΜFܹsjxwXzZ&>>zKzٞ:u|;;;&O two3f #Gرc4773a044wR˗166fРAՋ}{19qׯ_g֬YT*Ν;GSScǎ%--r Bbb"...աV6liiiTUU1n8HII'a+ |}}qrr" .]Dff&L0L6nHtt4$$$ciiǹu}!<<ÇSUUɓ9roٙ|IyWhkk':ΔsyիWQ*455ȍ7f\~8;***زe QQQT*.\ ''///B}v :t(vÇSTTDii)=\xFݩ3fH;;;'$$+++jh4z)f͚O?駟g„ VC1rH4 ϟBAPPNQQ666))gkkklllذa |?9r...vNHII!C/3b^y啻}M%{;vkCVVѻworrr633͍+WJ]]k֬!++Tصk΄Dnn..]"668ٳIݛTquuNKHHW_%33CY_t +\\\hjjBPp9rrr!11&dfϞ͸qx),,dn:_ΡCbǎܹTX|9lݺ\]] ѣp=ݻjX[[ELL ٱm68::Ju999퍩)ZoNJJJ_7?ɓ'IJJb޽b hlldÆ >}+V-{իlܸ???ZZZXni,99 G]]1<DGGcbb"MMM% @O2ر bbb8<ǎCVn:ttt &&>r򰱱a֭455m6j(J91qqq444eIJJ"??dm&ֆZf}Hqrr6bbbpvv}}}vMLL 999 >w}7o?ݻӇ􈏏ʕ+;wJ%&&&DGGSWW2ڊ)!!!,]ݻwSZZ˗ٴiфLVVuuuw4j5IJ\~7vyu hӣSNItt4vvv˗y&۷ogϞ=( JJJr {졥XN<Ν;100ã]]]RRRxGܶmގZo`:݋V>=z???֭[___lll?֭[155ёŋ grBLvʦVQ(ر=zp9 pww]*?'99{?̍7$ 맟~Jjj*Ϗ=zH.8p;wmmm5DA}}=\xjkkIJJ@PtT*9{,7nՕ`600Ύ4tuuy7ofǎ={qww'??KfpwwgرdffbllL@@hZ 077'99.]ĉ 00 Z[[122.fj166cccP|J%;wˋGTT#FFxW9w7n 88FB˗ijjfժU'[lkkKnn. <wwwtuut]QFqINNf޼yZJRvvvXXX/EٻBtRSS xyyϟcDza4j*BBBpuuf<<c"""{{{ӓ궵Ԕ={J]].{055eܹ⋸ˍ7P*@TTzzzرWWW.]ʀHNNٙӧӳgOJthMUU---ann3annNϞ=AAAxQB JtuuillDгgOiOFaȑ_^::^L4 ===ۇ+~!\t GGG}Y=MLLBPٳgٷo.\֖E1snǕRGDD B5.]wQUYV%! f$@l$", 3vіeܕfVfZB,$Vj}?n# *j|I{w{/s9Od4 1cr «Jff& P\;jkk~wf޽ 8X-/EHH>>>t:!!!>}ʼyxf̘1;'OРV%88Xm[II tMTWWcZINNfذa׏$"##V%66T5:YZZJzz:. &n՜=gy7x#=$k.8N8q" .$??˗_peFݣcccqwwW[??kWvzkwwwØL&lwcϞ=444pe̙ɓ'/ihh… 477ˣaÆa6$^^^۷vڨ*L&6bΝÇh4r!xjkk1 ttteRSS馛xywinnJv;oM~~>&[]] /}X~=jKinn winnV- .]jb۩GQ8=%L<==6mŠJN'TVVRYYIcc#L>ժn a,XVFJJJ*ZZZhhh\&<,^6nȭɓٶm۷o';;,{1^z%f3uuuR]]lߟ͛7c0|2 ,@CC#EIDAT[laҥfill`0>W466RVVFGGz???y1LF***hnnEQT+'}yy9&>}ϝdR_㩧nGWǧr\T#CII ---ę3g^zHFieꋌd߾}ƩSHKK̙3={L&dZ|}}1lذӧOL[[v^_~씕1|py &22"TS39y$}J멫@~i>SuLN'555TTTBRRv???ظq#Νc۶mlذ(5)Jaa!/_VKikkr᪖?vS\5 euihhP"##6lC rlt%:|Z_kk+:N\{GDDyfJJJ(++ L&eee477S__Oii)QQQ;vzZ[[ɨQ;ٴiZvMM UUUfJKKX, 8}hjj"22OOOHIIsFAAL21cPQQb!..B ɤl} bذaFᮻnSSSÔ)SԵX6lsdDD\|$5 00VtL:U_۷-m֬YL4I3gʎ;$==b"""tdddPXX*|95i 7@cc# deeQRRBkk+z+NEQׯf4h!!!frss)..Ã(4 111jfHH0e>S '''Bnn.È#T/1c_:p9RRR]v1bBBBh4`0cʔ){` #F@5;N#>>Ѩ޿Q[xxxx{Ν;P󡵵_}x7(++^Seǎ\p%K|:EQXj&L ((ө:~W:::ؼy3&|{M{{;oۺ!]{/`FRSS5:0 \l6֭['/Yf]ݩ5h4XVNcR).󳗗jk zĂB(\u.vqAҎ{l/' xyy]!((nAX,+eC۵4hhF||<ժCuOKK&?Nc]vRSS pss###kPJ5C ?dcUUUʦM>@ٺu#(_~R^^lٲEQEq8Z߶m۔bK믇zeJyyyﮧ~ө(|ʹs箫N5[nUJJJ2^W_U~o-RY`RWWlڴIijj6(WVVbٔ]v)+VP֬Y(|'ʿۿ]wyD4ߵiñj^ꂂ,Ia2)**RԜ౱\tÇSSSjF۹q81dBBB|2uuut:X,$''s 7`Xꫯ׏s0axzz?u1qDJJJD__TtؾpႪ1744GAADcc#UUUTUU@YY:hJJJ(//'**Ç닢(455q?祗^Riĉglݺʕ+innĉlܸիWsyZ[[7n---\xP֯_Odd$wuMMMt:N>>sΩlذ ?8^~e ;CXXO?4]ӧs8pgϞe֭ۗ2""">fq 5fhZNyyycjٽ{7фBuu5&۷c=ǏgƍDFFrqZ-[n%>>{ ׿^e{777ijjbݺu8>#F#GR5ԩS[oUǽ ֮]Khh(V"88!Ct1qܹÁ7/^f?3&1~ѣGhN8f㫯B_H|Mn6ug݌?gyDVZExx86l %%EMf/w1JQ˴ijh4V\n!JCK$߸raZ #vCh0a̚5e˖qarsstTUU1l0UkѣG?~<<z!Cl2222dߟ#GPYYy'ӧ}deeQ__>>>s=|G z|Zөܹs:t}+++￿օ;>,_~K"HnnnUׯFQ بgڵ>}v҈l6cXYϳvZjl6, ˉ%;;[ݔގGd2|={ é`Ϟ=deeh"vڅ;ͦ V;$--{HHH&L`ҥ;---8,oXVVˤd2+v=%%ѣGҥI&X`YJss3%%%ڊjAvv6,_X^uE*5n' @Nd6 EQ^W͛￯.stpqfɓ'EII zoooV"]XIj.rGGtFaŊDGG1fݮfRzusW׳W-9]Ͼ+l6t:l6ֆ7&M#gklN'N8233h4)߳D"tVEue~ f…Y7Hll,ǎe߾}<466bhhh(>(Gal65Z#--e˖d2]3СCx"3g7lucǎQTTĶmڵA[[555D͛73{. h@lh(--CMζl2xVVVv^x6m̙3PD"|WzYֲzj|I5AVEdXlIåpzQi4.\O<%ϵY缰_qMb[[[]\CUcuww{Anf] Kx3dž x7m;_Vu9u{۽tmܹs<#Qk\euNj#wyj,\P5Q٥ ԹNSͬu>I~X,]u{ܽkµa?c"H$_ǏFS%~nH=䧉L7*H$I/GD"rH$#D"H$)%D"Ha-H$I/G kD"Hz9=z5?BS$D"km[j| /$H$3PEO3O"H$n嚵D"H$ DEAM&$?//?dzV}<ct=Ð!4HՙhQ?7aD"guXp-/ Gw=?8X|QQp{3f=<ޯ߷xC7߄Éi Rn{ 3wwa;_&Uae8B`K$O{pՆW55y%~{0m,?bca@(-_q1cvB&4E$Q޽hX""w%%p(+0PhW!C`Pݻa|q^PhSb/w4! ?+#B(^ {Bf¥K0i|yBXFE $<QHHco\$$=_f_ncԙcD{%Kw+dgsoce }=p8 /O\%rr[ŽŤ- ƎZW]B޽bc.nE8V\UU!&G6Ϟ- ii?uu 7*]r(g^XHx5 %$еD˸>ZQKELU8h/7OKPk||WCtVl9S;q.B'=]edgB{.Ő)4ZQfbvT!PAmvC\أF]$Ac#˿^tUh(qΟBb +!4|NC[,_ӧÔ)bL=e{Xim qMH0rlFkZ[EE:f!@Dmm⼬,q/Nut =:j[q|"+ĸ\< ZQ9L ;vw1q?_ٳ}_ThӧCY$̵\}v$݄K_}w>Mht)|UZE)4IQhϋ{p"ɢ"x">rDhTxM' ,B0?/~m*/6#4#< εD}ᐛ +v^KC@֊v; ㏅o06tBcVxY1ȑB m&&v{oA@ԫ(]'SN!)>5G1ÎYr|MqĞމ[YGJ9n5{ _9VgsmIgR,vVm(l=ӱ@7V#z`ەe?k4e_hhG :Oɬ Oڳ>"s⌈D8|oǗr W *m(=+*~UYkYcCi=Leዣ\|[e=C7c6j {K/ku>k{+?rQE??z$DYcNH8٘u[s7fv*Q5[Uc^YZ c}Sonϳ{euZ5S>Q.6Z$ #: o{8.͌ͫfY66 zzjHx!^}v{kbXOXSN۞@ikcxgz[j.ME UY7̯WV~ \pN0)Gc9p/>1f)B0\aޯu뭟aM]G"[qr_]ui}$Ϭ]//8=:#oƜ&09o7G/ZR*څ`Y cY~Ik;n3[3gPY2$0Jfcmy+~U]gt5[GX_fG5z{.GMӱ*Ĺ9CC%5C{埙اO5fcZCv6B},\wO{lY[WP%b@ Nxc(TnoOzI5z.}d3qO>fKh]2}zBۭz[NDF[[:{Zu,q4H2T;d]g+)r7G},˫?ar/[xxE}szqͫ%U,I絏v~OFѯ{h>?z61(qxW q^OTfe]gȭ;XdSVcۭnhоt7ulJ1[}Oykceٹ}=TyȻ{C Fn5犮V928@㏤S{Nê?1]uO+c9 畹<✫ļ!)˩ߙ.d屄Kk\,~yWZEϳ7'.,cgf:ݬn;?e~{?/IwCˤnrn_lzO@˚Ϲ7;8#)ˊ71 Dn>v0f+Xis+pnv[G~cUx}+,W{C~ݍe@nֽsV龟ROW]NwB=_ҧ㋙@&ns $56b:oĸnc}f7-6)ia<#Yhxex+x0kykUk_oN6eTnWk3q# 3Y(}U6f6\~b|`_?x{":\~5tGCˊÌR?\nkћvk 0卛/vpzSKp*L6Kwoezc_kѢc63mxcu ~5i2{10'kYrEΗOF:Z_Usiٜz_N_~+7wR`:gUٙqnn =Un^vNmVRʨ.`u?ojs]'*e\ퟴirHuXa81cv!ˈNRe/\aXˍ~ZL`7x)5:GԮ:5=-aZ_]̴ZV-_8XgP]\,767޵ބ2bBR$*Q4_T쾚{[%T!h{ߵcRSjo< ]Hҩd>v4W^VOL7f=W_h47WT]Vz5]݆k]}81sj{nRr9ˆ'%(DB'O辩^E&zNnܬe_[i +x/zhὯm װKXMl=[J]tWen5P/ʡupoQҿ Gb1>C}TOI ֶ>s7lJ2r??cf!.p-c$DYYtә[LUCj/M+#}f]>b<ዛ LF~_:G&ٻ_t{ciKuΫwqL9>obߊzQĿYe8ߥ- vrnYngT;E9&_c돧6<0yc~!.G`uV5G1ÎYr|MqĞމ[YGJ9n5{ _9VgsmIgR,vVm(l=ӱ@7V#z`ەe?k4e_hhG :Oɬ Oڳ>"s⌈D8|oǗr W *m(=+*~UYkYcCi=Leዣ\|[e=C7c6j {K/ku>k{+?rQE??z$DYcNH8٘u[s7fv*Q5[Uc^YZ c}Sonϳ{euZ5S>Q.6Z$ #: o{8.͌ͫfY66 zzjHx!^}v{kbXOXSN۞@ikcxgz[j.ME UY7̯WV~ \pN0)Gc9p/>1f)B0\aޯu뭟aM]G"[qr_]ui}$Ϭ]//8=:#oƜ&09o7G/ZR*څ`Y cY~Ik;n3[3gPY2$0Jfcmy+~U]gt5[GX_fG5z{.GMӱ*Ĺ9CC%5C{埙اO5fcZCv6B},\wO{lY[WP%b@ Nxc(TnoOzI5z.}d3qO>fKh]2}zBۭz[NDF[[:{Zu,q4H2T;d]g+)r7G},˫?ar/[xxE}szqͫ%U,I絏v~OFѯ{h>?z61(qxW q^OTfe]gȭ;XdSVcۭnhоt7ulJ1[}Oykceٹ}=TyȻ{C Fn5犮V928@㏤S{Nê?1]uO+c9 畹<✫ļ!)˩ߙ.d屄Kk\,~yWZEϳ7'.,cgf:ݬn;?e~{?/IwCˤnrn_lzO@˚Ϲ7;8#)ˊ71 Dn>v0f+Xis+pnv[G~cUx}+,W{C~ݍe@nֽsV龟ROW]NwB=_ҧ㋙@&ns $56b:oĸnc}f7-6)ia<#Yhxex+x0kykUk_oN6eTnWk3q# 3Y(}U6f6\~b|`_?x{":\~5tGCˊÌR?\nkћvk 0卛/vpzSKp*L6Kwoezc_kѢc63mxcu ~5i2{10'kYrEΗOF:Z_Usiٜz_N_~+7wR`:gUٙqnn =Un^vNmVRʨ.`u?ojs]'*e\ퟴirHuXa81cv!ˈNRe/\aXˍ~ZL`7x)5:GԮ:5=-aZ_]̴ZV-_8XgP]\,767޵ބ2bBR$*Q4_T쾚{[%T!h{ߵcRSjo< ]Hҩd>v4W^VOL7f=W_h47WT]Vz5]݆k]}81sj{nRr9ˆ'%(DB'O辩^E&zNnܬe_[i +x/zhὯm װKXMl=[J]tWen5P/ʡupoQҿ Gb1>C}TOI ֶ>s7lJ2r??cf!.p-c$DYYtә[LUCj/M+#}f]>b<ዛ LF~_:G&ٻ_t{ciKuΫwqL9>obߊzQĿYe8ߥ- vrnYngT;E9&_c돧6<0yc~!.G`uV 4294967295 292 192 1 72/1 72/1 2 2004-11-18T18:30:22+10:00 2004-11-18T18:30:22+10:00 2004-11-18T18:30:22+10:00 Adobe Photoshop CS Windows uuid:4b8bb2f1-3931-11d9-a837-e4edefaee69c adobe:docid:photoshop:7058c517-3929-11d9-a837-e4edefaee69c adobe:docid:photoshop:7797a283-3933-11d9-a837-e4edefaee69c image/jpeg Adobed         $% !1"2AQqBR#abr3ѲCScsd$4%ғD6 1"2!AQBRbraq3#S$4Ccsу ?4R!H"R!H"R!H"R!H"|#TB$E^UTR!H"R!H"R!H"R!H"R!H"4R!H"*v'y1OJW)eN[%]4a<.B"z"|yET Ua>|sk*P'ϊ"zJ07 c*}1i菡?)&J̖5\ÿ/gH yneg@xQS_&R(k|5DVDn6DjH:e'cʾ++>''%,O1;@WE爝.~#z\O2+ iqԞMIQT6,b5_ebD.%gTH/*G4O yjDLyQWҫO0mDؾ`NDI2AUuLȏTd|1*DŕdHI_#Z-Y֒,6O:NRWŀdZg̛"'en?>"R!H)u?pb;"x<_) 4jBQ$ W^ 45*5tڳ"x-l//6vWZJxK|{:ʉ1I!D:vp1X/s5Ytxc003՗fq㑋WTI#@L>̌Vu #"B'm廨XRck) 82 mZ(+ #`*^J/!Pt9T(hر$3V[ Dזg[%ײbb~`=S /[1,Ӷ"Ho'8eV{ j{Su ΨaՌ4ykm)j*c ՛8|gKpX& wC&Xvĩخ*Ө{R||=)R̪v>m4 4( DK""%oU@ f,qbx+7GxIİh>BT_J̨ʷ h7e4Nwx{tM24 m6 (ʡFNqĜIR!H"R!H"R'F>H!&%Q"vTnpU,Sptx4_2Lv\Ori蟂I'>?MTW'SL vh/4wmpdZ=mf2{.>ePR$lZSBzkFfzn+L)B D)D9ae1o$yjDyc74ɴj/E,nFM *"'|ֈL"-5afȱ!4JCG`E }j(W^UrRrm iCU;˚w5]Bx8BᎪ\84θB7u,6L4#u&wKůڪ5b*)q &?ߦNI'4R#>藞C i( *WRAd\i(wǖgXREf4 uzR#,: 5301ĀRի/[JvÆ6 pNpr9,:y +&he_zj;ܿskHiSh&LGX{}`7彐/Mʹh_MO͞vSIHL?-KU'%"_vUϧbijg5UU4VsPB D)B D)B=4"_3./CW`FICm{e9ФIIcsN[Nî)2[1z[B:ƻPB D)B D)B DML~nJĠJ*Ɖ4R$wC%vvH:l dHbElE 7ܩ@MWHRrvN8ㆦ)-~u>$3=D(<%aHEfB/ hɻߚpNXNRR'7eMhTtDE.D*cĉ2H}Y" EI@E_)UP&2 yHupGTEQ>fvZHuwԞC1p6F~%$) + jm$+ꪋwV9Ŏ~"vŲ^|p=Z2.V 1ңNoHaWp3$V1aMn,k$R(ZPsLQ!zFBD P2b-" ZQu/JAb E |̘d"%% J i̊ ed}.ˠyMe ֩Gen:RIctR>FE[Cuzi?h̿1zٽ97c8u;Ӹ[u(69Jh _^ g]r8 pn,#Z!.*%+%1M&vaG HGb ى" YVBHIjHwJ‘ D)B D)U*}ۮ{Eo/jpx4R",_Okݾ*~3e+dȴ7Uվ)B Dz&w3/$LGJ#Ճ^q7*&0&%#8FC6q0KlFF sƚ!\OkYŻ6<_D0[{bf#ҋĽY].:5GG7+1Nj){ ao("%wZi{/r ih5ҜNKq;KVApF (fnNsugF̷2{ R\e2QhLF({OjEQԏALg^03 j͚Ѷ.pYf?:d9XD^h͜{m;ohD|s&#C*j^i$ZI?0=Nb pqiUDo#*.ULHS/2d:Ô(\ }֙֩}+Q ێhS W<2R jimL3㶶ᝍs+ *!S5VIm$ui lZ4N&j6>׌9Ogi(D W!{ jJT{#7í3o[[5*h咍q ДΤ^]mZ/Y| ⵢI3ǚ_un[>MUw2!a qЋ%ŲȪE5"6Zb~#"H[gJrG(3@0qzK &9 <^EUEZ8:cYI?,u "Zr '&:[ 2R)+e'汹TȓOq!# bPL @["'v7P|NSr'h$0SQx<.kL*:C,fބś1DW9Lה綼=صUCi`V璜>e$F'IXip8OFwT/EcI@d‘ D)ËJ1(4Ws+1?4R!Htnݻd:dOG68k y<ɯoUUN3.Ӿ,ff|5U"#}ONz"50jl%FeOꜵͬLmUfO]S5%^p K|VpqSEnbzjnO[ڃf랯t$vAp2xM;Y7#DuN@[QkHtDԚydu'MqUuUDU_/eP@X'KtZ(\HeY;88e9E|1 :N+ЉN(*^yk=@yLa~T4k)rV9Ioh=,)td01`".h 3IOHw5T-Y@J]6ۘ32+y%8i }lKy'Z6_'HkY3Tc1AAGT)AX,iwNRq$9{"2}izŌVD4R!Hs !&x64.bgGd\:iζ,# ;3'EX =q" C2˅"bL8~(G!|;Ѧ@,.P E\`thQ062tY{!rW zCaR1X:$rSQ1ne1e'3de7$~ m`My/\H^,å-R=ns02؊T>#5sdjz窬J 6\W[o,z G"Hdʈ!pys.[|4_C[!?5qYvAN毾U&r~(%GoXhjn0e saom͐&*T8*6Б8N(fBf\eydf#ϐtlXlȔZ-׀D<5xKq*Ivp9%utَncZP QauPTFx 0)fo`}=$M[1l!$QAps@#Tiq@cb6㆐M5qjzy i&;֙,UYƀY~e"Mom5R;͗uJPpKf1vaFa#&_\%e5֙)D`#/dXUzԋkcC5?>-+jyd?1D9q8?ʉ[74l2q|QVڥ=dYƦQne^ vHZ>{y-u4ryVPFjMO$91SpIeAE6-~ūU@pDrՇm0ˎF#n*phn4u`W9>ыbLp>ҟ[SoQɽz5@[%P0)8 @lߎ56RO'^ 3VbѫVS?we})}4ȘN=U<>jFB.j+۠ [MMRRTgMbPGjH,3!,D:lo<۵ؒ7|Bhߑ RmȄtl_5qfC2H&2bjN*U،eaNĪ~݉C'FHT1 ?/{}n\Bo,C"4*I$gPCQA%PA*v5 -(P'L 'GF7I~dX̀'^D ZA@ W٪ G:dxrNdHU=TE5:jƼS22Sh}_b|f*] b`t`N0qds6-km_VB!$F^z_$n.wY {H!69$#)%U2p;~%d-EmR4WB31%֣NBB!Ey*MtuKdڡyxIDc7O94h疮]ctdqϟ>8+h#Ꮁv7^Jl}9II(̋n<9>mqbBd.Oӑ֦ץgu'usn6._f\*XOr81 8AQiGlגM 2&u8 UB$򙏺fpq،a􂡿l̋1=Z D4R!Hgr8[rt #&;>g nfZѷ`zƱpBSQVg<[[MSAj?lշOl<#U U!M?M/CU;u{_ܐmR;iZ]4C%?YשUT"";x~Y[єiQg.]Q|@/}%SO^S;H)rVyg -rIv/gm,U LFiE6dh⣗B DX]nT93%)(-*!BUU_ct}YT4HkV8r~`6zfxc*6"58&edJcH 0k:dޏmC ˩ƕYDդS0Ik1lѕζJ>["~['{`KL:OӖOkS47Z2{cqxyd_7GZ"4"ZCi=+Zx^Au~i\bG,wfי;36ƋIj@MVm1c4nڻ:F̵7hARw4i3]yHR%Qӳ_iW+ai^?ŞɝnR'D$T$/EHg]>\ނxY_F9*:&FԔ tjBYE~d4dF ?(sۉWjcս.6NY (>c;:#cyXp"+6VGDuyU[m0UMǭQfFsyccJ m )6ncmD Hy2EepHi;\,ȭ= ‚3I%Y4@BpI=oW|/_0RӐ{{l,s./'J0/[t!^\(Te_Lw'eN26 Vxδ^0O4R!H]+=+oy겷7z<)GL~+du2 EP 8ESxO"R%uԞϖ',Ѵm: ޲U%EBU}A4,m"Uá܂\̜U(5/Iw|5i9j<^t1cNخ302OHtn\V9>5oA\Ij_)LSO iN1mP=\ڛ?luԒ$)!(D_-iy#2fu}xT,\Ą=kTSN ?ꭲ(Q浯8dՑMǽ,JyC;9} xyh>dPZ\K_Xs(!bj&Wt`t|o˯_˿tΏt5O&o< DT6P7O]¯4Q_Iun&R!H"R%;ݲr\$ 0.d&mEѪ-BZuҫ)PfJ3M,mmj{t{o&&rY: Ȟ_\X\ԌIKS7 Nᛵ%pc2&ti]KGao~7u{6O\!Kܢ73Kϩk9wA1 gCvp9,BGt"+ Zj+'MM2cXRR'4R!H'L6g S6:۸쟇Zg.iZ7לW"vܯ*Wc4DkBj,=nt_KO%w^go9VLğ)<>8~CmI/'mDi%} L@{תRN9Hݵ'ndH8ϲf%GKˤ| ilmS+{5mJee%53y"{j{_f/JT5O{;{SژG~r9>1 &٣ '`c*wܽ*K]}n)ܒ5?͂<-8[`:At.#uV/ ڧMsڰr:St݁xҳf86qTlUUx|Ȏkwx#FC Ma5l=/j 7 msWg7VWy-XrIŔ47epUGKOSo z~X|᪡ɭ|?,γ+6.jA:z&> ^G8TƳU-Wwo(8nY;đD%^pַ i/53EEV],l5puO^08[VP~8rֵ_@8V)} [Z ѩ)321Oa0=W ʨ(ON'1w>XI+傪'\ ~m5jN*W%el`HJ+ں*V'3Re@;1Hx2e/O+WͦxLεON"_3Klgνr*$xR#~=aen0˺]M k0Q}NoHFԐ`_B}w um!Ŧj+V.~zߜeHu]*/a^gzu{ƵJd~nnlwMpZ ıp(ϐ:$. oUx_)Y9suv׾E@)q=f=q;.d"umX/JiW( aA .8[5sAeы Ee«_l_fSޔe$kum &9":zТdžwk[dbjHQWY~c'>ϵىXxh^A&.6=^O)d;-uex+Ui~̒.Q@%RHhzz-SL/g-R#~h*ڂ!H4R!H"g 7^UYK)XE^siq?mW=3e9"\=62ՙ:<o^p~un|Rs9 qm.:S·h[ug7Bq ZW9yv1YhGO Zk ,Yٽm4@KCЕTiX6LFi t--IQ;S[WT Mu[LJc %԰sW_YΉ"' B*jK|.%{FG}ɾv!4D l5i}}5PjZsXS♫{{u([H,aS$+x{rmO0xj֘EϔrAVeqJExFG/ ^ExcֳWmCL7uiYm>2&%D5"D./W 721Qkfn#-x⥕92lKiZl+Z77ӵM{-6Ӹ\:-7JtR'JaD T7ơAd֙uWgDUl?dly8yQ?Q z;FBRݯ i:L^ϊ2g7V6-g glԜwhGeڭv5Mg0n S7klo[vLllTj?(ւ#SKG{H RdϟFrw+6|8t'Vy|blE\ACO!gZz066{@J層yLj7ZvG}Wp[ُt lWPJz j[d =b)S 8 gmΈKc$ǧ7%d;0o)zb n=Cq-1nehO+cTR'41K>F;<4KFn rĬnn鬭x\UPbfmuS%1zQ[﫛9&32F5E%ҏ Nk{ܸʎfmY;sQ &TzJ_{&V~C% $Gya*eGATei:v6u1ʴ)uk7㒎GQ\[a} P=57<ڶIO hl7Mo:IܬNüOCpIm8/WP#N <=/`n4.C)M^MmTj.Jvv&{j^uO>eJn3$;;U|Qըq2Jt˜z-m$ D(uBl~ټv@oRAqxK|kƌ|;㇚4Ã!&D:y?smQQTTWwi-K5VѭQ;._(Q҈ *7>:tWO? 1;&C,dpH$I㬬;'?pLqPNJZdA^H+e/\؄N\lk{2)$S'S.lՊso>_YZk+QZ=_Aݧ|Qm<ũtJ9o6?t_wmP|7 2T#{b۸*4:T tH7]Ѣmvo*ظ(FVm_0aH"yH^iV;&$( Rv#9mH ;!35F`&IJT`1f9VPvJܹ%പ:!**2#Ȧ^':5=u䴢vm~2/;qiQ_<Ҭ)^o;k{u{|~zN{|fp2v";FmGH=q) ^P둛VAlȶ@ӧYV=Z[}m{sqfeD\TG]l.hRfVZ*֨ݯҥ{+s1ǕQ-1ӰMʜDnR3M*iMrY7&@h&*y@І:Ua$0䓏SUj[]{z4 q]S՞q+$-1?pIfˀ} jB  `5ej%jKt6M6%i!Gzs7$k)G"zZ+Id>Q&}R)LՇ'F[Fl"Xq5"`**.USl,1wړ[OvM<Ii#f) b4]=cUêqsJoZfQ1mjOќ?|yh{V.LmLKԹ6Hfbʶ,sKJ4Qq apRum-nMmvd]ot"9l.yw FV3-KWF*Ƨk>YF׽\Oܽ{/J:'ggYq Ɖ6*qxo*'{4dI7[Geo6y IԆ ap{ .$Z݃RNYl)4ٚ2iuv%%3ɋ>9q՘PqX2[n>[+uFQKX,!ӧR1\vdw;ܥVNSʭ џsoĿDϛ?⚯-yz/ueJٔ˴݂f"RDҐc"uMivϻ-N_rVd]ܭ݋ݞ[aJ쑢s{RάB?4R%Uǹ+EQ9*yPغXW?ΛUBaF_JH7̣e,éBB^T8ICF3]qJӗTeJzKw_2qN#U%ֵdq U 4,TYx\@HK5݋LY4Uf9sLq eN*ixJ1a;Ǘ/\4I6iRB_*~\U?WvSDҦ+tU6MG}­N띟y;!3ui;YWIrk2,G'7Ȏ/]kY*S8\$OxUnj}K#?'wgy|> 3c0X%=-Nr(*yj-z2/RUU=oΕ})Lkozɇ'ˮ"4R#v`a2lZ*I4@V1)dZ5 Qv昇sm̞VE5Y }W=z8얗IqLTC 3HlO kKN㓣Nv_|WDkmHe'ȍM}ZQF?7#50Y)$6 "2["%UTժԳShtbO0dnU?dkK"<zߛSIH XQ<¦ D)B D)B D)B D)NNĎ5'a'O),X EN("/DOPztkidТ&<"nY)6EHu42ƭ<ܗj?ڙ mmPpDʊR 1c340beˬO8YUŠ'Y{G»mByd vTK_ڙϑ/?3"x"@nq_Wޏ7ZUe@n8ةj)uU^ګX$S[DDE6<Pt[ȀO7߉g;)_%<‘?4R!Ht q+9KߎO]_Wc[}Ѿ*Y#Zm/nf]q$ݗtΆ*J>E6D+QRӒz5 J^Y7 $v"O-fs~7M& =An?/mw;$9E^i[M":F٨- Cm髼Sz+d_[ۓ0̗!c`lV!ؠT61-ﻪZ4ʃ>;)Ve߻(I`bh'o޽UJbJ0[KlG I4؉v؏_U2SU0ۛ D)Opostfixadmin-2.3.7/tests/simpletest/docs/simpletest.org/images/simpletest-download.png0000664000175000017620000001143711157271050031477 0ustar davidpalepurplePNG  IHDR1m^VPsBIT|d pHYs  ~tEXtSoftwareMacromedia Fireworks 8hxtEXtCreation Time25/11/06b$ZtIDATx}pǿbl Xc9e4G˺i^g˅XN&^Xv&4IkIInb $w /3 k0 w %HllGB2cm!iV/+i3oyvg 4ʌB@ $bAh1 4 AD MC"F!#BӐiH4$bAh1 4 AD MC"F!#BӐiH437C]pa,BC]9t-pؒs,}[2/uZX˗d#ߢ"& uagQ JOb=Z^+'a"yK:O:(/X!\] L> p}[bگpBQtw&(yr.d0?OYA&|žk?*'ap~/=$ɊBGp>zcF>ɬ.Q,ƭh|iAhĄ,tjCIU"[Fr۳/u 1ؗVnˉ/a ~BBFO'svc _s мY ؞o9]+e,#ee,QhZ,i-Hވ ѴC`lK6^AiS3 ¬7bmr!"34+bf1oU|/A!fE|q2 y ЬkB@ $b Q)>CŋfE,d>;; C(Q% u C]ir'# L~5WYovj7 /܏68ϼ __k+S5N_HbQyUha_-KOGƉIoo$vݵ_5Ad(bעu0xQپ)8 _ 7&"7mbZ^#-9,ވ5a_9yfjOmG%"w"SX+Dհo_mvBc؎:rq-N7TPɮB-z#:7,,nbF(]>gb-*_/"}{^ *T1sF|־ޏ *ݹ E7޿>>p Iݤ7h=l6:0!86z>B@ "w"[uDsoe$,10r"} < WiE> '}WXeF7G bI][srX,ދVAŃz/᳘͕~{?8}0H_~󑖲*XʤO`7}.ǨS<7ɑ)v'XsVfϕF]llOJ7|/R I|'k SW)r2+Y[c{ jj"d)X_:Wo^[Fe; 6_7q+!Dz'Dz$1A!y.΁D[}f/FzQgocq%871l~bkIV+/bېN\PpT"=̎U=nЉĎdw"7aԟ(b>]I@r`{5mE ڗ4Phk5(7g,־QâHآd/xmW榤$.?*ٗɉdgv2ߥIL W{> (LJ#\(%q =%a'e撒;#7Cь*xW{'C2YXLm &qk 7T8:L3rҔ\bbJO1EpOBO'y8+I5piliM"bOBa b CdF}?1Jٝqx6&?*YqޝRtB# =Y>m]T,dޑ^pݚa ;q oD!d3=9]kR_T(dbV̝ڦX4vuI~F[,P ވ()iNE"x؊h<ݗ*l_egÙm;,E5wU؂H7#L?/ò mS.L1OhܙmzM$ z`1v|a,ul[3dg[ț*lz;a?k}B%"~ӿfw8Q ļ0(=8ӭI\xDv^\q4";t3>##BЊ} 4 'BW,44$Bp MCA^'BP&F91 4 ebAh4ؕ MCI 4 ' 4ih+A21 4LJBBܬem*[ :AbSJ#,| A",3󛯉"s:6edA=ܝ˰kS/%bSxG={9aBIyFh* ID BK?q'1IENDB`postfixadmin-2.3.7/tests/simpletest/docs/simpletest.org/images/quote.png0000664000175000017620000000115411157271050026631 0ustar davidpalepurplePNG  IHDR(2sBITO pHYs  ~tEXtCreation Time25/12/06pʋtEXtSoftwareMacromedia Fireworks 8hxIDATXߧ0n&dJو=#6 GȚv7M\&/_isGy o9 R&Z,>ZsQAe ﲏ<1>ZZkzXDbD<Qd)eDI>QkQs\ZiSkfӨ@RRtxW3fo%ӽ;[>Ș1c+V`ݺu`6fq3uTJKK>}:,]UsQVVFhh( .l y'hhhkjry"""())A9u"7:lѣ] Pk֬L^xiӦ}|2335kߘn(w{n{1Vnʔ)K|ڹ1L>#GhzA^.6EF0̝;;Jn^}U}]Z.E ׷b+**/… !00P,,,TVZE^~ŋyWڵC!jkk ׿5?<6l 33u>ٳL0u֡鴠tqz="##)++ :]vP\\LMM VFll,Lff&nnnIQQ 0NGee%۷oݝ),,dĉX,Ν;Ǒ#GHHHhXO?G t2d!!!",,=ɓQJljGond6d2B׮]NSSaXӧc00}t`߾}ZtBUU$ >}\Bhll&x^|E|}}xꩧ<..BPPݺuӾ| 8wwwΝ;lj'ѣ֦%%%]vĠArY,K-[`ٸ0jiZZZ:7@||<{/---FV+[nwf$;;=z?|d2F~djj:f̘76KjYӭ[7mi&INN7@)Eyy9&LЂm۶W_ǂ (**b׮]ʕ+QJoYp!QQQ 4UVCIOO >e˖q1 عs'+WCZZZزe}͚5lܸh b'O駟#Gi&nf|dddPVVڵk;^zDGNNL:dz)l6}s,YP ;;9|-[sדrQXt)))),Y9r$J)^uBCCٳX,>}:seĉ5I&vZn+V{dn&{9Ν3;;[[޽{RJ9s(@Md- ڰggѣr-TTT0|p>fϞٳlZR:sCC>кxXVjkkٳgnnn477իygۨM

    ώ;xynn.r6aoKѨOBbb" DGGkCcƌgϞ{ss־ `Ȇw^Nyyy?;NuZd`0h$88~___6mcƌ=Zs9jjjHKK#--nEμypuuL2[o!|׳fC߾})//W^O[Lֹ==؃ڣ|z[ož}}6/bhDZYip<~uZ^'OZ:lذ#Gh"^}>NZmڴt}Y^~e´GVZyꩧ:|AB%AMދzضmiii|QzǛwy'< կa(̟gv}ꫯ9KRi+V+?7v̷s3D駟&&&{;wb4A)vWWWR""GJ)Imm-nnnڢ{OK{vɂ HIIᣏ>/ ''л}rݹ뮻ݻ7>>>(D||-==2:uJ*22R_^uM7UQQfn:U]] R;vLKO:FU{?խ[7kW_}U*::Z?^566{GJطM>]M|8Æ Ӟ򪩩!""竏9Bss3^{-}DKtt4Æ LJp߿?Æ 8PJa6dϞ=_3g裏LCC>>>̘1\T{/jã>JHH=Մh"BBBŅ;vW_1gO ooox/ݻwݝ)S`חoQ[UUUÇ4h^{-Lcc#~~~7)SqF>|6]TTĀ:t(=o]]]MPPƍc֭8p#Gɲeڵ+uuu3p@ F.]pssaÆB@@1l0uFhh(Nb <HBB6m"--pײqFFҥK 0tP; 7Ht:Ռ7yi=麺:V\v}1buu5#F=6 @]]6mɓ,Y$`0?~!{!ZtJ]ݿp!/+˜1c۷8O¨ޣSudh|xLn}} !wpEÏ/&#ZmzxܯnHH}{eKI!Iz.6{z}:g祾,8e[DZihaØ0kItnJ}iv ~DZϱuln/c[8A.s;w fڥ5]3LBO$]\Ce}%1!fB{o/١emQc5fE/2H8^VvfJkGKcofp3 @YCY ;ukG!зL렴5g[oև,u ɺ[oqc̍xtRխU,;Z * =Yubz ݗmPvEӳ=;7H> BB8}tçC{#1({lȉyi4%g29CCb@"}`0ŝI}&ʿ⯼e23?RVGA}cIO4Omß9Rr3i$&%2?Bٻ~paڧXt"FFdݑuxwwvNncbD]OI H Yz#I!I`}zCL` ))\/lfs3n.nŐCxیQo *+6|xC||;RZWʍo[7'2ǽ̣_¾ `jTNUbR$ '`k^R 7-BPPMnE.vw|ybbI J%+86+z&'N&;gP 1n$$_falX{/ۋu! {ci0yŭ aR$BftcR$6n;X(()`d^ 9IqȯgjTBdlXcnfLVYI5dهqAq;:s]cqEڦlXmVl66kkr`Ytoo`Ƨ3ؖB/^4Yh6C yNC]aq7յ+1co  dg3gu:{^j"/2<%&]1W9T|rs()B?Io<6mѝ?Oghz^=uesfn8Zp}0Qu[[Tp[Nm!7sޮޘ&dI޸ םgO^2ׅ_ka9l݊/όxWkb2=,uzԜi=ӪL5M51ZԹs4PJntC15n*S㧶롲..]ZaSU8Yu|&kXw ՗wA:s55!)+/#QZVJau!(HLGvPxzyhC4ZɯT)늉ڈLQMtw;j3%$&WǩS;eǂ ڧq<BȮhκKWbb0yл{oh1`45yuHbp!3}&%88?Ǚӯg?Ln$&V՛'F?C=өiwDG`So{2kK> tP][ w r'," W+ w'yFW(!^!x=d|xvݏnnݨ5_1|\}uŠ7ō177ޣr"/}O'Ɂ 1}acDVXšCL3;qz]]$'˫{^E [ 62/drC d$0 1c֝)IS1sHH|WO|mϒdf@oDFDo +Fw:`GWKjP*d~:8qw!C˜1x-{cmJ+ @O0cbƴϗ !1,X`5k(hSEl#'+OR\:ȫ\֛JJ1||cRSiar1v@~e>V=g@ne. adINVĆ =zgC0Ml+Fo4gjΰf[Q(v"/ugٙo=CUEau!1c-m]![8g[{'QJipalR^g}4ZrjƿE9\rϾbR{~6:s=zE.;Mq7aY9Yvfk3;v_b0dl=3{ލS\ùss|: ~NMS T)ucϙ=4Z9UušB.؇|L05QooUg#*>]U lĊ+ٛ)+$g*g2Pzuב]͆ ]Caw$$HHΤq(UT5U[lۈAA?9.dnsFg=ahéimhinnKkjۮo>Ⰿ--߶Rmiھ ҵԖL<=os#}lUĦmmsc[Wv?[ll6/?ay8};k_shKg4XZַ~jh;}V9ԩsΑc7Wuwm~~__+9fOeƇ3^7k[zgϻ-X;Y!~jmsNmu:C\ h\tޯ3:psʥ eG5Pw6cގ_ow~{yâ ioOj~.9svZ N屷c{8G/)ټ.^ԛ[ӹ_I KEt`ٕcy[{W1z)!850_B`YuG\!nyZ9"BkHEzB }'Bڂu7n6_\!?iYBk!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!k!IB!?|[}-IENDB`postfixadmin-2.3.7/tests/simpletest/docs/simpletest.org/images/simpletest-support.png0000664000175000017620000001254411157271050031404 0ustar davidpalepurplePNG  IHDR1m^VPsBIT|d pHYs  ~tEXtSoftwareMacromedia Fireworks 8hxtEXtCreation Time25/11/06b$ZIDATxy\Sg_EpI\VQVhbqV8WqXS۹Zxۊvܪ+vqkݦh%RhK4r"d`@ p'W?pO~=tBBHG݀ Q`.u;,"%HC'T$%2Hn' ٧`s qod?]!PfW|EC"J<(4|7 ]=Cc0Zk |zOm^ !'1}PUk06}>gx,I e*G$"C`pӸ;~p)zvmW]Lz1UYn%!Wtre;=0P܋]cWa_qdb !ԭS}oXJ ^ĒY[ $6n'NLjGW8պ[O,x+1bt(_:zBkB| o! z oBЮ{86e6!ķbz6syxK6ި~9pf<~bV;^#$@0\b.szB.'\qƎ VOzfFXP(5 _/!uAH!{h4,v\8~܁K!HqwDHCcCp&k<:'+!PvWp RFHte*0Xy]$CHYV㟿YLu%4B?&>i7^ǝ`ݨX$|EP *6 0Bn3j+DAA[5/ yx5Ḧ́+7rv"!ZY}BA]oL'DLHd5 V,ňCWcY"!1Ynvg H .\c'/;3֋bIzAx[ue|ր ?`.S]GWbYB "DbVkB|8(ReWYyiGx(_~Jʚ*,; Gm5'RC!E\d,/ HVK1+Lxh#v^ƭ^!wwvMQh0>J5.WZMS۰u-%"xr|JX|l Z~s׫-= ,0L% E^#PIHi51G)±p߮YxgR Cf^|0J<;h: pQX1|l4_!+ S}~ zDG`DZpI: !3!J\x{d3!Pp8DeMl7d(4ƿ,%[<3p?:C"<ؕD6֞ކqVmr:Ē!3n[6[AO/5cl8tMzp~9OEpze?|[=1w"Db읩[wOogcW=t@a3#qP>!~l5c}8yT_qO?]1uR[H߇1al9|kS+rF #pCl5(zdfqX{zu&^4{;Z.wNoø># IT6!~bzrVNz8!>oC`Pv >& ߆XAy{zsBoC @l-4 rí$¯C3')Q4s_!t¶rڟ!&opzp ,ך?LVrq46]y?ۮxB`l>6b@B$ *+bRLd%Ek߸ \C>]!V,>!:=Ĭ[6%2yTLqyXSW Ym &ƎዚYB~#ڽʚ*? ˕j]B:uLRas!zvD0e] ƈ95 (B$3!jXS[t:1kxVBi!aj?NO"?z UË'"CEg '2tXk!wxC|^ZMB7:%}Oz/ QhB:9g>k쑅j9?EQUP[\˰,! `ځ夹Xp<liGWR%ƯʢMxZd:l;jza!~{x+dj>~<;hd6,!Z0Fۦ'̕[: UtI4Ĭ~xk"k/'\4utS?X#wŚ(]v;p'Pflb5l !tF^J$p̻g64'#א\C>FxPA] ֎ 01v4>CYo#!{X!fqVɐxC #cr !cAX$fI8 "Q!&$E3!'B\pru }Pd1`\yQIuYbtF.5+ĺsY@lHI3;B$8!<4enع,~6!Y%RX W(C$mM{XA@vsr57q5V<yF-\&A.A-Sbbg&?te*29\SIg3b=`G&b)2%2n-]q*UyFm5'D+0YF[nV Կ=x f]ck\qZڠl8q̫-X:l|$r0t.MN'X2d&Ƭ`62c8z<iGW7 .O"DblPg`\3.Bq EK]S&UКtp 9~ӎF-P'kbֆCVf?&ep;&6KgAyڎj=gbʾ%^\w0[)-Y f"ϨncU'F :s`U[_kCϘY8 14 û7-_EsX8ݵVڌ6}wm_Ҏfu4Cl-7h3o:"!Zu>7  4FƁ_NVͫXz" =*iTҤf˕lfh=վ=tLOBl}0ǐv1U_N|6<=ҚuP! ȰAIڪCL #cr{[j̨i(eJ7Op;>\a}m+7xݶZt~)ӸmXyq0E:xb?!@ !:o#xfߖ g{R1[xNG5}* s4%Vc+; {"(|EY@,x:er5TҤ6-.0b׋i!`yV#;5(0Bkx !- bfKHY##mp2m12f`Z1om==-}鶛x1_,}YLBzCwp9^o9{˚-T->%\pVK 'Fǹךt.˱ƻHthcuX8)Șڼ:ڌCIq)O'\BURNxe.ǫuV3o3k`Twʾ%иSakK={E¢codY e-vrg[Zrd5yӶXCO@[͌ cĚh`M Q`.luc{HjoeH%vmf sv 0>IG!DV[I}]6ݶv<LlR4bMd(Sl{`͈\{[lHo(4nמZ@ wH ӥ[r ycWSƂb-e(Sq1s,On5\bR,O[VL~Sg8(-ƊXަHV`Un]%M!ͺV{N" S7cu0$Wf]=U˔O݌ɜ^M} pnrZ@b]k F~=5v;gj6vX.i}ήMܴMSv,HO'O.qAHjH^DHKt;IkbF!FkbF~)$2% !~B(!~B(!~B(!~B(!~B(!~B(!~M(Pf5ZઽBH.C+-f7 TI/?ReC!^;W3N];8 V}w!k^tPY{S/#:G!.+gBU `^$N*k8Kt7t GHD$BN8BQ[ G] հ:WYqΠ&#!U{JmQv ,UQ]W'Q}k!܁DA  Btpz'"Efǹ 1B4ck{IENDB`postfixadmin-2.3.7/tests/simpletest/docs/simpletest.org/images/simpletest-logo.png0000664000175000017620000001535411157271050030632 0ustar davidpalepurplePNG  IHDROo@sBIT|d pHYs  ~tEXtSoftwareMacromedia Fireworks 8hxtEXtCreation Time25/11/06b$ZAIDATx;p暆( 14Ps7p,7JJgG'+#@ќ$MRNL Yxm|4S_8Ǣ Ec:+ *C\o_8cAh?&2T< Xxͅ8|ՈU f8Fb&$Qz"V-Ac)2"5.7m3u^^kA%uYlov*"M$u=9_$ /[PW% xADē "ga{7J|1[, zF|_RHXhɰY i@|=p{;9 dcdxH91 ]jLDr߶_^~^NܧOP:$9/''^^:z"V+{[ĎO /GEf~m1Pq's9\~&$"Q-ϓxm?v,Zϱ 姧$A$i#BadHzK￙U.AxiHq(񟳆^]jDYÊk1Y>{HLADfxx1J3Jlױ4_5j%pxzPCeޯ"gqw-IZs૯~^^k- w+*cyycKM{QvW4 LH=%+ @3-FƟmg- (AL*%]w-|&hG dZ<]@εm:Nf%bsOg0>ۡHAx2-O:׶ۡOb'bωrP!l+55XO3ql{_\ۡO| ֏i,ұ>"4͙:uX/fwUJ#0Ko'pZA0YsoI1rysS b-;; Yd5*w3dGkcu4 w2޼TIs{˥A{F sjy dGBv-z. RNL| ֏f,y7 p>xvhu5jX%y.px:߭2ÏxSb +3Ⱇ[!&Asx~m- _?n'9 X !gxeID$0Jst$b$IxADē "gK/d>Dw2<[\?_b0puu˲X]pQ!8.0S4tt[\F.C'.HǺ!T4H< Ud6TUEӁeYdzA@Z$IBjxOQWC<-' HtS$+@b⹿[I\1cQ|\D3 x m;㫿Uq/#6ga[O5%!p syhJo{|"kĵzRny1p9gT&xBћ"ⰿ[jnqE&AٜrrT*PUh$.0>}%\YcTBV(9@ӴZ @$TP888|X,l4M4͙f2HY&,z~fص /@qׁ⩄0h*^^k7 )'~m!qM.^^kxӂr'ã0j>AⷁqmFa{٭ H}8\.'](6z(wDZE^mh4v+wT*899 .;_?MÏfv=WoZ, H%ULy/}܋_5M/%)sP^7YmeTM؏kQR<'c3 )K' #YC;Lӄas~#xA+,KӁm۩d1ضz}t:u}\8WHbֳ(|[ViBm{?Z~3h4s]TUu|[¼Q^/r$GJnJTd(z4+n8ʁn6 " k#'<, Z .$2rYvo6 t3fSOԯϾp$q _6Kݶ' VeYc[KXWy|hau=k0 iZ"X*.>TU]Ƚ۱ 8|@K>mz :o'$כM, eMY&rJN ݺ'"aEցQ[Юl.]<[FpN^^BC7WB)x>ϗPnj,8I lx6HI.J4aL\WWWܰ<5rqgYqcyu0?۶3DŽPe,+1K9,oOyyc@ReTYuPү?y6Q^^kr[5o6N-~`œ8(؎pppH+hڢ(RV ˻dV*"AAEZw8nxMȲ<ӂT*,jMRõmnX $q;lPw-(殲Osyqq#NvH2qjkgD8Ktyr@I"tr;U1`$"(2gI9ѷ9)8|2IblɐeEcRsލWaFQJ%QXfF`Zo/쇜_XTa{"|7xK= "W>fcYү o:2ۋ|YE)<,9͍77Gmx-jVCVso`nA5 ids b$@ {y ;~Y016"50c匪Js,ēs?ľ1)}yW  f4 J'RC^^7ұo?ݰ|KlYZxNP6w+HA \~W &ҋ&Fom^8a3F˰؋ŢoEgRoO9>Q(|r8T^\w׶]wscœ8z=RUAG:WWW3s=anX~ :vg6vj*Լ >-ܶ۶}z=|gPymf3TeܬF>XDh{4 c妦YoہIC{?NfojmRYlɄsau]$JdY(S4tn"RNĽgВ)vhuBћ;:& Q^^J~g3Y}hUFpNHU %ȇ]e%<~z=<~_}|gc7Yv]Kxax~Xx=jtrκ? ;L7kYn7Y1m+|zr"^E}aY[~)nwe3lwzV=)jL@aAkL~'˷(ò15U2Nݖna5g_Tbut]Ȳqy.͍?jSuA ?'r?.OY 2*.׊xEQ"TgVF< se^wuI&ƈ'0uzz뗄$_gr( YhgϞ=A\"O3?۱Y2SImHDZ$%dY^(3@e'K8Z"pqq*TU EXDU&-_q,ʑJ'w2%;:EڹA.Mعu ܟIz}c@I$BDƝ/5/Teqضs^yQk5#.x:G>|NXё͋,Ob`_ _va SYžXTn,K5v0 v;uAkc#v %$֖Ez>&J%UKs-YySju:ƻ0AK^ɺ7 4QXit]_M?t]1 4Pf7aA֐MABAIl+[Vӑy41,_ۏ|gA4Mm2 jڔ*X7)6¥VM&|Ȳ<Ϗ<3 X,BX#'''rFmh6TU0;c+pMm{Oo\;g!IRyxDHx,QqqqUUazu7o't#VH^U Y^!GH.ǝ!PW^A<&R`\)yo1𿽚w%W:<0Y"[] Fkmˋk93o1O78o|,uO֮gьfIZdAIrTIƞ% ]SP{Vf-! f0mFv2z.&hRky,B֘ƤV[k+4Q.U~<=0~֯ěO|崲o+yJT~_zs7"U*TGUӏLWkvw8ӴO滇Kn, !{q|wi|Gqc,5lNc0p0ֵkIHS+[ďd 98o8Xќt;'wW9|E|E[3ǽ)'86> IalYNG,l;s4!w0'AVoE71 yTsNݩV_g%{1ЫAUMk_N_ǟZ M,pV'n)2*,h 霄 .'AC^q >}/'ein%EI c\/Vi܂DFkpb bޟ|2S6{giMF{HuH&C3ݴy>jVRx&c*kk3ϡJLtl|F7sx#?:Z/Dt~p?+gGf\Ij=?vOkvS0M׷3$PAK,ǀ9'IiFnmq-»<+# }sXYK;5SK#wC19$90sSiJ8Đ_ ?+=.Ɔھ!^+O1e&@JȬF8 +OX'i'hJA9y;U64ֺq\-CjMK;n5{,Ƴh$^c3H'񨘊@N)k2Yu9SM߻.LJf:TJݗVE5M8+Rg4šI(UXCdl@|9u.FrP{O)w+5Sj@x1b8E<qޗA74njD({lt Heƺl6ؐ=lxK2^P DJt>Q!vYYB:~xu\¶3}%ArJ'p#(TN%r@WYjZ~m O8iͫ=16A,$U8sy^~JdV&>ɴ&U8jK7i$(*֡H%Fq^s76I]i @2sRCXKD x:!Doԏιx+\ǷzΪ'afڌ/֋幬2 M&6o;wyO#zǥkk:Y:fG6(on#+g#WN.0s^k_osԫxeԐw9Gg˸[`~OJĸ>Tk/Ҙ(SXWz}jH3}itb8}*i}Ǚ%*X,2zPehgK|˕ d d[{fQ7F S0{u~)G'iTtoNaci3>G 7yhv^ia;l~nrNIdJYN:a3ʊMFY2ww!UqՏ~_ʷPӠ]@\EHo0㍎Np#g`]khא۴Ϻ#,lh=)R~yS#ץOhmD"7Ppz0 U}mzmN wڱهi ;B-/XkR躄bls1CNm>h0 $x;JN/Fto-x-Fz>_"ESSV<1^nfmK:g!y6jVyq G ;NJxgƯLJ֣SR+|K-IuӢ4r(z##s4}&mFCK>BrjjŬ66bI%-)H'OQ]wKA&̠rg.RjZal- IILc H瞕F:=C%X<,}BJγגT,-=];lpS~5['E H8vQ$NpQSnɯUјֽ5cnĖ 1-Sq׊xT#'Ԭ1Civ~GmohLdcq/\Kv=H9um:Gv"*hI_zt дxeW r ZxzܺMpUV1⻳CqxS 3iٟBdqܒx=ZPԭ nH8kd_rzU/TE ibgF2=OxY.xV-d=|,¢t\\]QYeMIKm'nºw}2NOb/FG8TcV ʽů x=UL.$0?YTF^# 육'nœ5QSօd}h s>3ʱ3 D*yi,TN}2Okma7S0 cշ횽w1zXS^~У.FiI 4ۇJFy.>]u uÚhGo>G,=Oj 5i6zm*"hN୵OVU[ODU!ʋ{ڭKF;ppPs8|T]OpΊVݙf>B0l(#u\m]! psΆ!}AC]_Xu)-gAYm3#ؙw6 f$=1VXu X⸌o 3a+R.Ly@=ԷвuUFztݙȐY!HddX1/nIwmI Ʃ:/]8T: 19q,>"-;x$>e𶍦."C2/"U&m*VvB;zԛ)Z-hџqu >Q4"Wp]ʜTz~UqxgI%8K-4waW?Ma}w P8?jqG4_Yw-)w+]p:{ht}E&G$W+5EA + .JفG$Oaz??-_ζe+. (O-Y>߾:q֓S^Z'KLxMv(mnh5OEONYFx2')O]LjB|'̓SZ8ޓ?fw>9|!Ii:̱Gp~*PpX98Nrj.^jW6~ݽ[꩗"F V2)^ndRHHVJmXyd>\Eg~z'븏y?n}m7/f!hu0w+v=2 :͖mk]w#E3Btour0F' $qǠO~cy9^;; >܏H F9'$ j湻bF kb~u5i4H)_tTn*?}H'T 9jz{=b3GJee0?JB KY+M7ݩ-@d`:c i{*wH1kbCLm5{postfixadmin-2.3.7/tests/simpletest/docs/simpletest.org/index.html0000664000175000017620000001635611157271050025530 0ustar davidpalepurple SimpleTest - Unit Testing for PHP

    SimpleTest 1.0.1 beta release is the latest version. It's very stable although PHP5 users will find it doesn't run with E_STRICT : it's still fully PHP4 compatible.

    Familiar with unit testing ? Just dive directly into SimpleTest with the one-page starter and the complete API.
    Otherwise see the ongoing documentation.
    And for example test cases check out the tutorial.

    Need help on your testing strategy ? Feel free to join the SimpleTest support mailing-list.

    If you need some new functionnality in SimpleTest, you may want to look at the features tracker. Also the bug and patches trackers can be useful.

    SimpleTest v1.0.1beta is available for download.

    The SimpleTest PHP unit tester is available for download from your nearest SourceForge. It is a PHP unit test and web test framework. Users of JUnit will be familiar with most of the interface. The JWebUnit style functionality is more complete now. It has support for SSL, forms, frames, proxies and basic authentication. The current CVS code should become the 1.0.1 release real soon now and includes file upload and many small improvements. The idea is that common but fiddly PHP tasks, such as logging into a site, can be tested easily.

    Screenshots

    Here's what the result of your first test would look like :

    test with 1 pass

    Well not quite. In true TDD fashion, you should see a failing test case :

    test with 1 fail

    You may also prefer doing your testing with the command-line :

    test in cli

    Documentation

    While (still) very scattered around different sites, the SimpleTest documentation is quite dense and thorough.

    Other type of interesting stuff while starting out with Test Driven Development and SimpleTest include :

    A couple of books do use SimpleTest quite extensively :

    Contributing

    For translators the documentation is available in XML format : we're always please to add new languages to our code base.

    And while we do try our best keeping this tool bug-free, detecting defects and submitting failing test cases and/or patches can come very handy ! Interested ? Drop by the mailing-list, most things tend to happen there...

    postfixadmin-2.3.7/tests/simpletest/scorer.php0000664000175000017620000006576011157271050021635 0ustar davidpalepurple_passes = 0; $this->_fails = 0; $this->_exceptions = 0; $this->_is_dry_run = false; } /** * Signals that the next evaluation will be a dry * run. That is, the structure events will be * recorded, but no tests will be run. * @param boolean $is_dry Dry run if true. * @access public */ function makeDry($is_dry = true) { $this->_is_dry_run = $is_dry; } /** * The reporter has a veto on what should be run. * @param string $test_case_name name of test case. * @param string $method Name of test method. * @access public */ function shouldInvoke($test_case_name, $method) { return ! $this->_is_dry_run; } /** * Can wrap the invoker in preperation for running * a test. * @param SimpleInvoker $invoker Individual test runner. * @return SimpleInvoker Wrapped test runner. * @access public */ function &createInvoker(&$invoker) { return $invoker; } /** * Accessor for current status. Will be false * if there have been any failures or exceptions. * Used for command line tools. * @return boolean True if no failures. * @access public */ function getStatus() { if ($this->_exceptions + $this->_fails > 0) { return false; } return true; } /** * Paints the start of a group test. * @param string $test_name Name of test or other label. * @param integer $size Number of test cases starting. * @access public */ function paintGroupStart($test_name, $size) { } /** * Paints the end of a group test. * @param string $test_name Name of test or other label. * @access public */ function paintGroupEnd($test_name) { } /** * Paints the start of a test case. * @param string $test_name Name of test or other label. * @access public */ function paintCaseStart($test_name) { } /** * Paints the end of a test case. * @param string $test_name Name of test or other label. * @access public */ function paintCaseEnd($test_name) { } /** * Paints the start of a test method. * @param string $test_name Name of test or other label. * @access public */ function paintMethodStart($test_name) { } /** * Paints the end of a test method. * @param string $test_name Name of test or other label. * @access public */ function paintMethodEnd($test_name) { } /** * Increments the pass count. * @param string $message Message is ignored. * @access public */ function paintPass($message) { $this->_passes++; } /** * Increments the fail count. * @param string $message Message is ignored. * @access public */ function paintFail($message) { $this->_fails++; } /** * Deals with PHP 4 throwing an error. * @param string $message Text of error formatted by * the test case. * @access public */ function paintError($message) { $this->_exceptions++; } /** * Deals with PHP 5 throwing an exception. * @param Exception $exception The actual exception thrown. * @access public */ function paintException($exception) { $this->_exceptions++; } /** * Prints the message for skipping tests. * @param string $message Text of skip condition. * @access public */ function paintSkip($message) { } /** * Accessor for the number of passes so far. * @return integer Number of passes. * @access public */ function getPassCount() { return $this->_passes; } /** * Accessor for the number of fails so far. * @return integer Number of fails. * @access public */ function getFailCount() { return $this->_fails; } /** * Accessor for the number of untrapped errors * so far. * @return integer Number of exceptions. * @access public */ function getExceptionCount() { return $this->_exceptions; } /** * Paints a simple supplementary message. * @param string $message Text to display. * @access public */ function paintMessage($message) { } /** * Paints a formatted ASCII message such as a * variable dump. * @param string $message Text to display. * @access public */ function paintFormattedMessage($message) { } /** * By default just ignores user generated events. * @param string $type Event type as text. * @param mixed $payload Message or object. * @access public */ function paintSignal($type, $payload) { } } /** * Recipient of generated test messages that can display * page footers and headers. Also keeps track of the * test nesting. This is the main base class on which * to build the finished test (page based) displays. * @package SimpleTest * @subpackage UnitTester */ class SimpleReporter extends SimpleScorer { var $_test_stack; var $_size; var $_progress; /** * Starts the display with no results in. * @access public */ function SimpleReporter() { $this->SimpleScorer(); $this->_test_stack = array(); $this->_size = null; $this->_progress = 0; } /** * Gets the formatter for variables and other small * generic data items. * @return SimpleDumper Formatter. * @access public */ function getDumper() { return new SimpleDumper(); } /** * Paints the start of a group test. Will also paint * the page header and footer if this is the * first test. Will stash the size if the first * start. * @param string $test_name Name of test that is starting. * @param integer $size Number of test cases starting. * @access public */ function paintGroupStart($test_name, $size) { if (! isset($this->_size)) { $this->_size = $size; } if (count($this->_test_stack) == 0) { $this->paintHeader($test_name); } $this->_test_stack[] = $test_name; } /** * Paints the end of a group test. Will paint the page * footer if the stack of tests has unwound. * @param string $test_name Name of test that is ending. * @param integer $progress Number of test cases ending. * @access public */ function paintGroupEnd($test_name) { array_pop($this->_test_stack); if (count($this->_test_stack) == 0) { $this->paintFooter($test_name); } } /** * Paints the start of a test case. Will also paint * the page header and footer if this is the * first test. Will stash the size if the first * start. * @param string $test_name Name of test that is starting. * @access public */ function paintCaseStart($test_name) { if (! isset($this->_size)) { $this->_size = 1; } if (count($this->_test_stack) == 0) { $this->paintHeader($test_name); } $this->_test_stack[] = $test_name; } /** * Paints the end of a test case. Will paint the page * footer if the stack of tests has unwound. * @param string $test_name Name of test that is ending. * @access public */ function paintCaseEnd($test_name) { $this->_progress++; array_pop($this->_test_stack); if (count($this->_test_stack) == 0) { $this->paintFooter($test_name); } } /** * Paints the start of a test method. * @param string $test_name Name of test that is starting. * @access public */ function paintMethodStart($test_name) { $this->_test_stack[] = $test_name; } /** * Paints the end of a test method. Will paint the page * footer if the stack of tests has unwound. * @param string $test_name Name of test that is ending. * @access public */ function paintMethodEnd($test_name) { array_pop($this->_test_stack); } /** * Paints the test document header. * @param string $test_name First test top level * to start. * @access public * @abstract */ function paintHeader($test_name) { } /** * Paints the test document footer. * @param string $test_name The top level test. * @access public * @abstract */ function paintFooter($test_name) { } /** * Accessor for internal test stack. For * subclasses that need to see the whole test * history for display purposes. * @return array List of methods in nesting order. * @access public */ function getTestList() { return $this->_test_stack; } /** * Accessor for total test size in number * of test cases. Null until the first * test is started. * @return integer Total number of cases at start. * @access public */ function getTestCaseCount() { return $this->_size; } /** * Accessor for the number of test cases * completed so far. * @return integer Number of ended cases. * @access public */ function getTestCaseProgress() { return $this->_progress; } /** * Static check for running in the comand line. * @return boolean True if CLI. * @access public * @static */ function inCli() { return php_sapi_name() == 'cli'; } } /** * For modifying the behaviour of the visual reporters. * @package SimpleTest * @subpackage UnitTester */ class SimpleReporterDecorator { var $_reporter; /** * Mediates between the reporter and the test case. * @param SimpleScorer $reporter Reporter to receive events. */ function SimpleReporterDecorator(&$reporter) { $this->_reporter = &$reporter; } /** * Signals that the next evaluation will be a dry * run. That is, the structure events will be * recorded, but no tests will be run. * @param boolean $is_dry Dry run if true. * @access public */ function makeDry($is_dry = true) { $this->_reporter->makeDry($is_dry); } /** * Accessor for current status. Will be false * if there have been any failures or exceptions. * Used for command line tools. * @return boolean True if no failures. * @access public */ function getStatus() { return $this->_reporter->getStatus(); } /** * The reporter has a veto on what should be run. * @param string $test_case_name name of test case. * @param string $method Name of test method. * @return boolean True if test should be run. * @access public */ function shouldInvoke($test_case_name, $method) { return $this->_reporter->shouldInvoke($test_case_name, $method); } /** * Can wrap the invoker in preperation for running * a test. * @param SimpleInvoker $invoker Individual test runner. * @return SimpleInvoker Wrapped test runner. * @access public */ function &createInvoker(&$invoker) { return $this->_reporter->createInvoker($invoker); } /** * Gets the formatter for variables and other small * generic data items. * @return SimpleDumper Formatter. * @access public */ function getDumper() { return $this->_reporter->getDumper(); } /** * Paints the start of a group test. * @param string $test_name Name of test or other label. * @param integer $size Number of test cases starting. * @access public */ function paintGroupStart($test_name, $size) { $this->_reporter->paintGroupStart($test_name, $size); } /** * Paints the end of a group test. * @param string $test_name Name of test or other label. * @access public */ function paintGroupEnd($test_name) { $this->_reporter->paintGroupEnd($test_name); } /** * Paints the start of a test case. * @param string $test_name Name of test or other label. * @access public */ function paintCaseStart($test_name) { $this->_reporter->paintCaseStart($test_name); } /** * Paints the end of a test case. * @param string $test_name Name of test or other label. * @access public */ function paintCaseEnd($test_name) { $this->_reporter->paintCaseEnd($test_name); } /** * Paints the start of a test method. * @param string $test_name Name of test or other label. * @access public */ function paintMethodStart($test_name) { $this->_reporter->paintMethodStart($test_name); } /** * Paints the end of a test method. * @param string $test_name Name of test or other label. * @access public */ function paintMethodEnd($test_name) { $this->_reporter->paintMethodEnd($test_name); } /** * Chains to the wrapped reporter. * @param string $message Message is ignored. * @access public */ function paintPass($message) { $this->_reporter->paintPass($message); } /** * Chains to the wrapped reporter. * @param string $message Message is ignored. * @access public */ function paintFail($message) { $this->_reporter->paintFail($message); } /** * Chains to the wrapped reporter. * @param string $message Text of error formatted by * the test case. * @access public */ function paintError($message) { $this->_reporter->paintError($message); } /** * Chains to the wrapped reporter. * @param Exception $exception Exception to show. * @access public */ function paintException($exception) { $this->_reporter->paintException($exception); } /** * Prints the message for skipping tests. * @param string $message Text of skip condition. * @access public */ function paintSkip($message) { $this->_reporter->paintSkip($message); } /** * Chains to the wrapped reporter. * @param string $message Text to display. * @access public */ function paintMessage($message) { $this->_reporter->paintMessage($message); } /** * Chains to the wrapped reporter. * @param string $message Text to display. * @access public */ function paintFormattedMessage($message) { $this->_reporter->paintFormattedMessage($message); } /** * Chains to the wrapped reporter. * @param string $type Event type as text. * @param mixed $payload Message or object. * @return boolean Should return false if this * type of signal should fail the * test suite. * @access public */ function paintSignal($type, &$payload) { $this->_reporter->paintSignal($type, $payload); } } /** * For sending messages to multiple reporters at * the same time. * @package SimpleTest * @subpackage UnitTester */ class MultipleReporter { var $_reporters = array(); /** * Adds a reporter to the subscriber list. * @param SimpleScorer $reporter Reporter to receive events. * @access public */ function attachReporter(&$reporter) { $this->_reporters[] = &$reporter; } /** * Signals that the next evaluation will be a dry * run. That is, the structure events will be * recorded, but no tests will be run. * @param boolean $is_dry Dry run if true. * @access public */ function makeDry($is_dry = true) { for ($i = 0; $i < count($this->_reporters); $i++) { $this->_reporters[$i]->makeDry($is_dry); } } /** * Accessor for current status. Will be false * if there have been any failures or exceptions. * If any reporter reports a failure, the whole * suite fails. * @return boolean True if no failures. * @access public */ function getStatus() { for ($i = 0; $i < count($this->_reporters); $i++) { if (! $this->_reporters[$i]->getStatus()) { return false; } } return true; } /** * The reporter has a veto on what should be run. * It requires all reporters to want to run the method. * @param string $test_case_name name of test case. * @param string $method Name of test method. * @access public */ function shouldInvoke($test_case_name, $method) { for ($i = 0; $i < count($this->_reporters); $i++) { if (! $this->_reporters[$i]->shouldInvoke($test_case_name, $method)) { return false; } } return true; } /** * Every reporter gets a chance to wrap the invoker. * @param SimpleInvoker $invoker Individual test runner. * @return SimpleInvoker Wrapped test runner. * @access public */ function &createInvoker(&$invoker) { for ($i = 0; $i < count($this->_reporters); $i++) { $invoker = &$this->_reporters[$i]->createInvoker($invoker); } return $invoker; } /** * Gets the formatter for variables and other small * generic data items. * @return SimpleDumper Formatter. * @access public */ function getDumper() { return new SimpleDumper(); } /** * Paints the start of a group test. * @param string $test_name Name of test or other label. * @param integer $size Number of test cases starting. * @access public */ function paintGroupStart($test_name, $size) { for ($i = 0; $i < count($this->_reporters); $i++) { $this->_reporters[$i]->paintGroupStart($test_name, $size); } } /** * Paints the end of a group test. * @param string $test_name Name of test or other label. * @access public */ function paintGroupEnd($test_name) { for ($i = 0; $i < count($this->_reporters); $i++) { $this->_reporters[$i]->paintGroupEnd($test_name); } } /** * Paints the start of a test case. * @param string $test_name Name of test or other label. * @access public */ function paintCaseStart($test_name) { for ($i = 0; $i < count($this->_reporters); $i++) { $this->_reporters[$i]->paintCaseStart($test_name); } } /** * Paints the end of a test case. * @param string $test_name Name of test or other label. * @access public */ function paintCaseEnd($test_name) { for ($i = 0; $i < count($this->_reporters); $i++) { $this->_reporters[$i]->paintCaseEnd($test_name); } } /** * Paints the start of a test method. * @param string $test_name Name of test or other label. * @access public */ function paintMethodStart($test_name) { for ($i = 0; $i < count($this->_reporters); $i++) { $this->_reporters[$i]->paintMethodStart($test_name); } } /** * Paints the end of a test method. * @param string $test_name Name of test or other label. * @access public */ function paintMethodEnd($test_name) { for ($i = 0; $i < count($this->_reporters); $i++) { $this->_reporters[$i]->paintMethodEnd($test_name); } } /** * Chains to the wrapped reporter. * @param string $message Message is ignored. * @access public */ function paintPass($message) { for ($i = 0; $i < count($this->_reporters); $i++) { $this->_reporters[$i]->paintPass($message); } } /** * Chains to the wrapped reporter. * @param string $message Message is ignored. * @access public */ function paintFail($message) { for ($i = 0; $i < count($this->_reporters); $i++) { $this->_reporters[$i]->paintFail($message); } } /** * Chains to the wrapped reporter. * @param string $message Text of error formatted by * the test case. * @access public */ function paintError($message) { for ($i = 0; $i < count($this->_reporters); $i++) { $this->_reporters[$i]->paintError($message); } } /** * Chains to the wrapped reporter. * @param Exception $exception Exception to display. * @access public */ function paintException($exception) { for ($i = 0; $i < count($this->_reporters); $i++) { $this->_reporters[$i]->paintException($exception); } } /** * Prints the message for skipping tests. * @param string $message Text of skip condition. * @access public */ function paintSkip($message) { for ($i = 0; $i < count($this->_reporters); $i++) { $this->_reporters[$i]->paintSkip($message); } } /** * Chains to the wrapped reporter. * @param string $message Text to display. * @access public */ function paintMessage($message) { for ($i = 0; $i < count($this->_reporters); $i++) { $this->_reporters[$i]->paintMessage($message); } } /** * Chains to the wrapped reporter. * @param string $message Text to display. * @access public */ function paintFormattedMessage($message) { for ($i = 0; $i < count($this->_reporters); $i++) { $this->_reporters[$i]->paintFormattedMessage($message); } } /** * Chains to the wrapped reporter. * @param string $type Event type as text. * @param mixed $payload Message or object. * @return boolean Should return false if this * type of signal should fail the * test suite. * @access public */ function paintSignal($type, &$payload) { for ($i = 0; $i < count($this->_reporters); $i++) { $this->_reporters[$i]->paintSignal($type, $payload); } } } ?>postfixadmin-2.3.7/tests/simpletest/dumper.php0000664000175000017620000003452611157271050021630 0ustar davidpalepurplegetType($value); switch($type) { case "Null": return "NULL"; case "Boolean": return "Boolean: " . ($value ? "true" : "false"); case "Array": return "Array: " . count($value) . " items"; case "Object": return "Object: of " . get_class($value); case "String": return "String: " . $this->clipString($value, 200); default: return "$type: $value"; } return "Unknown"; } /** * Gets the string representation of a type. * @param mixed $value Variable to check against. * @return string Type. * @access public */ function getType($value) { if (! isset($value)) { return "Null"; } elseif (is_bool($value)) { return "Boolean"; } elseif (is_string($value)) { return "String"; } elseif (is_integer($value)) { return "Integer"; } elseif (is_float($value)) { return "Float"; } elseif (is_array($value)) { return "Array"; } elseif (is_resource($value)) { return "Resource"; } elseif (is_object($value)) { return "Object"; } return "Unknown"; } /** * Creates a human readable description of the * difference between two variables. Uses a * dynamic call. * @param mixed $first First variable. * @param mixed $second Value to compare with. * @param boolean $identical If true then type anomolies count. * @return string Description of difference. * @access public */ function describeDifference($first, $second, $identical = false) { if ($identical) { if (! $this->_isTypeMatch($first, $second)) { return "with type mismatch as [" . $this->describeValue($first) . "] does not match [" . $this->describeValue($second) . "]"; } } $type = $this->getType($first); if ($type == "Unknown") { return "with unknown type"; } $method = '_describe' . $type . 'Difference'; return $this->$method($first, $second, $identical); } /** * Tests to see if types match. * @param mixed $first First variable. * @param mixed $second Value to compare with. * @return boolean True if matches. * @access private */ function _isTypeMatch($first, $second) { return ($this->getType($first) == $this->getType($second)); } /** * Clips a string to a maximum length. * @param string $value String to truncate. * @param integer $size Minimum string size to show. * @param integer $position Centre of string section. * @return string Shortened version. * @access public */ function clipString($value, $size, $position = 0) { $length = strlen($value); if ($length <= $size) { return $value; } $position = min($position, $length); $start = ($size/2 > $position ? 0 : $position - $size/2); if ($start + $size > $length) { $start = $length - $size; } $value = substr($value, $start, $size); return ($start > 0 ? "..." : "") . $value . ($start + $size < $length ? "..." : ""); } /** * Creates a human readable description of the * difference between two variables. The minimal * version. * @param null $first First value. * @param mixed $second Value to compare with. * @return string Human readable description. * @access private */ function _describeGenericDifference($first, $second) { return "as [" . $this->describeValue($first) . "] does not match [" . $this->describeValue($second) . "]"; } /** * Creates a human readable description of the * difference between a null and another variable. * @param null $first First null. * @param mixed $second Null to compare with. * @param boolean $identical If true then type anomolies count. * @return string Human readable description. * @access private */ function _describeNullDifference($first, $second, $identical) { return $this->_describeGenericDifference($first, $second); } /** * Creates a human readable description of the * difference between a boolean and another variable. * @param boolean $first First boolean. * @param mixed $second Boolean to compare with. * @param boolean $identical If true then type anomolies count. * @return string Human readable description. * @access private */ function _describeBooleanDifference($first, $second, $identical) { return $this->_describeGenericDifference($first, $second); } /** * Creates a human readable description of the * difference between a string and another variable. * @param string $first First string. * @param mixed $second String to compare with. * @param boolean $identical If true then type anomolies count. * @return string Human readable description. * @access private */ function _describeStringDifference($first, $second, $identical) { if (is_object($second) || is_array($second)) { return $this->_describeGenericDifference($first, $second); } $position = $this->_stringDiffersAt($first, $second); $message = "at character $position"; $message .= " with [" . $this->clipString($first, 200, $position) . "] and [" . $this->clipString($second, 200, $position) . "]"; return $message; } /** * Creates a human readable description of the * difference between an integer and another variable. * @param integer $first First number. * @param mixed $second Number to compare with. * @param boolean $identical If true then type anomolies count. * @return string Human readable description. * @access private */ function _describeIntegerDifference($first, $second, $identical) { if (is_object($second) || is_array($second)) { return $this->_describeGenericDifference($first, $second); } return "because [" . $this->describeValue($first) . "] differs from [" . $this->describeValue($second) . "] by " . abs($first - $second); } /** * Creates a human readable description of the * difference between two floating point numbers. * @param float $first First float. * @param mixed $second Float to compare with. * @param boolean $identical If true then type anomolies count. * @return string Human readable description. * @access private */ function _describeFloatDifference($first, $second, $identical) { if (is_object($second) || is_array($second)) { return $this->_describeGenericDifference($first, $second); } return "because [" . $this->describeValue($first) . "] differs from [" . $this->describeValue($second) . "] by " . abs($first - $second); } /** * Creates a human readable description of the * difference between two arrays. * @param array $first First array. * @param mixed $second Array to compare with. * @param boolean $identical If true then type anomolies count. * @return string Human readable description. * @access private */ function _describeArrayDifference($first, $second, $identical) { if (! is_array($second)) { return $this->_describeGenericDifference($first, $second); } if (! $this->_isMatchingKeys($first, $second, $identical)) { return "as key list [" . implode(", ", array_keys($first)) . "] does not match key list [" . implode(", ", array_keys($second)) . "]"; } foreach (array_keys($first) as $key) { if ($identical && ($first[$key] === $second[$key])) { continue; } if (! $identical && ($first[$key] == $second[$key])) { continue; } return "with member [$key] " . $this->describeDifference( $first[$key], $second[$key], $identical); } return ""; } /** * Compares two arrays to see if their key lists match. * For an identical match, the ordering and types of the keys * is significant. * @param array $first First array. * @param array $second Array to compare with. * @param boolean $identical If true then type anomolies count. * @return boolean True if matching. * @access private */ function _isMatchingKeys($first, $second, $identical) { $first_keys = array_keys($first); $second_keys = array_keys($second); if ($identical) { return ($first_keys === $second_keys); } sort($first_keys); sort($second_keys); return ($first_keys == $second_keys); } /** * Creates a human readable description of the * difference between a resource and another variable. * @param resource $first First resource. * @param mixed $second Resource to compare with. * @param boolean $identical If true then type anomolies count. * @return string Human readable description. * @access private */ function _describeResourceDifference($first, $second, $identical) { return $this->_describeGenericDifference($first, $second); } /** * Creates a human readable description of the * difference between two objects. * @param object $first First object. * @param mixed $second Object to compare with. * @param boolean $identical If true then type anomolies count. * @return string Human readable description. * @access private */ function _describeObjectDifference($first, $second, $identical) { if (! is_object($second)) { return $this->_describeGenericDifference($first, $second); } return $this->_describeArrayDifference( get_object_vars($first), get_object_vars($second), $identical); } /** * Find the first character position that differs * in two strings by binary chop. * @param string $first First string. * @param string $second String to compare with. * @return integer Position of first differing * character. * @access private */ function _stringDiffersAt($first, $second) { if (! $first || ! $second) { return 0; } if (strlen($first) < strlen($second)) { list($first, $second) = array($second, $first); } $position = 0; $step = strlen($first); while ($step > 1) { $step = (integer)(($step + 1) / 2); if (strncmp($first, $second, $position + $step) == 0) { $position += $step; } } return $position; } /** * Sends a formatted dump of a variable to a string. * @param mixed $variable Variable to display. * @return string Output from print_r(). * @access public * @static */ function dump($variable) { ob_start(); print_r($variable); $formatted = ob_get_contents(); ob_end_clean(); return $formatted; } } ?>postfixadmin-2.3.7/tests/simpletest/expectation.php0000664000175000017620000006676611157271050022672 0ustar davidpalepurple_message = $message; } /** * Tests the expectation. True if correct. * @param mixed $compare Comparison value. * @return boolean True if correct. * @access public * @abstract */ function test($compare) { } /** * Returns a human readable test message. * @param mixed $compare Comparison value. * @return string Description of success * or failure. * @access public * @abstract */ function testMessage($compare) { } /** * Overlays the generated message onto the stored user * message. An additional message can be interjected. * @param mixed $compare Comparison value. * @param SimpleDumper $dumper For formatting the results. * @return string Description of success * or failure. * @access public */ function overlayMessage($compare, $dumper) { $this->_dumper = $dumper; return sprintf($this->_message, $this->testMessage($compare)); } /** * Accessor for the dumper. * @return SimpleDumper Current value dumper. * @access protected */ function &_getDumper() { return $this->_dumper; } /** * Test to see if a value is an expectation object. * A useful utility method. * @param mixed $expectation Hopefully an Epectation * class. * @return boolean True if descended from * this class. * @access public * @static */ function isExpectation($expectation) { return is_object($expectation) && SimpleTestCompatibility::isA($expectation, 'SimpleExpectation'); } } /** * A wildcard expectation always matches. * @package SimpleTest * @subpackage MockObjects */ class AnythingExpectation extends SimpleExpectation { /** * Tests the expectation. Always true. * @param mixed $compare Ignored. * @return boolean True. * @access public */ function test($compare) { return true; } /** * Returns a human readable test message. * @param mixed $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { $dumper = &$this->_getDumper(); return 'Anything always matches [' . $dumper->describeValue($compare) . ']'; } } /** * An expectation that passes on boolean true. * @package SimpleTest * @subpackage MockObjects */ class TrueExpectation extends SimpleExpectation { /** * Tests the expectation. * @param mixed $compare Should be true. * @return boolean True on match. * @access public */ function test($compare) { return (boolean)$compare; } /** * Returns a human readable test message. * @param mixed $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { $dumper = &$this->_getDumper(); return 'Expected true, got [' . $dumper->describeValue($compare) . ']'; } } /** * An expectation that passes on boolean false. * @package SimpleTest * @subpackage MockObjects */ class FalseExpectation extends SimpleExpectation { /** * Tests the expectation. * @param mixed $compare Should be false. * @return boolean True on match. * @access public */ function test($compare) { return ! (boolean)$compare; } /** * Returns a human readable test message. * @param mixed $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { $dumper = &$this->_getDumper(); return 'Expected false, got [' . $dumper->describeValue($compare) . ']'; } } /** * Test for equality. * @package SimpleTest * @subpackage UnitTester */ class EqualExpectation extends SimpleExpectation { var $_value; /** * Sets the value to compare against. * @param mixed $value Test value to match. * @param string $message Customised message on failure. * @access public */ function EqualExpectation($value, $message = '%s') { $this->SimpleExpectation($message); $this->_value = $value; } /** * Tests the expectation. True if it matches the * held value. * @param mixed $compare Comparison value. * @return boolean True if correct. * @access public */ function test($compare) { return (($this->_value == $compare) && ($compare == $this->_value)); } /** * Returns a human readable test message. * @param mixed $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { if ($this->test($compare)) { return "Equal expectation [" . $this->_dumper->describeValue($this->_value) . "]"; } else { return "Equal expectation fails " . $this->_dumper->describeDifference($this->_value, $compare); } } /** * Accessor for comparison value. * @return mixed Held value to compare with. * @access protected */ function _getValue() { return $this->_value; } } /** * Test for inequality. * @package SimpleTest * @subpackage UnitTester */ class NotEqualExpectation extends EqualExpectation { /** * Sets the value to compare against. * @param mixed $value Test value to match. * @param string $message Customised message on failure. * @access public */ function NotEqualExpectation($value, $message = '%s') { $this->EqualExpectation($value, $message); } /** * Tests the expectation. True if it differs from the * held value. * @param mixed $compare Comparison value. * @return boolean True if correct. * @access public */ function test($compare) { return ! parent::test($compare); } /** * Returns a human readable test message. * @param mixed $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { $dumper = &$this->_getDumper(); if ($this->test($compare)) { return "Not equal expectation passes " . $dumper->describeDifference($this->_getValue(), $compare); } else { return "Not equal expectation fails [" . $dumper->describeValue($this->_getValue()) . "] matches"; } } } /** * Test for being within a range. * @package SimpleTest * @subpackage UnitTester */ class WithinMarginExpectation extends SimpleExpectation { var $_upper; var $_lower; /** * Sets the value to compare against and the fuzziness of * the match. Used for comparing floating point values. * @param mixed $value Test value to match. * @param mixed $margin Fuzziness of match. * @param string $message Customised message on failure. * @access public */ function WithinMarginExpectation($value, $margin, $message = '%s') { $this->SimpleExpectation($message); $this->_upper = $value + $margin; $this->_lower = $value - $margin; } /** * Tests the expectation. True if it matches the * held value. * @param mixed $compare Comparison value. * @return boolean True if correct. * @access public */ function test($compare) { return (($compare <= $this->_upper) && ($compare >= $this->_lower)); } /** * Returns a human readable test message. * @param mixed $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { if ($this->test($compare)) { return $this->_withinMessage($compare); } else { return $this->_outsideMessage($compare); } } /** * Creates a the message for being within the range. * @param mixed $compare Value being tested. * @access private */ function _withinMessage($compare) { return "Within expectation [" . $this->_dumper->describeValue($this->_lower) . "] and [" . $this->_dumper->describeValue($this->_upper) . "]"; } /** * Creates a the message for being within the range. * @param mixed $compare Value being tested. * @access private */ function _outsideMessage($compare) { if ($compare > $this->_upper) { return "Outside expectation " . $this->_dumper->describeDifference($compare, $this->_upper); } else { return "Outside expectation " . $this->_dumper->describeDifference($compare, $this->_lower); } } } /** * Test for being outside of a range. * @package SimpleTest * @subpackage UnitTester */ class OutsideMarginExpectation extends WithinMarginExpectation { /** * Sets the value to compare against and the fuzziness of * the match. Used for comparing floating point values. * @param mixed $value Test value to not match. * @param mixed $margin Fuzziness of match. * @param string $message Customised message on failure. * @access public */ function OutsideMarginExpectation($value, $margin, $message = '%s') { $this->WithinMarginExpectation($value, $margin, $message); } /** * Tests the expectation. True if it matches the * held value. * @param mixed $compare Comparison value. * @return boolean True if correct. * @access public */ function test($compare) { return ! parent::test($compare); } /** * Returns a human readable test message. * @param mixed $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { if (! $this->test($compare)) { return $this->_withinMessage($compare); } else { return $this->_outsideMessage($compare); } } } /** * Test for identity. * @package SimpleTest * @subpackage UnitTester */ class IdenticalExpectation extends EqualExpectation { /** * Sets the value to compare against. * @param mixed $value Test value to match. * @param string $message Customised message on failure. * @access public */ function IdenticalExpectation($value, $message = '%s') { $this->EqualExpectation($value, $message); } /** * Tests the expectation. True if it exactly * matches the held value. * @param mixed $compare Comparison value. * @return boolean True if correct. * @access public */ function test($compare) { return SimpleTestCompatibility::isIdentical($this->_getValue(), $compare); } /** * Returns a human readable test message. * @param mixed $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { $dumper = &$this->_getDumper(); if ($this->test($compare)) { return "Identical expectation [" . $dumper->describeValue($this->_getValue()) . "]"; } else { return "Identical expectation [" . $dumper->describeValue($this->_getValue()) . "] fails with [" . $dumper->describeValue($compare) . "] " . $dumper->describeDifference($this->_getValue(), $compare, TYPE_MATTERS); } } } /** * Test for non-identity. * @package SimpleTest * @subpackage UnitTester */ class NotIdenticalExpectation extends IdenticalExpectation { /** * Sets the value to compare against. * @param mixed $value Test value to match. * @param string $message Customised message on failure. * @access public */ function NotIdenticalExpectation($value, $message = '%s') { $this->IdenticalExpectation($value, $message); } /** * Tests the expectation. True if it differs from the * held value. * @param mixed $compare Comparison value. * @return boolean True if correct. * @access public */ function test($compare) { return ! parent::test($compare); } /** * Returns a human readable test message. * @param mixed $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { $dumper = &$this->_getDumper(); if ($this->test($compare)) { return "Not identical expectation passes " . $dumper->describeDifference($this->_getValue(), $compare, TYPE_MATTERS); } else { return "Not identical expectation [" . $dumper->describeValue($this->_getValue()) . "] matches"; } } } /** * Test for a pattern using Perl regex rules. * @package SimpleTest * @subpackage UnitTester */ class PatternExpectation extends SimpleExpectation { var $_pattern; /** * Sets the value to compare against. * @param string $pattern Pattern to search for. * @param string $message Customised message on failure. * @access public */ function PatternExpectation($pattern, $message = '%s') { $this->SimpleExpectation($message); $this->_pattern = $pattern; } /** * Accessor for the pattern. * @return string Perl regex as string. * @access protected */ function _getPattern() { return $this->_pattern; } /** * Tests the expectation. True if the Perl regex * matches the comparison value. * @param string $compare Comparison value. * @return boolean True if correct. * @access public */ function test($compare) { return (boolean)preg_match($this->_getPattern(), $compare); } /** * Returns a human readable test message. * @param mixed $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { if ($this->test($compare)) { return $this->_describePatternMatch($this->_getPattern(), $compare); } else { $dumper = &$this->_getDumper(); return "Pattern [" . $this->_getPattern() . "] not detected in [" . $dumper->describeValue($compare) . "]"; } } /** * Describes a pattern match including the string * found and it's position. * @param string $pattern Regex to match against. * @param string $subject Subject to search. * @access protected */ function _describePatternMatch($pattern, $subject) { preg_match($pattern, $subject, $matches); $position = strpos($subject, $matches[0]); $dumper = $this->_getDumper(); return "Pattern [$pattern] detected at character [$position] in [" . $dumper->describeValue($subject) . "] as [" . $matches[0] . "] in region [" . $dumper->clipString($subject, 100, $position) . "]"; } } /** * @package SimpleTest * @subpackage UnitTester * @deprecated */ class WantedPatternExpectation extends PatternExpectation { } /** * Fail if a pattern is detected within the * comparison. * @package SimpleTest * @subpackage UnitTester */ class NoPatternExpectation extends PatternExpectation { /** * Sets the reject pattern * @param string $pattern Pattern to search for. * @param string $message Customised message on failure. * @access public */ function NoPatternExpectation($pattern, $message = '%s') { $this->PatternExpectation($pattern, $message); } /** * Tests the expectation. False if the Perl regex * matches the comparison value. * @param string $compare Comparison value. * @return boolean True if correct. * @access public */ function test($compare) { return ! parent::test($compare); } /** * Returns a human readable test message. * @param string $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { if ($this->test($compare)) { $dumper = &$this->_getDumper(); return "Pattern [" . $this->_getPattern() . "] not detected in [" . $dumper->describeValue($compare) . "]"; } else { return $this->_describePatternMatch($this->_getPattern(), $compare); } } } /** * @package SimpleTest * @subpackage UnitTester * @deprecated */ class UnwantedPatternExpectation extends NoPatternExpectation { } /** * Tests either type or class name if it's an object. * @package SimpleTest * @subpackage UnitTester */ class IsAExpectation extends SimpleExpectation { var $_type; /** * Sets the type to compare with. * @param string $type Type or class name. * @param string $message Customised message on failure. * @access public */ function IsAExpectation($type, $message = '%s') { $this->SimpleExpectation($message); $this->_type = $type; } /** * Accessor for type to check against. * @return string Type or class name. * @access protected */ function _getType() { return $this->_type; } /** * Tests the expectation. True if the type or * class matches the string value. * @param string $compare Comparison value. * @return boolean True if correct. * @access public */ function test($compare) { if (is_object($compare)) { return SimpleTestCompatibility::isA($compare, $this->_type); } else { return (strtolower(gettype($compare)) == $this->_canonicalType($this->_type)); } } /** * Coerces type name into a gettype() match. * @param string $type User type. * @return string Simpler type. * @access private */ function _canonicalType($type) { $type = strtolower($type); $map = array( 'bool' => 'boolean', 'float' => 'double', 'real' => 'double', 'int' => 'integer'); if (isset($map[$type])) { $type = $map[$type]; } return $type; } /** * Returns a human readable test message. * @param mixed $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { $dumper = &$this->_getDumper(); return "Value [" . $dumper->describeValue($compare) . "] should be type [" . $this->_type . "]"; } } /** * Tests either type or class name if it's an object. * Will succeed if the type does not match. * @package SimpleTest * @subpackage UnitTester */ class NotAExpectation extends IsAExpectation { var $_type; /** * Sets the type to compare with. * @param string $type Type or class name. * @param string $message Customised message on failure. * @access public */ function NotAExpectation($type, $message = '%s') { $this->IsAExpectation($type, $message); } /** * Tests the expectation. False if the type or * class matches the string value. * @param string $compare Comparison value. * @return boolean True if different. * @access public */ function test($compare) { return ! parent::test($compare); } /** * Returns a human readable test message. * @param mixed $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { $dumper = &$this->_getDumper(); return "Value [" . $dumper->describeValue($compare) . "] should not be type [" . $this->_getType() . "]"; } } /** * Tests for existance of a method in an object * @package SimpleTest * @subpackage UnitTester */ class MethodExistsExpectation extends SimpleExpectation { var $_method; /** * Sets the value to compare against. * @param string $method Method to check. * @param string $message Customised message on failure. * @access public * @return void */ function MethodExistsExpectation($method, $message = '%s') { $this->SimpleExpectation($message); $this->_method = &$method; } /** * Tests the expectation. True if the method exists in the test object. * @param string $compare Comparison method name. * @return boolean True if correct. * @access public */ function test($compare) { return (boolean)(is_object($compare) && method_exists($compare, $this->_method)); } /** * Returns a human readable test message. * @param mixed $compare Comparison value. * @return string Description of success * or failure. * @access public */ function testMessage($compare) { $dumper = &$this->_getDumper(); if (! is_object($compare)) { return 'No method on non-object [' . $dumper->describeValue($compare) . ']'; } $method = $this->_method; return "Object [" . $dumper->describeValue($compare) . "] should contain method [$method]"; } } ?>postfixadmin-2.3.7/tests/simpletest/LICENSE0000664000175000017620000006347111157271050020631 0ustar davidpalepurple GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! postfixadmin-2.3.7/tests/simpletest/VERSION0000664000175000017620000000001211157271050020652 0ustar davidpalepurple1.0.1beta2postfixadmin-2.3.7/tests/simpletest/reflection_php4.php0000664000175000017620000000552011157271050023411 0ustar davidpalepurple_interface = $interface; } /** * Checks that a class has been declared. * @return boolean True if defined. * @access public */ function classExists() { return class_exists($this->_interface); } /** * Needed to kill the autoload feature in PHP5 * for classes created dynamically. * @return boolean True if defined. * @access public */ function classExistsSansAutoload() { return class_exists($this->_interface); } /** * Checks that a class or interface has been * declared. * @return boolean True if defined. * @access public */ function classOrInterfaceExists() { return class_exists($this->_interface); } /** * Needed to kill the autoload feature in PHP5 * for classes created dynamically. * @return boolean True if defined. * @access public */ function classOrInterfaceExistsSansAutoload() { return class_exists($this->_interface); } /** * Gets the list of methods on a class or * interface. * @returns array List of method names. * @access public */ function getMethods() { return get_class_methods($this->_interface); } /** * Gets the list of interfaces from a class. If the * class name is actually an interface then just that * interface is returned. * @returns array List of interfaces. * @access public */ function getInterfaces() { return array(); } /** * Finds the parent class name. * @returns string Parent class name. * @access public */ function getParent() { return strtolower(get_parent_class($this->_interface)); } /** * Determines if the class is abstract, which for PHP 4 * will never be the case. * @returns boolean True if abstract. * @access public */ function isAbstract() { return false; } /** * Determines if the the entity is an interface, which for PHP 4 * will never be the case. * @returns boolean True if interface. * @access public */ function isInterface() { return false; } /** * Gets the source code matching the declaration * of a method. * @param string $method Method name. * @access public */ function getSignature($method) { return "function &$method()"; } } ?>postfixadmin-2.3.7/tests/simpletest/user_agent.php0000664000175000017620000003065511157271050022467 0ustar davidpalepurple_cookie_jar = &new SimpleCookieJar(); $this->_authenticator = &new SimpleAuthenticator(); } /** * Removes expired and temporary cookies as if * the browser was closed and re-opened. Authorisation * has to be obtained again as well. * @param string/integer $date Time when session restarted. * If omitted then all persistent * cookies are kept. * @access public */ function restart($date = false) { $this->_cookie_jar->restartSession($date); $this->_authenticator->restartSession(); } /** * Adds a header to every fetch. * @param string $header Header line to add to every * request until cleared. * @access public */ function addHeader($header) { $this->_additional_headers[] = $header; } /** * Ages the cookies by the specified time. * @param integer $interval Amount in seconds. * @access public */ function ageCookies($interval) { $this->_cookie_jar->agePrematurely($interval); } /** * Sets an additional cookie. If a cookie has * the same name and path it is replaced. * @param string $name Cookie key. * @param string $value Value of cookie. * @param string $host Host upon which the cookie is valid. * @param string $path Cookie path if not host wide. * @param string $expiry Expiry date. * @access public */ function setCookie($name, $value, $host = false, $path = '/', $expiry = false) { $this->_cookie_jar->setCookie($name, $value, $host, $path, $expiry); } /** * Reads the most specific cookie value from the * browser cookies. * @param string $host Host to search. * @param string $path Applicable path. * @param string $name Name of cookie to read. * @return string False if not present, else the * value as a string. * @access public */ function getCookieValue($host, $path, $name) { return $this->_cookie_jar->getCookieValue($host, $path, $name); } /** * Reads the current cookies within the base URL. * @param string $name Key of cookie to find. * @param SimpleUrl $base Base URL to search from. * @return string/boolean Null if there is no base URL, false * if the cookie is not set. * @access public */ function getBaseCookieValue($name, $base) { if (! $base) { return null; } return $this->getCookieValue($base->getHost(), $base->getPath(), $name); } /** * Switches off cookie sending and recieving. * @access public */ function ignoreCookies() { $this->_cookies_enabled = false; } /** * Switches back on the cookie sending and recieving. * @access public */ function useCookies() { $this->_cookies_enabled = true; } /** * Sets the socket timeout for opening a connection. * @param integer $timeout Maximum time in seconds. * @access public */ function setConnectionTimeout($timeout) { $this->_connection_timeout = $timeout; } /** * Sets the maximum number of redirects before * a page will be loaded anyway. * @param integer $max Most hops allowed. * @access public */ function setMaximumRedirects($max) { $this->_max_redirects = $max; } /** * Sets proxy to use on all requests for when * testing from behind a firewall. Set URL * to false to disable. * @param string $proxy Proxy URL. * @param string $username Proxy username for authentication. * @param string $password Proxy password for authentication. * @access public */ function useProxy($proxy, $username, $password) { if (! $proxy) { $this->_proxy = false; return; } if ((strncmp($proxy, 'http://', 7) != 0) && (strncmp($proxy, 'https://', 8) != 0)) { $proxy = 'http://'. $proxy; } $this->_proxy = &new SimpleUrl($proxy); $this->_proxy_username = $username; $this->_proxy_password = $password; } /** * Test to see if the redirect limit is passed. * @param integer $redirects Count so far. * @return boolean True if over. * @access private */ function _isTooManyRedirects($redirects) { return ($redirects > $this->_max_redirects); } /** * Sets the identity for the current realm. * @param string $host Host to which realm applies. * @param string $realm Full name of realm. * @param string $username Username for realm. * @param string $password Password for realm. * @access public */ function setIdentity($host, $realm, $username, $password) { $this->_authenticator->setIdentityForRealm($host, $realm, $username, $password); } /** * Fetches a URL as a response object. Will keep trying if redirected. * It will also collect authentication realm information. * @param string/SimpleUrl $url Target to fetch. * @param SimpleEncoding $encoding Additional parameters for request. * @return SimpleHttpResponse Hopefully the target page. * @access public */ function &fetchResponse($url, $encoding) { if ($encoding->getMethod() != 'POST') { $url->addRequestParameters($encoding); $encoding->clear(); } $response = &$this->_fetchWhileRedirected($url, $encoding); if ($headers = $response->getHeaders()) { if ($headers->isChallenge()) { $this->_authenticator->addRealm( $url, $headers->getAuthentication(), $headers->getRealm()); } } return $response; } /** * Fetches the page until no longer redirected or * until the redirect limit runs out. * @param SimpleUrl $url Target to fetch. * @param SimpelFormEncoding $encoding Additional parameters for request. * @return SimpleHttpResponse Hopefully the target page. * @access private */ function &_fetchWhileRedirected($url, $encoding) { $redirects = 0; do { $response = &$this->_fetch($url, $encoding); if ($response->isError()) { return $response; } $headers = $response->getHeaders(); $location = new SimpleUrl($headers->getLocation()); $url = $location->makeAbsolute($url); if ($this->_cookies_enabled) { $headers->writeCookiesToJar($this->_cookie_jar, $url); } if (! $headers->isRedirect()) { break; } $encoding = new SimpleGetEncoding(); } while (! $this->_isTooManyRedirects(++$redirects)); return $response; } /** * Actually make the web request. * @param SimpleUrl $url Target to fetch. * @param SimpleFormEncoding $encoding Additional parameters for request. * @return SimpleHttpResponse Headers and hopefully content. * @access protected */ function &_fetch($url, $encoding) { $request = &$this->_createRequest($url, $encoding); $response = &$request->fetch($this->_connection_timeout); return $response; } /** * Creates a full page request. * @param SimpleUrl $url Target to fetch as url object. * @param SimpleFormEncoding $encoding POST/GET parameters. * @return SimpleHttpRequest New request. * @access private */ function &_createRequest($url, $encoding) { $request = &$this->_createHttpRequest($url, $encoding); $this->_addAdditionalHeaders($request); if ($this->_cookies_enabled) { $request->readCookiesFromJar($this->_cookie_jar, $url); } $this->_authenticator->addHeaders($request, $url); return $request; } /** * Builds the appropriate HTTP request object. * @param SimpleUrl $url Target to fetch as url object. * @param SimpleFormEncoding $parameters POST/GET parameters. * @return SimpleHttpRequest New request object. * @access protected */ function &_createHttpRequest($url, $encoding) { $request = &new SimpleHttpRequest($this->_createRoute($url), $encoding); return $request; } /** * Sets up either a direct route or via a proxy. * @param SimpleUrl $url Target to fetch as url object. * @return SimpleRoute Route to take to fetch URL. * @access protected */ function &_createRoute($url) { if ($this->_proxy) { $route = &new SimpleProxyRoute( $url, $this->_proxy, $this->_proxy_username, $this->_proxy_password); } else { $route = &new SimpleRoute($url); } return $route; } /** * Adds additional manual headers. * @param SimpleHttpRequest $request Outgoing request. * @access private */ function _addAdditionalHeaders(&$request) { foreach ($this->_additional_headers as $header) { $request->addHeaderLine($header); } } } ?>postfixadmin-2.3.7/tests/RemoteVacationTest.php0000664000175000017620000000477011171453612021723 0ustar davidpalepurpleassertTrue($this->vacation->isVacationSupported()); } catch(Exception $e){ var_dump($e); var_dump($this->xmlrpc_client->getHttpClient()->getLastResponse()->getBody()); die("fail.."); } } public function testCheckVacation() { $this->assertFalse($this->vacation->checkVacation()); } public function testGetDetails() { $details = $this->vacation->getDetails(); $this->assertFalse($details); // empty by default (thansk to tearDown/setUp); } public function testSetAway() { try { $this->assertFalse($this->vacation->checkVacation()); $this->assertTrue($this->vacation->setAway('zzzz', 'aaaa')); $this->assertTrue($this->vacation->checkVacation()); } catch(Exception $e) { var_dump($this->xmlrpc_client->getHttpClient()->getLastResponse()->getBody()); } $details = $this->vacation->getDetails(); $this->assertEqual($details['subject'], 'zzzz'); $this->assertEqual($details['body'], 'aaaa'); $this->vacation->remove(); $details = $this->vacation->getDetails(); $this->assertEqual($details['subject'], 'zzzz'); $this->assertEqual($details['body'], 'aaaa'); $this->vacation->setAway('subject', 'body'); $details = $this->vacation->getDetails(); $this->assertEqual($details['subject'], 'subject'); $this->assertEqual($details['body'], 'body'); } } /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ postfixadmin-2.3.7/tests/RemoteUserTest.php0000664000175000017620000000172411171453612021071 0ustar davidpalepurpleassertTrue($this->user->login($this->username, $this->password)); $this->assertTrue($this->user->changePassword($this->password, 'foobar')); $this->assertTrue($this->user->login($this->username, 'foobar')); } catch(Exception $e) { var_dump($this->xmlrpc_client->getHttpClient()->getLastResponse()->getBody()); } } } /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ postfixadmin-2.3.7/tests/RemoteAliasTest.php0000664000175000017620000000406611171453612021206 0ustar davidpalepurpleassertEqual($this->alias->get(), array()); } catch(Exception $e) { var_dump($this->xmlrpc_client->getHttpClient()->getLastResponse()->getBody()); } } public function testHasStoreAndForward() { $this->assertTrue($this->alias->hasStoreAndForward()); } public function testUpdateRemoteOnly() { $this->assertTrue($this->alias->update(array('roger@rabbit.com'), 'remote_only')); $this->assertFalse($this->alias->hasStoreAndForward()); $this->assertTrue($this->alias->update(array('roger@rabbit.com'), 'remote_only')); $this->assertTrue($this->alias->update(array('roger@rabbit.com', 'fish@fish.net', 'road@runner.com'), 'remote_only')); $this->assertEqual($this->alias->get(), array('roger@rabbit.com', 'fish@fish.net', 'road@runner.com')); $this->assertFalse($this->alias->hasStoreAndForward()); } public function testUpdateForwardandStore() { $orig_aliases = $this->alias->get(); if(!is_array($orig_aliases)) { $orig_aliases = array(); } $orig_aliases[] = 'roger@robbit.com'; $this->assertTrue($this->alias->update($orig_aliases, 'forward_and_store')); $this->assertEqual($this->alias->get(), $orig_aliases); $this->assertTrue($this->alias->update(array($this->username), 'forward_and_store')); $this->assertEqual($this->alias->get(), array()); } } /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ postfixadmin-2.3.7/edit-admin.php0000664000175000017620000001136311146027202017002 0ustar davidpalepurple= $CONF['min_password_length']) { $fPassword = pacrypt($fPassword); } else { $error = 1; flash_error(sprintf($PALANG['pPasswordTooShort'], $CONF['min_password_length'])); } } else { $error = 1; $pAdminEdit_admin_password_text = $PALANG['pAdminEdit_admin_password_text_error']; } } } $fDomains = array(); if (array_key_exists('fDomains', $_POST)) $fDomains = escape_string ($_POST['fDomains']); if ($error != 1) { if ($fActive == "on") { $sqlActive = db_get_boolean(True); } else { $sqlActive = db_get_boolean(False); } $password_query = ''; if ($fPassword != '') { # do not change password to empty one $password_query = ", password='$fPassword'"; } $result = db_query ("UPDATE $table_admin SET modified=NOW(),active='$sqlActive' $password_query WHERE username='$username'"); if ($fSadmin == "on") $fSadmin = 'ALL'; // delete everything, and put it back later on.. db_query("DELETE FROM $table_domain_admins WHERE username = '$username'"); if($fSadmin == 'ALL') { $fDomains = array('ALL'); } foreach($fDomains as $domain) { $result = db_query ("INSERT INTO $table_domain_admins (username,domain,created) VALUES ('$username','$domain',NOW())"); } flash_info($PALANG['pAdminEdit_admin_result_success']); header("Location: list-admin.php"); exit(0); } else { flash_error($PALANG['pAdminEdit_admin_result_error']); } } if (isset($_GET['username'])) $username = escape_string ($_GET['username']); $tAllDomains = list_domains(); $tDomains = list_domains_for_admin ($username); $tActive = ''; $tPassword = $admin_details['password']; if($admin_details['active'] == 't' || $admin_details['active'] == 1) { $tActive = $admin_details['active']; } $tSadmin = '0'; $result = db_query ("SELECT * FROM $table_domain_admins WHERE username='$username'"); // could/should be multiple matches to query; if ($result['rows'] >= 1) { $result = $result['result']; while($row = db_array($result)) { if ($row['domain'] == 'ALL') { $tSadmin = '1'; $tDomains = array(); /* empty the list, they're an admin */ } } } include ("templates/header.php"); include ("templates/menu.php"); include ("templates/admin_edit-admin.php"); include ("templates/footer.php"); /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ ?> postfixadmin-2.3.7/INSTALL.TXT0000664000175000017620000001155411522107112015764 0ustar davidpalepurple# # Postfix Admin # by Mischa Peters # Copyright (c) 2002 - 2005 High5! # Licensed under GPL for more info check GPL-LICENSE.TXT # REQUIRED!! ---------- - You are using Postfix 2.0 or higher. - You are using Apache 1.3.27 / Lighttpd 1.3.15 or higher. - You are using PHP 5.1.2 or higher. - You are using MySQL 3.23 or higher (5.x recommended) OR PostgreSQL 7.4 (or higher) READ THIS FIRST! ---------------- When this is an upgrade from a previous version of Postfix Admin, please read DOCUMENTS/UPGRADE.TXT also! If you need to setup Postfix to be able to handle Virtual Domains and Virtual Users check out: - the PostfixAdmin documentation in the DOCUMENTS/ directory - our wiki at http://sourceforge.net/apps/mediawiki/postfixadmin/ There are also lots of HOWTOs around the web. Be warned that many of them (even those listed below) may be outdated or incomplete. Please stick to the PostfixAdmin documentation, and use those HOWTOs only if you need some additional information that is missing in the PostfixAdmin DOCUMENTS/ folder. - http://codepoets.co.uk/postfixadmin-postgresql-courier-squirrelmail-debian-etch-howto-tutorial (Debian+Courier+PostgreSQL+Postfix+Postfixadmin) - http://bliki.rimuhosting.com/space/knowledgebase/linux/mail/postfixadmin+on+debian+sarge (Postfix+MySQL+Postfixadmin+Dovecot) - http://en.gentoo-wiki.com/wiki/Virtual_mail_server_using_Postfix,_Courier_and_PostfixAdmin (Postfix+MySQL+Postfixadmin+Courier) 1. Unarchive new Postfix Admin ------------------------------ Make sure that you are in your WWW directory and then unarchive the Postfix Admin archive (whatever the filename is): $ tar -zxvf postfixadmin-2.2.0.tgz 2. Setup a Database ------------------- With your chosen/preferred database server (i.e. MySQL or PostgreSQL), you need to create a new database. A good name for this could be : postfix The mechanics of creating the database vary depending on which server you are using. Most users will find using phpMyAdmin or phpPgAdmin the easiest route. If you wish to use the command line, you'll need to do something like : For MySQL: CREATE DATABASE postfix; CREATE USER 'postfix'@'localhost' IDENTIFIED BY 'choose_a_password'; GRANT ALL PRIVILEGES ON `postfix` . * TO 'postfix'@'localhost'; For PostgreSQL: CREATE USER postfix WITH PASSWORD 'whatever'; CREATE DATABASE postfix OWNER postfix ENCODING 'unicode'; 3. Configure PostfixAdmin so it can find the database ----------------------------------------------------- Edit the config.inc.php file - or - create config.local.php and add your settings there. The most important settings are those for your database server. You must also change the line that says : $CONF['configured'] = false; to $CONF['configured'] = true; PostfixAdmin does not require write access to any files. You can therefore leave the files owned as root (or a.n.other user); as long as the web server user (e.g. www-data) can read them, it will be fine. The next 'step', is optional. Only do it, if other non-trusted users have access to your user: Depending on your environment, you may want to protect the database username and password stored in config.inc.php - if so, you could move them into the Apache configuration file (which can be set to be visible only by root) using something like the following in your VirtualHost definition : SetEnv DB_USER "postfix" SetEnv DB_PASS "opensesame" config.inc.php would then be able to access these through : $CONF['database_user'] = $_SERVER['DB_USER'] 4. Check settings, and create Admin user ---------------------------------------- Hit http://yourserver.tld/postfixadmin/setup.php in a web browser. You should see a list of 'OK' messages. The setup.php script will attempt to create the database structure (or upgrade it if you're coming from a previous version). Assuming everything is OK you can specify a password (which you'll need to use setup.php again in the future); when you submit the form, the hashed value (which you need to enter into config.inc.php is echoed out - with appropriate instructions on what to do with it). create the admin user using the form displayed. 5. Use PostfixAdmin ------------------- This is all that is needed. Fire up your browser and go to the site that you specified to host Postfix Admin. 6. Integration with Postfix, Dovecot etc. ----------------------------------------- Now that PostfixAdmin is working, you need to do some configuration in Postfix, Dovecot etc. so that they use the domains, mailboxes and aliases you setup in PostfixAdmin. The files in the DOCUMENTS/ directory explain which settings you need to do/change. 7. More information ------------------- As of March 2007, PostfixAdmin moved to SourceForge. For the forum posts and source updates, see: https://sourceforge.net/projects/postfixadmin There is also #postfixadmin on irc.freenode.net. postfixadmin-2.3.7/edit-active-domain.php0000664000175000017620000000261510724535105020441 0ustar davidpalepurple postfixadmin-2.3.7/users/0000775000175000017620000000000012301477470015425 5ustar davidpalepurplepostfixadmin-2.3.7/users/edit-alias.php0000664000175000017620000000653511425362524020162 0ustar davidpalepurpleget(); $tStoreAndForward = $ah->hasStoreAndForward(); $vacation_domain = $CONF['vacation_domain']; if ($_SERVER['REQUEST_METHOD'] == "GET") { include ("../templates/header.php"); include ("../templates/users_menu.php"); include ("../templates/users_edit-alias.php"); include ("../templates/footer.php"); } if ($_SERVER['REQUEST_METHOD'] == "POST") { // user clicked on cancel button if(isset($_POST['fCancel'])) { header("Location: main.php"); exit(0); } $pEdit_alias_goto = $PALANG['pEdit_alias_goto']; if (isset($_POST['fVacation'])) $fVacation = $_POST['fVacation']; if (isset($_POST['fGoto'])) $fGoto = trim($_POST['fGoto']); if (isset($_POST['fForward_and_store'])) $fForward_and_store = $_POST['fForward_and_store']; $goto = strtolower ($fGoto); $goto = preg_replace ('/\\\r\\\n/', ',', $goto); $goto = preg_replace ('/\r\n/', ',', $goto); $goto = preg_replace ('/[\s]+/i', '', $goto); $goto = preg_replace ('/\,*$/', '', $goto); $goto = explode(",",$goto); $error = 0; $goto = array_merge(array_unique($goto)); $good_goto = array(); if($fForward_and_store == 'NO' && sizeof($goto) == 1 && $goto[0] == '') { $tMessage = $PALANG['pEdit_alias_goto_text_error1']; $error += 1; } if($error === 0) { foreach($goto as $address) { if ($address != "") { # $goto[] may contain a "" element if(!check_email($address)) { $error += 1; $tMessage = $PALANG['pEdit_alias_goto_text_error2'] . " $address"; } else { $good_goto[] = $address; } } } } if ($error == 0) { $flags = 'remote_only'; if($fForward_and_store == "YES" ) { $flags = 'forward_and_store'; } $updated = $ah->update($good_goto, $flags); if($updated) { header ("Location: main.php"); exit; } $tMessage = $PALANG['pEdit_alias_result_error']; } else { $tGotoArray = $goto; } include ("../templates/header.php"); include ("../templates/users_menu.php"); include ("../templates/users_edit-alias.php"); include ("../templates/footer.php"); } /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ ?> postfixadmin-2.3.7/users/logout.php0000664000175000017620000000133011146027202017432 0ustar davidpalepurple postfixadmin-2.3.7/users/password.php0000664000175000017620000000420111410232653017765 0ustar davidpalepurplechange_pass($fPassword_current, $fPassword)) { flash_info($PALANG['pPassword_result_success']); header("Location: main.php"); exit(0); } else { $tMessage = $PALANG['pPassword_result_error']; } } } include ("../templates/header.php"); include ("../templates/users_menu.php"); include ("../templates/users_password.php"); include ("../templates/footer.php"); /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ ?> postfixadmin-2.3.7/users/login.php0000664000175000017620000000366711156543230017255 0ustar davidpalepurple' . $PALANG['pLogin_failed'] . ''; $tUsername = $fUsername; } include ("../templates/header.php"); include ("../templates/users_login.php"); include ("../templates/footer.php"); } /* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/users/vacation.php0000664000175000017620000000615611174647540017756 0ustar davidpalepurpleget_details(); if($details != false) { $tSubject = $details['subject']; $tBody = $details['body']; } if($vh->check_vacation()) { $tMessage = $PALANG['pUsersVacation_welcome_text']; } if ($tSubject == '') { $tSubject = html_entity_decode($PALANG['pUsersVacation_subject_text'], ENT_QUOTES, 'UTF-8'); } if ($tBody == '') { $tBody = html_entity_decode($PALANG['pUsersVacation_body_text'], ENT_QUOTES, 'UTF-8'); } } if ($_SERVER['REQUEST_METHOD'] == "POST") { if(isset($_POST['fCancel'])) { header("Location: main.php"); exit(0); } if (isset ($_POST['fSubject'])) $fSubject = $_POST['fSubject']; if (isset ($_POST['fBody'])) $fBody = $_POST['fBody']; if (isset ($_POST['fAway'])) $fAway = escape_string ($_POST['fAway']); if (isset ($_POST['fBack'])) $fBack = escape_string ($_POST['fBack']); //set a default, reset fields for coming back selection if ($tSubject == '') { $tSubject = html_entity_decode($PALANG['pUsersVacation_subject_text'], ENT_QUOTES, 'UTF-8'); } if ($tBody == '') { $tBody = html_entity_decode($PALANG['pUsersVacation_body_text'], ENT_QUOTES, 'UTF-8'); } // if they've set themselves away OR back, delete any record of vacation emails. // the user is going away - set the goto alias and vacation table as necessary. if (!empty ($fAway)) { if(!$vh->set_away($fSubject, $fBody)) { $error = 1; $tMessage = $PALANG['pUsersVacation_result_error']; } flash_info($PALANG['pVacation_result_added']); header ("Location: main.php"); exit; } if (!empty ($fBack)) { $vh->remove(); $tMessage = $PALANG['pUsersVacation_result_success']; flash_info($tMessage); header ("Location: main.php"); exit; } } include ("../templates/header.php"); include ("../templates/users_menu.php"); include ("../templates/users_vacation.php"); include ("../templates/footer.php"); /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ ?> postfixadmin-2.3.7/users/main.php0000664000175000017620000000212111156543230017051 0ustar davidpalepurplecheck_vacation()) { $tummVacationtext = $PALANG['pUsersMain_vacationSet']; } else { $tummVacationtext = $PALANG['pUsersMain_vacation']; } include ("../templates/header.php"); include ("../templates/users_menu.php"); include ("../templates/users_main.php"); include ("../templates/footer.php"); /* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/users/index.php0000664000175000017620000000124511146027202017235 0ustar davidpalepurple postfixadmin-2.3.7/admin/0000775000175000017620000000000012301477471015355 5ustar davidpalepurplepostfixadmin-2.3.7/admin/index.php0000664000175000017620000000006510715711016017167 0ustar davidpalepurple postfixadmin-2.3.7/config.inc.php0000664000175000017620000004154511510167431017015 0ustar davidpalepurple 'admin', 'alias' => 'alias', 'alias_domain' => 'alias_domain', 'config' => 'config', 'domain' => 'domain', 'domain_admins' => 'domain_admins', 'fetchmail' => 'fetchmail', 'log' => 'log', 'mailbox' => 'mailbox', 'vacation' => 'vacation', 'vacation_notification' => 'vacation_notification', 'quota' => 'quota', 'quota2' => 'quota2', ); // Site Admin // Define the Site Admins email address below. // This will be used to send emails from to create mailboxes. $CONF['admin_email'] = 'postmaster@change-this-to-your.domain.tld'; // Mail Server // Hostname (FQDN) of your mail server. // This is used to send email to Postfix in order to create mailboxes. $CONF['smtp_server'] = 'localhost'; $CONF['smtp_port'] = '25'; // Encrypt // In what way do you want the passwords to be crypted? // md5crypt = internal postfix admin md5 // md5 = md5 sum of the password // system = whatever you have set as your PHP system default // cleartext = clear text passwords (ouch!) // mysql_encrypt = useful for PAM integration // authlib = support for courier-authlib style passwords // dovecot:CRYPT-METHOD = use dovecotpw -s 'CRYPT-METHOD'. Example: dovecot:CRAM-MD5 $CONF['encrypt'] = 'md5crypt'; // In what flavor should courier-authlib style passwords be enrypted? // md5 = {md5} + base64 encoded md5 hash // md5raw = {md5raw} + plain encoded md5 hash // SHA = {SHA} + base64-encoded sha1 hash // crypt = {crypt} + Standard UNIX DES-enrypted with 2-character salt $CONF['authlib_default_flavor'] = 'md5raw'; // If you use the dovecot encryption method: where is the dovecotpw binary located? $CONF['dovecotpw'] = "/usr/sbin/dovecotpw"; // Minimum length required for passwords. Postfixadmin will not // allow users to set passwords which are shorter than this value. $CONF['min_password_length'] = 5; // Generate Password // Generate a random password for a mailbox or admin and display it. // If you want to automagically generate paswords set this to 'YES'. $CONF['generate_password'] = 'NO'; // Show Password // Always show password after adding a mailbox or admin. // If you want to always see what password was set set this to 'YES'. $CONF['show_password'] = 'NO'; // Page Size // Set the number of entries that you would like to see // in one page. $CONF['page_size'] = '10'; // Default Aliases // The default aliases that need to be created for all domains. $CONF['default_aliases'] = array ( 'abuse' => 'abuse@change-this-to-your.domain.tld', 'hostmaster' => 'hostmaster@change-this-to-your.domain.tld', 'postmaster' => 'postmaster@change-this-to-your.domain.tld', 'webmaster' => 'webmaster@change-this-to-your.domain.tld' ); // Mailboxes // If you want to store the mailboxes per domain set this to 'YES'. // Examples: // YES: /usr/local/virtual/domain.tld/username@domain.tld // NO: /usr/local/virtual/username@domain.tld $CONF['domain_path'] = 'NO'; // If you don't want to have the domain in your mailbox set this to 'NO'. // Examples: // YES: /usr/local/virtual/domain.tld/username@domain.tld // NO: /usr/local/virtual/domain.tld/username // Note: If $CONF['domain_path'] is set to NO, this setting will be forced to YES. $CONF['domain_in_mailbox'] = 'YES'; // If you want to define your own function to generate a maildir path set this to the name of the function. // Notes: // - this configuration directive will override both domain_path and domain_in_mailbox // - the maildir_name_hook() function example is present below, commented out // - if the function does not exist the program will default to the above domain_path and domain_in_mailbox settings $CONF['maildir_name_hook'] = 'NO'; /* maildir_name_hook example function Called by create-mailbox.php if $CONF['maildir_name_hook'] == '' - allows for customized maildir paths determined by a custom function - the example below will prepend a single-character directory to the beginning of the maildir, splitting domains more or less evenly over 36 directories for improved filesystem performance with large numbers of domains. Returns: maildir path ie. I/example.com/user/ */ /* function maildir_name_hook($domain, $user) { $chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; $dir_index = hexdec(substr(md5($domain), 28)) % strlen($chars); $dir = substr($chars, $dir_index, 1); return sprintf("%s/%s/%s/", $dir, $domain, $user); } */ // Default Domain Values // Specify your default values below. Quota in MB. $CONF['aliases'] = '10'; $CONF['mailboxes'] = '10'; $CONF['maxquota'] = '10'; // Quota // When you want to enforce quota for your mailbox users set this to 'YES'. $CONF['quota'] = 'NO'; // You can either use '1024000' or '1048576' $CONF['quota_multiplier'] = '1024000'; // Transport // If you want to define additional transport options for a domain set this to 'YES'. // Read the transport file of the Postfix documentation. $CONF['transport'] = 'NO'; // Transport options // If you want to define additional transport options put them in array below. $CONF['transport_options'] = array ( 'virtual', // for virtual accounts 'local', // for system accounts 'relay' // for backup mx ); // Transport default // You should define default transport. It must be in array above. $CONF['transport_default'] = 'virtual'; // Virtual Vacation // If you want to use virtual vacation for you mailbox users set this to 'YES'. // NOTE: Make sure that you install the vacation module. (See VIRTUAL-VACATION/) $CONF['vacation'] = 'NO'; // This is the autoreply domain that you will need to set in your Postfix // transport maps to handle virtual vacations. It does not need to be a // real domain (i.e. you don't need to setup DNS for it). $CONF['vacation_domain'] = 'autoreply.change-this-to-your.domain.tld'; // Vacation Control // If you want users to take control of vacation set this to 'YES'. $CONF['vacation_control'] ='YES'; // Vacation Control for admins // Set to 'YES' if your domain admins should be able to edit user vacation. $CONF['vacation_control_admin'] = 'YES'; // Alias Control // Postfix Admin inserts an alias in the alias table for every mailbox it creates. // The reason for this is that when you want catch-all and normal mailboxes // to work you need to have the mailbox replicated in the alias table. // If you want to take control of these aliases as well set this to 'YES'. // Alias control for superadmins $CONF['alias_control'] = 'NO'; // Alias Control for domain admins $CONF['alias_control_admin'] = 'NO'; // Special Alias Control // Set to 'NO' if your domain admins shouldn't be able to edit the default aliases // as defined in $CONF['default_aliases'] $CONF['special_alias_control'] = 'NO'; // Alias Goto Field Limit // Set the max number of entries that you would like to see // in one 'goto' field in overview, the rest will be hidden and "[and X more...]" will be added. // '0' means no limits. $CONF['alias_goto_limit'] = '0'; // Alias Domains // Alias domains allow to "mirror" aliases and mailboxes to another domain. This makes // configuration easier if you need the same set of aliases on multiple domains, but // also requires postfix to do more database queries. // Note: If you update from 2.2.x or earlier, you will have to update your postfix configuration. // Set to 'NO' to disable alias domains. $CONF['alias_domain'] = 'YES'; // Backup // If you don't want backup tab set this to 'NO'; $CONF['backup'] = 'YES'; // Send Mail // If you don't want sendmail tab set this to 'NO'; $CONF['sendmail'] = 'YES'; // Logging // If you don't want logging set this to 'NO'; $CONF['logging'] = 'YES'; // Fetchmail // If you don't want fetchmail tab set this to 'NO'; $CONF['fetchmail'] = 'YES'; // fetchmail_extra_options allows users to specify any fetchmail options and any MDA // (it will even accept 'rm -rf /' as MDA!) // This should be set to NO, except if you *really* trust *all* your users. $CONF['fetchmail_extra_options'] = 'NO'; // Header $CONF['show_header_text'] = 'NO'; $CONF['header_text'] = ':: Postfix Admin ::'; // link to display under 'Main' menu when logged in as a user. $CONF['user_footer_link'] = "http://change-this-to-your.domain.tld/main"; // Footer // Below information will be on all pages. // If you don't want the footer information to appear set this to 'NO'. $CONF['show_footer_text'] = 'YES'; $CONF['footer_text'] = 'Return to change-this-to-your.domain.tld'; $CONF['footer_link'] = 'http://change-this-to-your.domain.tld'; // Welcome Message // This message is send to every newly created mailbox. // Change the text between EOM. $CONF['welcome_text'] = <<= 1.2, set this to yes. // Note about dovecot config: table "quota" is for 1.0 & 1.1, table "quota2" is for dovecot 1.2 and newer $CONF['new_quota_table'] = 'NO'; // // Normally, the TCP port number does not have to be specified. // $CONF['create_mailbox_subdirs_hostport']=143; // // If you have trouble connecting to the IMAP-server, then specify // a value for $CONF['create_mailbox_subdirs_hostoptions']. These // are some examples to experiment with: // $CONF['create_mailbox_subdirs_hostoptions']=array('notls'); // $CONF['create_mailbox_subdirs_hostoptions']=array('novalidate-cert','norsh'); // See also the "Optional flags for names" table at // http://www.php.net/manual/en/function.imap-open.php // Theme Config // Specify your own logo and CSS file $CONF['theme_logo'] = 'images/logo-default.png'; $CONF['theme_css'] = 'css/default.css'; // XMLRPC Interface. // This should be only of use if you wish to use e.g the // Postfixadmin-Squirrelmail package // change to boolean true to enable xmlrpc $CONF['xmlrpc_enabled'] = false; // If you want to keep most settings at default values and/or want to ensure // that future updates work without problems, you can use a separate config // file (config.local.php) instead of editing this file and override some // settings there. if (file_exists(dirname(__FILE__) . '/config.local.php')) { include(dirname(__FILE__) . '/config.local.php'); } // // END OF CONFIG FILE // /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ postfixadmin-2.3.7/motd-users.txt0000664000175000017620000000041010715711016017114 0ustar davidpalepurple
    === Announcement ===
    This is a new version of Postfix Admin.
    If you have any questions please direct them to the Site Admin
    === Announcement ===

    postfixadmin-2.3.7/main.php0000664000175000017620000000155311146027202015713 0ustar davidpalepurple postfixadmin-2.3.7/images/0000775000175000017620000000000012301477471015532 5ustar davidpalepurplepostfixadmin-2.3.7/images/postfixadmin2.png0000664000175000017620000000363510601151304021017 0ustar davidpalepurplePNG  IHDR2HŧbKGDC pHYs  tIME 2(ytEXtCommentCreated with The GIMPd%nIDATxwEG!Q`DQA E %؈"79"JXP)B $A w( J?wɲ7y_i;;|e恢((((((((((((r撣CZ 8SgXcʽ6G:5T P(*'U6\R $#11os5PTcfi3Rݳ?H+aQ21|g뀺}`Om6]^` RԿ/:Hg?]q$*r,(3 x8΄cZẀzҏ}2&mU_b5>&XkW"Ƙ:@0o=h!=@Bk푸ϊٟN2f;k̜J(\l-  LI0Hom=O8>։̳n29@#k3p4U!h}3<!8dH#B <2kLYƆFp6"ZoL!eZq*`$lh.9p+RθBy>!HD+5_P珈Ȼ!VC &Hkm6=k|C@u1=&?VN ^ԋ/ZIIz)=Pܖ:29\'m7%8F{R7BG~}yF2(Y9cie{k26/qbRT.;_`>l],՜6l=&mZ|`  ,ky7Ƹ=aW$fQ-e19my{@.K>pܐuQf[̴c+(<|Yf~'71wO 9?yOŽfSqv!KVdXQz1*6_H(3- ]H#UO fpWi3h$߾r+cE=kX3$(W0h [q-iy1]ɠ)컿Qf}~p#`bVG|< RIDpkHzU21~*( ,+7-)ɉ_uٿ( 0yW2(dY5bcv&40qVEc O1މ?Y<{=VEc?+F>x$h{ÿ3owVvR>z[`قwH"lޕ fC`yDML(_ZMi,[Apn po -oLt ^( /&<35v򥝇=dR((8E[TfU^ <Huw6 }u~1f $A%wgޙ"`<޾YT}pʵK40:7x'$I_/C7Kwu|2ZKv9E8ޟc֖X-^tb*JjLEQT0ESQLEQEQEQEQEQEQEQEQEQEQEI;>μQ"~GIENDB`postfixadmin-2.3.7/images/logo-default.png0000664000175000017620000001030510757370236020625 0ustar davidpalepurplePNG  IHDR2hsRGBbKGD pHYs  tIME>(tEXtCommentCreated with The GIMPd%nIDATxyUe?3C"ɮ b) 䖖YZ()J*+* *,pf=3s;sgaxs{.[Þx@+`+~f S;WM m@`pG0D4X0?w&gG)(`6U#ڢxLdOdf= =^UXom,Sssw4*;0A>P`pf :I8VXs}"y8烩/.N:DC(jx}?ϽSL((i|,,`S~_/h¡.QŃ"R3ri[o0`K:Fe̖ sfP SzN!Ө^ ^UO}WlkfC2+ pO,3| )ŢD6Xݿx8X&3$ؔi9Y3JԻZcG0gj C_eHkOQ9v}WȞj|-"?\W]ipQ]N9g&L*oM '\=ﯬ^0J1Mᅭi#J<z`K=k} zT2}V3Lh:Y!|\N~] ʯIL&P _}Ȍ*O@,"AZ,w>f8,Mq2&5t\  Ͳ*kXϕY^`9(<`\̱GԨ3@?OwQ׏&dbxIܼ8,>!08\tR>&4 i H&h%Cv_ү?Vrg^"B#wVR[EXt\c|cb %P)w` aܘ46I |ןc+:Lɥf BTB4Oa{iKsXH8]N,XP5L,CwL+3]fEџroѼ<˛y0eP,P/?[G8j>F;N,3grEIi` W $i @eQDEQѭ&eժʘvGpobYl&<c,ii=[|;5x;=c??;zGòI H Tsjk{e "R$<;,i_zLY"50R)"["+5U1|}dX? ^6*=nJf.4|loہ%](EQ1Ǚ|!w=WK1)nfT4.jR5"e9u _ҐP[N R[hvWH =>s֩߄^g)1ک?Ė\!/^"f-$ vFLX/D47Ո6Fl:YE`7R5ao~9*O"gu9gezR77gT0Uil̟AfTE ys5Hiȅ>/װ޳*Iȝ\|G AfTI;,ʳ-D$I`[/S&R0XLoio'!)u||AC18Y md// >XG(]MD<)Z/P3xTw` ?_>!x ^ZJ,~Tf]Er2ep?`YomrJ=2P'f0p'1P0GtI& *La?A#[9='t51gPu@01"LR#R=4Vd0ץt.*FbԹнBR1Cr15AT/gHJN8E X_.qn*¢mѭ $LU5wZY 8L#hEHʰ(G%D&2B ż<{6ozF2cy:һge0s.B~9Qm#};&Wqk!uLD߱ gF/7 "+\FIp:}{Y ܗyUvaܧ>y0g|%RW#ȗdxI.LǰBzEHG )D c, Ϩ}KX\Qviƿ$INmXF,D@ M"򰉃u㱈jl*<[3Vq;G=8DO` 5)2҅/%m) ө3>ꌳ7`} w˝VmCH>*S2~)"6rX>u"Ve5EP}?}#/B0 TTձw26?j QO#VdHSEJa!.zWh[&RwY':R5fgKI3̙X$P"%Udv(vƢCe z9Ddq|?$Wb?D4Ke_884rrYeB`asS& l $IM:넥/dz,{$E0884B w`b< 9u,)67!,Ru3sQ,T;D{XC̩]W,YT!Ӥ2SzdXcױlWStTXXz6z,;%,ǡNBS5aS0-0j4ޕe|$jX%Xdy̑Q*/ϚXŮl ,_l+kʄ:Zs.2leEf[0x,"WM eJ: ,]{: )*:H[0)m Єq{#;Z/1Kraٚo`94'MsEtlYX2k1m3)R٠jW{'K 'Ų/K7lm|>J]`FX;dNX[|ʱeƦD+V{&:cka#0$^Xdh3\ϱV`Iz.aKEPs%4P}KO`N) .]dd:Q\;888888Oj[IIENDB`postfixadmin-2.3.7/images/arrow-r.png0000664000175000017620000000062710601151304017617 0ustar davidpalepurplePNG  IHDRa^IDATxO@h`X@ݚŸ/N[&4pR|w{16ay]FDQ+i4|fAk1q]ץV8'Qn+B~ߧ}f3g:2ͨ[bEk|>gm| &L&V$ s C[(A@)1DR*rΪzIENDB`postfixadmin-2.3.7/images/postbox.png0000664000175000017620000001041110601151304017714 0ustar davidpalepurplePNG  IHDR00WbKGDC pHYs  tIME ,(tEXtCommentCreated with The GIMPd%nmIDATx՚}Te?3  B`'hu _SC(c˩\°SڋV̎edzB` 0 0/l5ng|gu]#B~&^RZZz*~)'VKKK ˖-رc>~~~S^z_R:kPo)05,\oI<<YYYB׋ӧO뱫hhh*J,_\?~\L&t:y%fϞ- `ٰAO!())/^q^GL6MF#/_.^}ի:jZ$&&41a%j6lk֬&IՉaJӧÇIII`0ʕ+qqqc6t(ݯd2Opҥĥzϟϒ%K`ƍ3yhW_}%1P\\Ljj*{~x*++b0qD֯_餠ŋsNzzz~ҩ* A`` !z=r h4-ZĬY\t8V^&ɓ'餺O?fΜIFFƈd2Z{aZbh".\|Yj 1͌3w} &R0͜zTWWGUU8~~~h4d2t:X~=o6;`و෿-/^`00gOUU |{=Μ9Cdd$ׯ6mmm!B/F^ZrT* ATT*BpEj5K.DGGιs(++#..f)(( ++۷̙34773<<̄ ())]vwuG!&&ӧOc6B faZ900nvrp\ K!ga͚5,YoPL&O>$ƍGHHT*^jZ R+(Jq_('N`3zh.\a$&&r233h4ȇ?ɔ)SzYh$22pJb\~n7B.\ȦM0qFƎ;CVV[n_dҤIcyב,XcjzF#mmmh4tt̙CVV Ǐs1T*7 hZr9ҎpnX`&NIf1csCɜ9sԩS:u[oD\.*Hhll{^W\Ne˖T*HNNvcXp8Ft:zBBBFWww7'O߲i&N<I,//^Nee%111KUU ~dddۋb!**oNO?w}=+1m۶jHOOd21fF%=I]]'N/ .ȁ|tiooȑ#?~???fϞMvv6gϞ\p3gb2X,%B_믿Pٿ;#d<38IMMJ;F?45xJ%TTT`69<: :?>GSN1ahkkC^?_jyoo/fv-5l r!qm޼y/X,رcZ~krQ>v;SLaҥl6?R$99(p\qN'*jG%$$ɝwNLLu [3}t1477Fpp0DFFJKtt4mۮBs̡!FɓyIIIn= K%664ni?EEE;w۷_9|0%%%\.MƊ+9s?}JAAL\, ۷SNa2;wZkZ(,,O^Ioʕx;n81o}8t萘1cƍC [QXX(M&l6mXDnnL&q-X`8|뭷bZ f믾$!@&ICn~z̚5Gb2ɜ={X"##BϞ={lP__M7ĨQ$IV,X_r 1chiiAT?tvvEYY'Oǃje׮]7]#yIENDB`postfixadmin-2.3.7/images/arrow-l.png0000664000175000017620000000055310601151304017607 0ustar davidpalepurplePNG  IHDRh6sRGBgAMA a cHRMz&u0`:pQ< pHYs+IDAT8O1 0 :uruq̒%t"T,dH?zF`w/g."+ dE]A''XkAAVdhuUU5MCVK4 8 CVBl|eLK)%B7i L 6r=!X=9gI[kYhǵ"4A'ʁ~l jwxo9zIENDB`postfixadmin-2.3.7/images/postfixadmin2.xcf0000664000175000017620000001507110757370236021033 0ustar davidpalepurplegimp xcf file2BBS gimp-commentCreated with The GIMPgimp-image-grid(style intersections) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches)  A2box     v2 2 B R b r]<ʐ;989998============!  yF<Ǘ;5:~q9ğ~7ğI6ğ~C({ǩ\ğh'^ŸVT%"a#@vN~do;$/aw(/'~~.$sMq~jO&#,3~j R  m5~/$#ŪC~"iY|$~U_srO^~:;^e@۹~n{~BNͽ]R}q'~^f\pynƽbIYTּ~fjx\RRJβye^Cc~vSl]I>R 8Էf_XD/ܫ~Hb>fnD'bߨa_ҽ{th\I4]|~}ɛ4Op5NT!}ՠfμxgUF4$p~ͼ\z~$UP0?!Y@п}tZC/$j|tӢFt]Lh6"@N˻|n`ZM1%pwƓ:p‚7m?:>QԀ}ȷw`Q?',ۘ|/re)aq+ ԰NͼveUC%6TgCq)mF#QFVF˻}ohV;%FJgd6_&bx5(!YfƸoe_S>'GjuJPi-mQ'TQIєmtdVE5#GjXݱQ=c)\x<. ,ܻsne[^TD4Kk{?oW+lZ&DT$ ~};7ktg^P<20!OXqݖBJa$MvL#e37QYB5$AykZIɨQ/ib%6P4 {ep7I|dFb̀7Vd+EhL$pyn~njtOIOǺ{fРO2hf0%C6xϗ>*o](_g.:d^,ӓU! zΉ[Diu900ϕ7 TȦkBHL; cU T"Iƍ?&&ٰx0o怩"'ʮJ!RqP?Ŋ kӺJ#RN+\ &M"ۇ􈇊|&}AvҺU)Zj6+b_            F # !.      +gimp-text-layer(text ".") (font "Bitstream Vera Sans Bold") (font-size 28.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "en-us") (base-direction ltr) (color (color-rgba 0.890196 0.111711 0.111711 1.000000)) (justify left) (box-mode dynamic) (box-unit pixels) w ! ! kkkO\ admin      /gimp-text-layer(text "admin") (font "Bitstream Vera Sans Bold") (font-size 26.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "en-us") (base-direction ltr) (color (color-rgba 0.494118 0.494118 0.494118 1.000000)) (justify left) (box-mode dynamic) (box-unit pixels) \  5\ G~~~]:::::$kLJ"?H؁ h{ _~ .  kp3 /QDC>?  mmo#sK""$ (  !" 9kkq .QBB  ME~~~N9ߏy  u? r#%.f postfix     9 1gimp-text-layer(text "postfix") (font "Bitstream Vera Sans Bold") (font-size 26.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "en-us") (base-direction ltr) (color (color-rgba 0.000000 0.000000 0.000000 1.000000)) (justify left) (box-mode dynamic) (box-unit pixels) f 6f J+:::Aۈuv kФk$ ii   ~  ECP1ih0s )Unm ""()tV-R8IJ""()NslkCBP2hg0ڑZ0]  ~ ij +E܉vw"eӡM%::::nj     IH59ik./ XQ  32Empty Layer#1     2r22            lllls9 2 Background     22!-2            lllls9 postfixadmin-2.3.7/images/arrow-u.png0000664000175000017620000000055510601151304017622 0ustar davidpalepurplePNG  IHDRh6sRGBgAMA a cHRMz&u0`:pQ< pHYs+IDAT8O0?KSSX ! Cv!a CS}]{reIdY=Vks~˟$P1FeYVU3NBAHEQ}?Xx n&;9FTSaP}5t`[@kvY0&mK2l:4 jC 1rtY+=65~;|o9)NIENDB`postfixadmin-2.3.7/images/postfixadmin.png0000664000175000017620000001364410601151304020736 0ustar davidpalepurplePNG  IHDR2(e[gAMAOX2tEXtSoftwareAdobe ImageReadyqe<5IDATx̱00U\AUe&X{Owۖ I9#X.\LYiii7o>qϟ?0/_Lq3 pb 0R,ii˗/sqq=zׯd'`=1 & Yo޼9_`` y(f}o߾ s155 Q@ @LǏ iӦM2p4G@Q3վz@77֭[###mmmW\ l(" S `z|޽ `lڵa= !77={\p֭[׮]3\__6Xrȑɓ'e;⣀r@ĦZh`Q+++ CUUx=D]1`Db8p7GS(  bS ,\,,, 'NȻw|x~hp"ܮCeggUqqqmyy9=L@q`d ԕiHGm@H47w\uu4 7$$DXXŋJ+22Ç@q7/POXXXeΝ;uuuoqqq!G(B^^0ET`!Ԅ\_x(h€_zpB` ӦM/))144ǰM`a wvv¥Uq绷oQPDDHXZ&߽y:-@RNkkٳ={fddLɓ';99Ge*PD ޽{0nfB T{]6An~~v..2dMQ ,-FFF`cbbv ˗c&YD`q ,Gy2jlu{iC4Q24EJ-ɎbZhӧO]\\6m,# 2Ν;Pב#G^jmm e<~xOOτ n%Ξ= `޽{@ ʰ8+M#[KussVyׯ+;USSb <T)...)))''o dFDDTWW^eff ,UTS++ -(3{ WgAvb!<װR6:Bl vc~xJGj&2D[bN} <ViܓHnU Bۘ1!U)#۶ 9׾,/@` ^嵻.'0JYZ linJ)!0QhK)tB7~݇#y#d[9d0ڂj!;(|֕7Gv";" ׆&||;_`̎Q( o-J `c\+tYK·!yu ?ж-l&DRb ٨Z 4E +L} ۶,y _i=8²,0 }c|`ӧ#kӐ+#T[bۧ`Z2n`XIb# |a{D qZ33'\>XACdvs>qߗ\>}bδ.GHL?y{ 0A.(6h6R '2"$6{v_RVtY0i6E-+7M;S6o. m[uH58fCֶ-o4r0P A X^Vm(//`#X^ Cgߛ3vZH0=O况a4h-H$&3&ƯχGݟD@da$n :& !QO1@'ckZ!N#A)R3r1z(YD`{iV{BYX imk&@ MR)$ 8+SXإ#IB\)Y<w+@ I9g SDԦZ+]8yuljRb,Vhsb{!:)IRBϓw-:KKy Y*a&cmC,jA $QS@F `  fغڰa=LNNN ܹs555@cC@@ !` L@q`zZe!f{k =Z`ڽ{7wiY LL4 ><ZLDd1B 5gp1Dѽ  H'j9{5|02,,䲃Aϟ̍ZR ilFAdrzDhCfJ)o9#bC&Ѹw-S 8SxQKAmmdh>GqgGUmUSk%:vSf؆a M l@.ެA.OD"U~NcjQ=ZARW7!^X%Ŗx])1 Cۜ3*Z) Ϥ&U'KpaAG)n1*ni$`:{&!4p|oTsmY0pۺ N9{A ``r, ,,t](U\X6:|k1u|!e^Pz] Hk;,#%#qR ԦBZ=4S#%1 9gUJI7aZk]k7]㔞-Hup'`4fѠ/)D޴oW doE7⡇#TkE{)8K)wksέs`q QykE0|1` HA.p әok9&\Y@`Tl##$"d!Hv{"RJᐵ%-xjsN֜sk kI8:c&}B4u`ma DH  }b N&$E(ї[o0焋tsn19Q=I1Z+@'v鬵RJc;謸YU!^/A{rp3~bqJ 3{ bw; 0.Dt(=:6\r yBx_**٬q1sNuH?]GI5j{ICr szXd+s\)ZZv2fe;ȵ1j?P@͸`ma x:/mr@w&F`J Sw;;mSN]n]֭[9`ӧOTu c3 pb[Go;D2} .D_Ԃ^<8@-"fꈨm33$Id- J*<4+.Gf``d ӧOiK, π+`' X$xr0][@C XB6陛[M?  Z&SSSS`JRR6%.999a=X01X@ Kƀ0~WW׋/bbbN>}A`3 h%7~ AclF#fHv L@.0AvAJq T!挂Q A;nÐIENDB` postfixadmin-2.3.7/images/index.php0000664000175000017620000000027410715711016017346 0ustar davidpalepurple postfixadmin-2.3.7/model/0000775000175000017620000000000012301477467015372 5ustar davidpalepurplepostfixadmin-2.3.7/model/VacationHandler.php0000664000175000017620000001166011243507316021140 0ustar davidpalepurpleusername = $username; } /** * Removes the autoreply alias etc for this user; namely, if they're away we remove their vacation alias and * set the vacation table record to false. * @return boolean true on success. */ function remove() { $ah = new AliasHandler($this->username); $aliases = $ah->get(true); // fetch all. $new_aliases = array(); $table_vacation = table_by_key('vacation'); $table_vacation_notification = table_by_key('vacation_notification'); /* go through the user's aliases and remove any that look like a vacation address */ foreach($aliases as $alias) { if(!$ah->is_vacation_address($alias)) { $new_aliases[] = $alias; } } $ah->update($new_aliases, '', false); // tidy up vacation table. $active = db_get_boolean(False); $username = escape_string($this->username); $result = db_query("UPDATE $table_vacation SET active = '$active' WHERE email='$username'"); $result = db_query("DELETE FROM $table_vacation_notification WHERE on_vacation='$username'"); /* crap error handling; oh for exceptions... */ return true; } /** * @return boolean true indicates this server supports vacation messages, and users are able to change their own. * @global array $CONF */ function vacation_supported() { global $CONF; return $CONF['vacation'] == 'YES' && $CONF['vacation_control'] == 'YES'; } /** * @return boolean true if on vacation, otherwise false * Why do we bother storing true/false in the vacation table if the alias dictates it anyway? */ function check_vacation() { $ah = new AliasHandler($this->username); $aliases = $ah->get(true); // fetch all. foreach($aliases as $alias) { if($ah->is_vacation_address($alias)) { return true; } } return false; } /** * Retrieve information on someone who is on vacation * @return struct|boolean stored information on vacation - array(subject - string, message - string, active - boolean) * will return false if no existing data */ function get_details() { $table_vacation = table_by_key('vacation'); $username = escape_string($this->username); $sql = "SELECT * FROM $table_vacation WHERE email = '$username'"; $result = db_query($sql); if($result['rows'] == 1) { $row = db_array($result['result']); $boolean = ($row['active'] == db_get_boolean(true)); return array( 'subject' => $row['subject'], 'body' => $row['body'], 'active' => $boolean ); } return false; } /** * @param string $subject * @param string $body */ function set_away($subject, $body) { $this->remove(); // clean out any notifications that might already have been sent. // is there an entry in the vacaton table for the user, or do we need to insert? $table_vacation = table_by_key('vacation'); $username = escape_string($this->username); $body = escape_string($body); $subject = escape_string($subject); $result = db_query("SELECT * FROM $table_vacation WHERE email = '$username'"); $active = db_get_boolean(True); // check if the user has a vacation entry already, if so just update it if($result['rows'] == 1) { $result = db_query("UPDATE $table_vacation SET active = '$active', body = '$body', subject = '$subject', created = NOW() WHERE email = '$username'"); } else { $tmp = preg_split ('/@/', $username); $domain = escape_string($tmp[1]); $result = db_query ("INSERT INTO $table_vacation (email,subject,body,domain,created,active) VALUES ('$username','$subject','$body','$domain',NOW(),'$active')"); } $ah = new AliasHandler($this->username); $aliases = $ah->get(true); $vacation_address = $this->getVacationAlias(); $aliases[] = $vacation_address; return $ah->update($aliases, '', false); } /** * Returns the vacation alias for this user. * i.e. if this user's username was roger@example.com, and the autoreply domain was set to * autoreply.fish.net in config.inc.php we'd return roger#example.com@autoreply.fish.net * @return string an email alias. */ public function getVacationAlias() { global $CONF; $vacation_domain = $CONF['vacation_domain']; $vacation_goto = preg_replace('/@/', '#', $this->username); $vacation_goto = "{$vacation_goto}@{$vacation_domain}"; return $vacation_goto; } } /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ postfixadmin-2.3.7/model/UserHandler.php0000664000175000017620000000416411243507316020313 0ustar davidpalepurpleusername = $username; } /** * @return boolean true on success; false on failure * @param string $username * @param string $old_password * @param string $new_passwords * * All passwords need to be plain text; they'll be hashed appropriately * as per the configuration in config.inc.php */ public function change_pass($old_password, $new_password) { global $config; $username = $this->username; $tmp = preg_split ('/@/', $username); $USERID_DOMAIN = $tmp[1]; $username = escape_string($username); $table_mailbox = table_by_key('mailbox'); $active = db_get_boolean(True); $result = db_query("SELECT * FROM $table_mailbox WHERE username='$username' AND active='$active'"); $new_db_password = escape_string(pacrypt($new_password)); $result = db_query ("UPDATE $table_mailbox SET password='$new_db_password',modified=NOW() WHERE username='$username'"); db_log ($username, $USERID_DOMAIN, 'edit_password', "$username"); return true; } /** * Attempt to log a user in. * @param string $username * @param string $password * @return boolean true on successful login (i.e. password matches etc) */ public static function login($username, $password) { global $config; $username = escape_string($username); $table_mailbox = table_by_key('mailbox'); $active = db_get_boolean(True); $query = "SELECT password FROM $table_mailbox WHERE username='$username' AND active='$active'"; $result = db_query ($query); if ($result['rows'] == 1) { $row = db_array ($result['result']); $crypt_password = pacrypt ($password, $row['password']); if($row['password'] == $crypt_password) { return true; } } return false; } } /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ postfixadmin-2.3.7/model/AliasHandler.php0000664000175000017620000001476411243507316020435 0ustar davidpalepurpleusername = $username; } /** * @return array - list of email addresses the user's mail is forwarded to. * (may be an empty list, especially if $CONF['alias_control'] is turned off... * @param boolean - by default we don't return special addresses (e.g. vacation and mailbox alias); pass in true here if you wish to. */ public function get($all=false) { $username = escape_string($this->username); $table_alias = table_by_key('alias'); $sql = "SELECT * FROM $table_alias WHERE address='$username'"; $result = db_query($sql); if($result['rows'] == 1) { $row = db_array ($result['result']); // At the moment Postfixadmin stores aliases in it's database in a comma seperated list; this may change one day. $list = explode(',', $row['goto']); if($all) { return $list; } $new_list = array(); /* if !$all, remove vacation & mailbox aliases */ foreach($list as $address) { if($address != '' ) { if($this->is_vacation_address($address) || $this->is_mailbox_alias($address)) { } else { $new_list[] = $address; } } } $list = $new_list; return $list; } return array(); } /** * @param string $address * @param string $username * @return boolean true if the username is an alias for the mailbox AND we have alias_control turned off. */ public function is_mailbox_alias($address) { global $CONF; $username = $this->username; if($address == $username) { return true; } return false; } /** * @param string $address * @return boolean true if the address contains the vacation domain */ public function is_vacation_address($address) { global $CONF; if($CONF['vacation'] == 'YES') { if(stripos($address, '@' . $CONF['vacation_domain'])) { return true; } } return false; } /** * @return boolean true on success * @param string $username * @param array $addresses - list of aliases to set for the user. * @param string flags - forward_and_store or remote_only or '' * @param boolean $vacation_persist - set to false to stop the vacation address persisting across updates * Set the user's aliases to those provided. If $addresses ends up being empty the alias record is removed. */ public function update($addresses, $flags = '', $vacation_persist=true) { // find out if the user is on vacation or not; if they are, // then the vacation alias needs adding to the db (as we strip it out in the get method) // likewise with the alias_control address. $valid_flags = array('', 'forward_and_store', 'remote_only'); if(!in_array($flags, $valid_flags)) { die("Invalid flag passed into update()... : $flag - valid options are :" . implode(',', $valid_flags)); } $addresses = array_unique($addresses); $original = $this->get(true); $tmp = preg_split('/@/', $this->username); $domain = $tmp[1]; foreach($original as $address) { if($vacation_persist) { if($this->is_vacation_address($address)) { $addresses[] = $address; } } if($flags != 'remote_only') { if($this->is_mailbox_alias($address)) { $addresses[] = $address; } } } $addresses = array_unique($addresses); $new_list = array(); if($flags == 'remote_only') { foreach($addresses as $address) { // strip out our username... if it's in the list given. if($address != $this->username) { $new_list[] = $address; } } $addresses = $new_list; } if($flags == 'forward_and_store') { if(!in_array($this->username, $addresses)) { $addresses[] = $this->username; } } $new_list = array(); foreach($addresses as $address) { if($address != '') { $new_list[] = $address; } } $addresses = array_unique($new_list); $username = escape_string($this->username); $goto = escape_string(implode(',', $addresses)); $table_alias = table_by_key('alias'); if(sizeof($addresses) == 0) { $sql = "DELETE FROM $table_alias WHERE address = '$username'"; } if($this->hasAliasRecord() == false) { $true = db_get_boolean(True); $sql = "INSERT INTO $table_alias (address, goto, domain, created, modified, active) VALUES ('$username', '$goto', '$domain', NOW(), NOW(), '$true')"; } else { $sql = "UPDATE $table_alias SET goto = '$goto', modified = NOW() WHERE address = '$username'"; } $result = db_query($sql); if($result['rows'] != 1) { return false; } db_log($username, $domain, 'edit_alias', "$username -> $goto"); return true; } /** * Determine whether a local delivery address is present. This is * stores as an alias with the same name as the mailbox name (username) * @return boolean true if local delivery is enabled */ public function hasStoreAndForward() { $aliases = $this->get(true); if(in_array($this->username, $aliases)) { return true; } return false; } /** * @return boolean true if the user has an alias record (i.e row in alias table); else false. */ public function hasAliasRecord() { $username = escape_string($this->username); $table_alias = table_by_key('alias'); $sql = "SELECT * FROM $table_alias WHERE address = '$username'"; $result = db_query($sql); if($result['rows'] == 1) { return true; } return false; } } /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ postfixadmin-2.3.7/create-domain.php0000664000175000017620000001154011552152102017473 0ustar davidpalepurple array('type' => 'str', 'default' => null), 'fDescription' => array('type' => 'str', 'default' =>''), 'fAliases' => array('type' => 'int', 'default' => $CONF['aliases']), 'fMailboxes' => array('type' => 'int', 'default' => $CONF['mailboxes']), 'fMaxquota' => array('type' => 'int', 'default' => $CONF['maxquota']), 'fTransport' => array('type' => 'str', 'default' => $CONF['transport_default'], 'options' => $CONF['transport_options']), 'fDefaultaliases' => array('type' => 'str', 'default' => 'off', 'options' => array('on', 'off')), 'fBackupmx' => array('type' => 'str', 'default' => 'off', 'options' => array('on', 'off')) ); foreach($form_fields as $key => $default) { if(isset($_POST[$key]) && (strlen($_POST[$key]) > 0)) { $$key = escape_string($_POST[$key]); } else { $$key = $default['default']; } if($default['type'] == 'int') { $$key = intval($$key); } if($default['type'] == 'str') { $$key = strip_tags($$key); /* should we even bother? */ } if(isset($default['options'])) { if(!in_array($$key, $default['options'])) { die("Invalid parameter given for $key"); } } } $fDomain = strtolower($fDomain); if ($_SERVER['REQUEST_METHOD'] == "GET") { /* default values as set above */ $tTransport = $fTransport; $tAliases = $fAliases; $tMaxquota = $fMaxquota; $tMailboxes = $fMailboxes; $tDefaultaliases = $fDefaultaliases; $tBackupmx = $fBackupmx; } if ($_SERVER['REQUEST_METHOD'] == "POST") { $tBackupmx = ""; if ($fDomain == null or domain_exist($fDomain) or !check_domain($fDomain)) { $error = 1; $tDomain = $fDomain; $tDescription = $fDescription; $tAliases = $fAliases; $tMailboxes = $fMailboxes; if (isset ($_POST['fMaxquota'])) $tMaxquota = $fMaxquota; if (isset ($_POST['fTransport'])) $tTransport = $fTransport; if (isset ($_POST['fDefaultaliases'])) $tDefaultaliases = $fDefaultaliases; if (isset ($_POST['fBackupmx'])) $tBackupmx = $fBackupmx; $pAdminCreate_domain_domain_text = $PALANG['pAdminCreate_domain_domain_text_error2']; if (domain_exist ($fDomain)) $pAdminCreate_domain_domain_text = $PALANG['pAdminCreate_domain_domain_text_error']; } if ($error != 1) { $tAliases = $CONF['aliases']; $tMailboxes = $CONF['mailboxes']; $tMaxquota = $CONF['maxquota']; if ($fBackupmx == "on") { $fBackupmx = 1; $sqlBackupmx = db_get_boolean(true); } else { $fBackupmx = 0; $sqlBackupmx = db_get_boolean(false); } $sql_query = "INSERT INTO $table_domain (domain,description,aliases,mailboxes,maxquota,transport,backupmx,created,modified) VALUES ('$fDomain','$fDescription',$fAliases,$fMailboxes,$fMaxquota,'$fTransport','$sqlBackupmx',NOW(),NOW())"; $result = db_query($sql_query); if ($result['rows'] != 1) { $tMessage = $PALANG['pAdminCreate_domain_result_error'] . "
    ($fDomain)
    "; } else { if ($fDefaultaliases == "on") { foreach ($CONF['default_aliases'] as $address=>$goto) { $address = $address . "@" . $fDomain; $result = db_query ("INSERT INTO $table_alias (address,goto,domain,created,modified) VALUES ('$address','$goto','$fDomain',NOW(),NOW())"); } } $tMessage = $PALANG['pAdminCreate_domain_result_success'] . "
    ($fDomain)
    "; } if (!domain_postcreation($fDomain)) { $tMessage = $PALANG['pAdminCreate_domain_error']; } } } include ("templates/header.php"); include ("templates/menu.php"); include ("templates/admin_create-domain.php"); include ("templates/footer.php"); /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ ?> postfixadmin-2.3.7/list-domain.php0000664000175000017620000000757511550341323017223 0ustar davidpalepurple postfixadmin-2.3.7/edit-active.php0000664000175000017620000000667111173140622017175 0ustar davidpalepurple$fDomain
    !"; } else { $setSql=('pgsql'==$CONF['database_type']) ? 'active=NOT active' : 'active=1-active'; $setSql.=', modified=NOW()'; if ($fUsername != '') { $result = db_query ("UPDATE $table_mailbox SET $setSql WHERE username='$fUsername' AND domain='$fDomain'"); if ($result['rows'] != 1) { $error = 1; $tMessage = $PALANG['pEdit_mailbox_result_error']; } else { db_log ($SESSID_USERNAME, $fDomain, 'edit_mailbox_state', $fUsername); } } if ($fAlias != '') { $result = db_query ("UPDATE $table_alias SET $setSql WHERE address='$fAlias' AND domain='$fDomain'"); if ($result['rows'] != 1) { $error = 1; $tMessage = $PALANG['pEdit_mailbox_result_error']; } else { db_log ($SESSID_USERNAME, $fDomain, 'edit_alias_state', $fAlias); } } if ($fAliasDomain != '') { $result = db_query ("UPDATE $table_alias_domain SET $setSql WHERE alias_domain='$fDomain'"); if ($result['rows'] != 1) { $error = 1; $tMessage = $PALANG['pEdit_alias_domain_result_error']; } else { db_log ($SESSID_USERNAME, $fDomain, 'edit_alias_domain_state', $fDomain); } } } if ($error != 1) { if ( preg_match( "/^list-virtual.php.*/", $fReturn ) || preg_match( "/^search.php.*/", $fReturn ) ) { //$fReturn appears OK, jump there header ("Location: $fReturn"); } else { header ("Location: list-virtual.php?domain=$fDomain"); } exit; } } include ("templates/header.php"); include ("templates/menu.php"); include ("templates/message.php"); include ("templates/footer.php"); /* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/sendmail.php0000664000175000017620000000415411156036527016576 0ustar davidpalepurple postfixadmin-2.3.7/CHANGELOG.TXT0000664000175000017620000006467412301472405016166 0ustar davidpalepurple# Postfix Admin # # LICENSE # This source file is subject to the GPL license that is bundled with # this package in the file LICENSE.TXT. # # Further details on the project are available at : # http://www.postfixadmin.com or http://postfixadmin.sf.net # # Last update: # $Id: CHANGELOG.TXT 1651 2014-02-20 21:35:01Z christian_boltz $ Version 2.3.7 - 2014/02/20 - SVN r1651 (postfixadmin-2.3 branch) ---------------------------------------------------------------- - SECURITY: fix SQL injection in show_gen_status() - lt.lang, da.lang translation update - when enabling/disabling a mailbox, also update the corresponding alias - fix creating superadmin in setup.php with MariaDB (more strict SQL) - don't trim() mail address to avoid that aliases starting with a space are allowed. This fixes http://sourceforge.net/p/postfixadmin/bugs/210/ and https://sourceforge.net/p/postfixadmin/feature-requests/113/ - update regex in check_domain() to support new, longer TLDs like .international - mark vacation_notification.notified field as latin1 to avoid overlong index - vacation.pl: encode subject - vacation.pl: disable use of TLS by default due to a bug in Mail::Sender 0.8.22 (you can re-enable it with $smtp_tls_allowed) Version 2.3.6 - 2013/01/02 - SVN r1417 (postfixadmin-2.3 branch) ---------------------------------------------------------------- - display domain and mailbox description with correct encoding - fix footer link - focus username input field in login form - fix double inclusion of config.inc.php in setup.php - fix bool and date handling in fetchmail Version 2.3.5 - 2012/01/16 - SVN r1335 (postfixadmin-2.3 branch) ---------------------------------------------------------------- - fix SQL injection in pacrypt() (if $CONF[encrypt] == 'mysql_encrypt') - fix SQL injection in backup.php - the dump was not mysql_escape()d, therefore users could inject SQL (for example in the vacation message) which will be executed when restoring the database dump. WARNING: database dumps created with backup.php from 2.3.4 or older might contain malicious SQL. Double-check before using them! - fix XSS with $_GET[domain] in templates/menu.php and edit-vacation - fix XSS in some create-domain input fields - fix XSS in create-alias and edit-alias error message - fix XSS (by values stored in the database) in fetchmail list view, list-domain and list-virtual - create-domain: fix SQL injection (only exploitable by superadmins) - add missing $LANG['pAdminDelete_admin_error'] - don't mark mailbox targets with recipient delimiter as "forward only" - wrap hex2bin with function_exists() - PHP 5.3.8 has it as native function Version 2.3.4 - 2011/09/16 - SVN r1180 (postfixadmin-2.3 branch) ---------------------------------------------------------------- - generate more secure random passwords - squirrelmail plugin: fix typo in variable name - list-domain: fix SELECT query to work with PgSQL even when using custom fields - create-domain: force domain name to lowercase to avoid problems with PgSQL foreign keys - fix vacation.pl to log to "mail" syslog facility - error_log() dovecotpw error messages Version 2.3.3 - 2011/03/14 - SVN r1010 (postfixadmin-2.3 branch) ---------------------------------------------------------------- - create-alias: allow multiple alias targets - create-alias, edit-alias: prevent input data loss on validation errors - list-virtual: fix displaying of 'modified' column for aliases when using postgres - replaced deprecated split() with preg_split() or explode() - functions.inc.php: better error messages when database functions are missing - create domain: fixed typo in variable name that broke the default value for default aliases - postgres: changed mailbox.quota, domain.quota and domain.maxquota fields to bigint to allow mailboxes >4 GB (run setup.php to upgrade your database) - vacation.pl logged literal $variable instead of the variable content at two places - edit-vacation: log enabling/disabling vacation if done by admins - POSTFIX_CONF.txt: fixed filename for quota map - config.inc.php: removed double $CONF['database_prefix'] - config.inc.php: fixed comments about domain_post* script parameters - updated INSTALL.TXT and UPGRADE.TXT - sk translation update - some more minor fixes Version 2.3.2 - 2010/08/24 - SVN r860 (postfixadmin-2.3 branch) --------------------------------------------------------------- - SUMMARY: PostfixAdmin 2.3.2 is a bugfix-only release for Postfix Admin 2.3.1 - SECURITY: attackers could find out if a admin exists (login pre-filled the username after "only" a wrong password was entered) - SECURITY: fix sql injection in list-domain (only exploitable by superadmins) - alias targets in users/edit-alias are now validated - invalid alias targets in users/edit-alias are shown to the user again instead of dropping them - fix dovecot:* password encryption (was broken in 2.3.1) - fix displaying used quota for dovecot <= 1.1 (was broken in 2.3.1) - when deleting a domain that is an alias domain (on the "from" side), the alias domain is deleted Version 2.3.1 - 2010/07/09 - SVN r847 (postfixadmin-2.3 branch) --------------------------------------------------------------- - SUMMARY: PostfixAdmin 2.3.1 is a bugfix-only release for Postfix Admin 2.3. The only visible change is displaying the alias target for mailboxes which was a longstanding issue/"missing feature". The ADDITIONS directory contains some new scripts. - SECURITY: users could bypass checking the old password when changing the password by entering a too short new password. Fortunately only "exploitable" by authentificated users. - merge in changes to /debain (thanks normes) from trunk - display alias targets for mailboxes (if $CONF['special_alias_control'] = YES) - add hook for custom maildir path generation - add import_users_from_csv.py script (by Simone Piccardi) - add mailbox_post* scripts for cyrus - handle dovecot passwords without any tempfile (prevents safe_mode issues) - fix MySQL 6.0 compatibility - fix quota display (for dovecot >= 1.2) - fix short open tags ("= 1.2) - list-virtual can now handle both table formats - fixed upgrade.php for MySQL 6.0 compability - changed vacation.pl syslog facility from "user" to "mail" - added config option for postregsql database port - added config option to enable/disable XMLRPC interface (default: off) - Fix check/query for alias with enabled vacation in vacation.pl - Fix db_get_boolean() to return t/f for postgresql, not true/false - Fix missing quoting for boolean values in SQL queries at various places - Allow SHA courier-authlib passwords - various small bug fixes - fixed SVN revision for 2.3rc7 in changelog (was r691, should be r694) Version 2.3rc7 - 2009/07/27 - SVN r694 -------------------------------------- - Fix bug with confd-link.sh debian thing (breakage on Lenny with wwwconfig-common 0.1.2) - Fix crypt() issue (see https://sourceforge.net/tracker/?func=detail&aid=2814820&group_id=191583&atid=937964 ) Version 2.3rc6 - 2009/07/20 - SVN r689 -------------------------------------- - Updates to vacation.pl - PHP 5.3 compatibility - Easier dependencies for .debs - should work on Lenny/Ubuntu etc without issue now. Version 2.3rc5 - 2009/05/20 - SVN r658 -------------------------------------- - Improvements to the setup process - Far better Debian packaging (we hope!) which should make installation much, much easier. - Various bug fixes - Performance enhancements (or we fixed the regressions ...) in domain listing etc. Version 2.3rc4 - 2009/04/18 - SVN r632 -------------------------------------- - *Security fix* - on upgrade setup.php is restored; allowing a malicious user to create their own superadmin account. We've removed the requirement to delete setup.php, and instead a new config parameter (setup_password) is used to protect access to this page. Password is encrypted, and setup.php can be used to generate the initial value. - Fix undefined variables problem(s) - Fix PostgreSQL date timestamp issues... Version 2.3rc3 - 2009/04/06 - SVN r611 -------------------------------------- - Minor improvements to the Debian packaging, expect more soon - Assorted bug fixes - Partial support for per-user fetchmail.pl support Version 2.3rc2 - 2009/02/03 - SVN r593 -------------------------------------- - Refactor /users (see /model) and provide XmlRpc interface for remote mail clients (e.g. squirrelmail-postfixadmin) - Add dovecotpw support - see: https://sourceforge.net/tracker/index.php?func=detail&aid=2607332&group_id=191583&atid=937966 - Add unit tests for model/ directory (see /tests) - Add additional scripts to ADDITIONS - Documentation updates - Various language updates - added ADDITIONS/delete-mailq-by-domain.pl (by Jose Nilton) - added ADDITIONS/quota_usage.pl (by Jose Nilton) - produces report of quota usage - added support for courier authlib authentication flavors ($CONF['authlib_default_flavor']) Version 2.3 Beta - 2009/01/15 - SVN r527 ----------------------------------------- - added support for domain aliases (from lenix) (can be disabled with $CONF['alias_domain']) Important: If you update from a previous version, you'll have to adapt your postfix configuration (see DOCUMENTS/POSTFIX_CONF.txt) - or just disable alias domain support, your postfix configuration will continue to work - updated postfix example configuration for domain aliases and to use the new mysql map format - vacation.pl: - add option for re-notification after definable timeout (patch from Luxten) (default stays on "notify once") - force usage of envelope from/to, better checks for mailinglists, spam etc. If in doubt, do not send a vacation reply (patch from Lutxen) - added a small test suite - use Log4Perl - allow to enter the configuration in /etc/mail/postfixadmin/vacation.conf instead of editing vacation.pl directly - bump version number of vacation.pl - added domain-postcreation script support - added dovecot quota support (documentation + viewing in postfixadmin) - enhanced mailbox table to make it easier for people to customise where mailboxes live (new column "local_part") - enhanced fetchmail.pl script (file locking, syslog logging, configuration file etc) - added clear error message for non-resolvable domains when creating mailboxes or aliases - check for non-resolvable domains on domain creation - new option $CONF['create_mailbox_subdirs_prefix'] for compatibility with more IMAP servers - added support for mysql encrypt() password encrpytion - fix "illegal mix of collations" problem in MySQL by explicitely setting the charset everywhere - fix: cleanup vacation_notification table when disabling vacation - fix: config and fetchmail tables now honor $CONF['database_tables'] - fix: several table names were hardcoded in database creation/update - fix: "unlimited" and "disabled" for quota and limits were crossed at several places - fix: honor $CONF['default_transport'] even if $CONF['transport'] = "no" (patch by fabiobon) - fix: transport field is no longer emptied on domain edit if editing transport is disabled - show links to create mailboxes or alias even on disabled domains - added support for fetchmail's "ssl" option - superadmin can now setup fetchmail for all users, not only for himself - force username to be lowercase - this helps some IMAP clients apparently - the "probably undeliverable" marker now honors catchall targets - on mailbox creation, show password if $CONF['generate_password'] == 'YES', but do not show it if it was _not_ autogenerated and $CONF['show_password'] == 'NO' - dropped $CONF['show_custom_count']. PHP can count ;-) - dropped obsolete VIRTUAL_VACATION/mail-filter script - translation updates - several small bugfixes Version 2.2.1.1 - 2008/07/23 - SVN r412 --------------------------------------- - fixed version number in functions.inc.php ;-) Version 2.2.1 - 2008/07/21 - SVN r408 ------------------------------------- - added quota parameter to mailbox_postcreation hook - new hook to update the quota after editing a mailbox ($CONF['mailbox_postedit_script']) - fixed subfolder creation order and timing - allow smtp server to be specified in vacation.pl - fixed MySQL charset issues - several small bugfixes - Norwegian (bokmal) translation added - several translation updates Version 2.2.0 - 2008/04/29 -------------------------- - Unicode support for vacation messages - More language translations - Merged the two vacation scripts (PostgreSQL version won :) ) - Added setup.php/upgrade.php scripts to handle upgrades - See also new 'config' database table - Added support for 'fetchmail' so mail from a remote server can be retrieved. - Many, many bug fixes - Added: Feature to show status of aliases/mailboxes (GregC) - Fixed: Many admin/*.php files merged with /*.php - Fixed: 'alias' instead of '$table_alias' being used by some .php files (GregC) - Fixed: Overview no longer lists alias entries for mailboxes (GregC) - Changed: Added exit buttons to several edit options. (GregC) - Fixed: user options are a little more idiot-proof, templates are consistent (GregC) - Changed: Users can view and edit their vacation config (GregC) - Added: Slovakian language posted on SourceForge by eszabo - Changed: searches include mailbox.name matches (GregC) - Fixed: function check_email will ignore vacation_domain if vacation==YES (GregC) - Changed: applied patches from Christian Boltz posted at http://www.cboltz.de/tmp/postfixadmin-3.patch, referenced at https://sourceforge.net/tracker/index.php?func=detail&aid=1696647&group_id=191583&atid=937966 (GregC) - Added: main.php to admin dirctory (GregC) - Added: Item "Main" on admin menu (GregC) - Changed: Edit-vacation now edits for admins/superadmins (GregC) - Added: Do not store local copy when forward mail. (Mihau) [24] - Added: Virtual Vacation for PostgreSQL. (Tarvin) - Added: Virtual Vacation 3.2 (Thanx David) - Added: SUBJECT tag for Virtual Vacation. - Added: Dovecot setup document for Postfix Admin. (Thanx Massimo) - Added: SquirrelMail plugin to change_password. - Changed: Starting to merge /admin in root. (Mihau) - Changed: Moved some TXT files to DOCUMENTS. - Changed: Updated tw.lang. (Thanx Bruce) - Fixed: Usage of mysql_real_escape_string(). (Mihau) - Fixed: Calculating of quotas. (Mihau) - Fixed: Password generation when creating a new account. (Mihau) - Fixed: PostgreSQL patches. (Tarvin) - Fixed: Adding of multiple aliases. (Mihau) - Fixed: CSS Menu width. (Mihau) - Fixed: Overview when upgrading from 2.0.4. (Mihau) - Fixed: smtp_mail() to wait for response from server. - Fixed: pacrypt() so system works properly. (Thanx Npaufler) - Fixed: quoting an email address when sending mail in vacation.pl. (Thanx Marc) - Fixed: vacation.pl has a clean exit when it encounters an error. (Thanx Brian) - Fixed: descriptions for quota={-1|0} in admin section (Mihau) Version 2.1.0 -- 2005/01/07 --------------------------- - Added: Traditional Chinese language. (Thanx Bruce) - Added: Traditional Bulgarian language. (Thanx Plamen) - Added: Macedonian language. (Thanx Damjan) - Added: Estonian language. (Thanx Peeter) - Added: Slovenian language. (Thanx Nejc) - Added: Check for update link in footer. - Added: Additional language strings. Check LANGUAGE.TXT - Added: Transport support. (read postfix transport for more information) - Added: Additional language string for transport support. - Added: MySQL 4.1 support. - Added: PostgreSQL support. (Big Thanx WhiteFox!) - Added: Setup Checker script. (Thanx Fenrir) - Added: Database prefix. (Thanx Decramy) - Added: Template tags. (Thanx Nelson) - Added: admin/domain/alias/mailbox in delete dialog box. - Added: $CONF['postfix_admin_url'] variable. - Added: $CONF['postfix_admin_path'] variable. - Added: $CONF['vacation_domain'] variable. - Added: $CONF['welcome_text'] variable. - Added: $CONF['special_alias_control'] variable. (Thanx Mihau) - Added: Virtual Vacation 3.1 (Thanx David) - Added: ADDITIONS directory with third party scripts and plugins. - Added: Search function for aliases and mailboxes. - Changed: Postfix Admin has now it's own license. - Changed: New menu and color scheme. (Thanx Nelson) - Changed: Disable number and unlimited number for aliases/mailboxes/quota. - Changed: Virtual Vacation to have it's own transport. (Big Thanx Npaufler!) - Changed: Removed the welcome text for a new mailbox from the language files. - Changed: backup.php to be a more secure. (Thanx John) - Fixed: Cleaned up stylesheet. - Fixed: Default quota multiplier. - Fixed: All POST/GET strings are escaped. - Fixed: Corrected smtp_mail() to wait for result. (Thanx Patrice) - Fixed: Pagination with alias_control switched on. - Fixed: Swedish language. (Thanx Bjorne) - Fixed: Polish language. (Thanx Piotr) - Fixed: Minor Virtual Vacation bugs. (Thanx David) - Fixed: check_quota(). - Fixed: Minor encode_header() issue. (Thanx Matthew) - Fixed: edit-alias.php when running with magic_quotes_gpc = off Version 2.0.5 -- 2004/08/21 --------------------------- - Added: Chinese language. (Thanx Matthew) - Added: Catalan language. (Thanx Jaume) - Added: Czech language. (Thanx Jakub) - Added: Dynamic language detection. - Added: Header in header.tpl to set charset header from language file. - Added: More subroutines and alias checking for Vacation. (Thanx David) - Added: Domain pass-through with certain pages. - Added: Backup MX option for domain. - Added: Log contains IP address of admin. - Added: Pagination for alias/mailbox listing. - Added: 2 additional language strings to support Backup MX. - Added: Support for motd.txt (Domain Admins only). - Added: Support for motd-admin.txt (Site Admins only). - Added: Support for motd-users.txt (Users only). - Added: Optional hostname for vacation. - Added: generate_password() to generating random passwords for mailboxes. - Changed: dk -> da, se -> sv, no-nn -> nn - Changed: All email addresses are now converted to lowercase, strtolower(). - Changed: Moved onMouseOver to the CSS stylesheet. - Changed: Moved font color to the CSS styleheet. - Changed: PHP mail() is replaced by an internal function, smtp_mail(). - Changed: mysql_fetch_array() replaced with internal function db_array(). - Changed: mysql_fetch_assoc() replaced with internal function db_assoc(). - Changed: mysql_fetch_row() replaced with internal function db_row(). - Changed: Quota multiplier is now a configuration option. - Fixed: Login didn't check for active flag. - Fixed: Minor html table errors. - Fixed: Row count by using COUNT(*). - Fixed: Locked down subdirectories. - Fixed: Create admin properly populates the domain_admins table. - Fixed: Cleaned up stylesheet.css. - Fixed: Delete mailbox properly removes vacation entries. Version 2.0.4 -- 2004/02/26 ---------------------------- - Added: Euskara language. (Thanx Julen) - Added: Hungarian language. (Thanx Christian) - Added: Icelandic language. (Thanx Gestur) - Added: Italian language. (Thanx Stucchi) - Added: Norwegian - Nynorsk language. (Thanx Paul) - Added: Polish language. (Thanx Jarek) - Added: Portuguese - Brazil language. (Thanx Roberto) - Added: Rusian language. (Thanx Paul) - Added: Turkish language (Thanx Onuryalazi) - Added: Encode a string according to RFC 1522 for use in headers if it contains 8-bit characters. (Thanx Evgeniy) - Added: One click active change of mailbox/domain/admin. (Thanx Marcin) - Changed: Header in header.tpl to read charset header from language file. - Fixed: Some form values are now parsed through htmlspecialchars(). (Thanx Marcin) - Fixed: admin/delete.php ignored $CONF['vacation']. - Fixed: More minor fixes to Virtual Vacation. Version 2.0.3 -- 2004/01/14 ---------------------------- - Added: Site Admin email address. - Added: Danish language. (Thanx Lars) - Added: Dutch language. (Thanx Mourik) - Added: Faroese language. (Thanx Danial) - Added: Finnish language. (Thanx Palo) - Added: French language. (Thanx Kuthz) - Added: Swedish language. (Thanx Slite) - Added: Ignoring of MAILER-DAEMON type emails for Vacation. - Fixed: Minor issues regarding mail(). - Fixed: Minor issues regarding crypt(). - Fixed: Strip issue of email address for Vacation. Version 2.0.2 -- 2004/01/06 ---------------------------- - Added: German language. (Thanx Tobias) - Added: Spanish language. (Thanx Alvaro) - Fixed: The body was not included using sendmail.php. - Fixed: Undefined variables. - Fixed: Minor HTML cleanup. Version 2.0.1 -- 2004/01/04 ---------------------------- - Fixed: The language variable caused a problem on some systems. Version 2.0.0 -- 2004/01/03 ---------------------------- - Added: The ability for one domain admin to maintain multiple domains. - Added: Domain to domain forwarding. - Added: Mailboxes can now be activated or deactivated. - Added: Configurable welcome message for new mailboxes. - Added: Optional sending of welcome message. - Added: Create alias "To" defaults to current domain. - Added: Logging of admin / user actions. - Added: Limit for aliases and/or mailboxes per domain. - Added: Disable aliases and/or mailboxes per domain. - Added: Max quota per mailbox per domain. - Added: Multi-Language support. - Added: Statistics overview for all domains. - Added: User .forwarding for mailbox users. - Added: Logo for Postfix Admin (Thanx Andrew). - Added: Extra MySQL debugging capabilities. - Added: Clear text password support. - Added: PHP crypt() support. - Changed: Separated logic and SQL from content. - Changed: config.inc.php doesn't point to example.com anymore. - Changed: Virtual Vacation no longer requires procmail. - Changed: Complete re-write. Version 1.5.4 -- 2003/06/16 ---------------------------- - Added: Option for "Back to". - Added: Option for Vacation module. - Added: Table declaration for the use of Quota in the INSTALL.TXT. This requires an additional local delivery agent. Quotas are not supported by Postfix! - Changed: The word "View" to "List". Version 1.5.3 -- 2003/06/06 ---------------------------- - Fixed: Even more minor bugs in regards to declaration of variables. (Thanx Aquilante and Kyle_m) Version 1.5.2 -- 2003/06/05 ---------------------------- - Fixed: Minor bugs in regards to declaration of variables. Version 1.5.1 -- 2003/06/04 ---------------------------- - Added: Optional mailbox per domain directory structure. (Thanx Jim) - Added: Option to completely control the stored aliases. (Thanx Alex) - Changed: config.inc.php is renamed to config.inc.php.sample. (Thanx Alex) - Fixed: $PHP_SELF in config.inc.php and my_lib.php. (Thanx Jim) Version 1.5.0 -- 2003/05/28 ---------------------------- - Added: Support for "Back to Main Site" - Added: config.inc.php as the main configuration file. - Added: Drop down box for domain selection when adding a new admin. - Added: Resend of test email to newly created mailbox. - Added: Mailbox and Aliases count for domainview. - Added: Change description of domain without deleting the complete domain. - Added: Change name of mailbox user without deleting the mailbox. - Added: Expire headers for unnecessary reloads. (Thanx Alex) - Fixed: Code clean up. - Fixed: Minor bugs and cosmetic fixes. - Fixed: Modified check_string() to check numbers and returns false if not matched. (Thanx btaber) - Fixed: Correct session handling in login.php (Thanx Yen-Wei Liu) - Fixed: Correct deletion of RFC822 email addresses. (Thanx Yen-Wei Liu) - Removed: Completely removed the site_lib.php. - Removed: my_lib.php from the admin directory. - Removed: Symlink to index.php. Version 1.4.0 -- 2003/04/07 ---------------------------- - Added: When deleting a domain, all aliases and mailboxes for that domain are also deleted from the database. - Added: Add standard aliases for every domain that is created. These aliases can point to the main "local" administrator. The aliases are configured in the config.php in the admin directory. - Changed: The layout of my_lib.php and site_lib.php have been changed. - Changed: Modifying an alias is now done with TEXTAREA for more flexibility. - Fixed: Minor bugs and cosmetic fixes. Version 1.3.8a -- 2003/03/31 ---------------------------- - Fixed: After deletion of a domain it would not return to the correct page. Version 1.3.8 -- 2003/03/25 ---------------------------- - Added: Admin password change. No longer needed to delete and re-enter the admin user for a specific domain. Version 1.3.7 -- 2002/12/24 ---------------------------- - Initial public release of Postfix Admin. postfixadmin-2.3.7/GPL-LICENSE.TXT0000664000175000017620000003545410715711016016374 0ustar davidpalepurple GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS postfixadmin-2.3.7/search.php0000664000175000017620000001015511146027202016232 0ustar davidpalepurple 0) { while ($row = db_array ($result['result'])) { if (check_owner ($SESSID_USERNAME, $row['domain']) || authentication_has_role('global-admin')) { if ('pgsql'==$CONF['database_type']) { $row['modified']=gmstrftime('%c %Z',$row['modified']); $row['active']=('t'==$row['active']) ? 1 : 0; } $tAlias[] = $row; } } } if ($CONF['vacation_control_admin'] == 'YES' && $CONF['vacation'] == 'YES') { $query = ("SELECT $table_mailbox.*, $table_vacation.active AS v_active FROM $table_mailbox LEFT JOIN $table_vacation ON $table_mailbox.username=$table_vacation.email WHERE $table_mailbox.username LIKE '%$fSearch%' OR $table_mailbox.name LIKE '%$fSearch%' ORDER BY $table_mailbox.username"); } else { $query = "SELECT * FROM $table_mailbox WHERE username LIKE '%$fSearch%' OR name LIKE '%$fSearch%' ORDER BY username"; } $result = db_query ($query); if ($result['rows'] > 0) { while ($row = db_array ($result['result'])) { if (check_owner ($SESSID_USERNAME, $row['domain']) || authentication_has_role('global-admin')) { if ('pgsql'==$CONF['database_type']) { $row['created']=gmstrftime('%c %Z',strtotime($row['created'])); $row['modified']=gmstrftime('%c %Z',strtotime($row['modified'])); $row['active']=('t'==$row['active']) ? 1 : 0; } $tMailbox[] = $row; } } } include ("templates/header.php"); include ("templates/menu.php"); include ("templates/search.php"); include ("templates/footer.php"); /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ ?> postfixadmin-2.3.7/ADDITIONS/0000775000175000017620000000000012301477471015603 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/delete-mailq-by-domain.pl0000664000175000017620000000255011616351471022361 0ustar davidpalepurple#!/usr/bin/perl use strict; use warnings; use Getopt::Long; $ENV{'PATH'} = "/sbin:/bin:/usr/sbin:/usr/bin"; my ($domain); my $list = 0; (help()) if (!$ARGV[0]); GetOptions ('l' => \$list, 'd=s' => \$domain) or (help()); (list_queue()) if ($list == 1); (delete_queue()) if ($domain); sub delete_queue { my $ids = `postqueue -p`; my @ids = split /\n/, $ids; for my $id (@ids) { next if $id =~ /^[\s\(-]/; chomp $id; next unless $id; $id =~ s/(.*?)\**\s.*/$1/; #print "$id\n"; my $match = `postcat -q $id | grep '$domain'`; next unless $match; #print "Deleting ID: $id\n"; my $saida = `postsuper -d $id`; print $saida; } } sub list_queue { my %hash_mail = (); my @queue = `postqueue -p`; my($queue,$key,$total); foreach $queue(@queue) { chomp $queue; if ( $queue =~ /^\s+.*\@(.*)/ ) { $hash_mail{$1}++; } } print"\nTOTAL\tTO\n"; print"----- ----------------------------------------------------------------\n"; foreach $key (reverse sort { $hash_mail{$a} <=> $hash_mail{$b}} keys %hash_mail) { $total += $hash_mail{$key}; print"$hash_mail{$key} - $key\n"; } print"\n$total -> TOTAL QUEUE\n"; } sub help { print "Usage $0 -l To list a row of E-mail Usage $0 -d domain.com To delete the mensgens the Domain\n"; } postfixadmin-2.3.7/ADDITIONS/import_users_from_csv.py0000664000175000017620000001520311617071641022605 0ustar davidpalepurple#!/usr/bin/env python # -*- coding: utf-8 -*- # Script takes a CSV list of users and does a 'bulk' insertion into mysql. # # Copyright (C) 2009 Simone Piccardi # # This program 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 2 of the License, or (at # your option) any later version. # # This program 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 this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # import csv import getopt import sys import re import time import random, string from datetime import datetime from crypt import crypt try: import MySQLdb except ImportError ,e: print 'Cannot import the needed MySQLdb module, you must install it' print 'on Debian systems just use the command' print ' apt-get install python-mysqldb' def usage(): print "Usage: inspostadmusers.py [options] users.csv" print " -h print this help" print " -t test run, do not insert, just print" print " -u DB user" print " -p DB password" print " -D DB name" print " -H DB host" print " -q Quota in Mb (0 => no limit)" print " -n char in seed" print " -d debug info on" print " -A create default alias for each domain" print print "the users.csv file must contains the user list with a line" print "for each user, first line should be a title line with at least" print "the following column names: " print " * user - user part of the email (like user in user@domain.com)" print " * password - cleartext password" print " * domain - domain name (like 'domain.com')" print " * name - full user name ('Name Surname')" print print "the 'name' column is optional, other columns will be ignored" print print "Known restrictions:" print "* this script only works with MySQL" print "* mailbox paths are hardcoded to domain/username/" # option parsing try: opts, args = getopt.getopt(sys.argv[1:], 'u:p:d:D:H:htdA') optval={} for opt, val in opts: if opt == "-h": usage() sys.exit(0) else: optval[opt]=val except getopt.GetoptError: usage() sys.exit(2) # # Setup DB connection # MYSQLDB="postfixadmin" MYSQLUSER="postfixadmin" MYSQLPASSWORD="" MYSQLHOST="localhost" # settings by command line options if optval.has_key('-u'): MYSQLUSER = optval['-u'] if optval.has_key('-p'): MYSQLPASSWORD = optval['-p'] if optval.has_key('-D'): MYSQLDB = optval['-D'] if optval.has_key('-H'): MYSQLHOST = optval['-H'] if optval.has_key('-q'): quota = optval['-q'] else: quota = 0 if optval.has_key('-n'): seed_len = optval['-n'] else: seed_len = 8 # check arguments, only the user list file must be present if len(args) !=1: print 'Need just one argument' usage() sys.exit(1) # MySQL connection (skipped in test run) if optval.has_key('-t'): print "Test Run" else: try: connection = MySQLdb.connect(host=MYSQLHOST, user=MYSQLUSER, db=MYSQLDB, passwd=MYSQLPASSWORD) except MySQLdb.MySQLError, e: print "Database connection error" print e sys.exit(1) cursor = connection.cursor() # # Main body # NOW = datetime.now().strftime("%Y-%m-%d %H:%M:%S") # read and convert CSV data lista = csv.DictReader(open(args[0])) def gen_seed(seed_len, chars): return '$1$'+''.join([random.choice(chars) for _ in xrange(seed_len)])+'$' def insert_record(cursor,table,record): columns = record.keys() query = "INSERT INTO " + table + "(" + ','.join(columns) + ") VALUES (" + ','.join(len(columns)*['%s']) + ")" try: cursor.execute(query, record.values()) return 0 except MySQLdb.MySQLError, e: print "Database insertion error" print e print "Record was:" print record.values() print "Query was:" print query # defining default values for tables (mailbox, alias and domain) mailbox = { 'created': NOW, 'modified': NOW, 'active': 1, 'quota': quota } aliases = { 'created': NOW, 'modified': NOW, 'active': 1 } domain = { 'description': "", 'aliases': 0, 'mailboxes': 0, 'quota': 0, 'transport': 'virtual', 'backupmx': 0, 'created': NOW, 'modified': NOW, 'active': 1 } # list of default alias def_alias = ['abuse','hostmaster','postmaster','webmaster'] domain_list = {} chars = string.letters + string.digits # loop over the CSV for row in lista: # create domain if it does not exists if domain_list.has_key(row["domain"]): if optval.has_key('-d'): print "Domain " + row["domain"] + "already exixts" else: domain_list[row["domain"]] = 1 domain['domain'] = row["domain"] if optval.has_key('-t'): print "Inserting domain" print domain else: insert_record(cursor,'domain',domain) if optval.has_key('-A'): for i in def_alias: aliases['address']= i+'@'+row["domain"] aliases['goto']= aliases['address'] aliases['domain'] = row["domain"] if optval.has_key('-t'): print "Inserting alias" print aliases else: insert_record(cursor,'alias',aliases) # build query data for mailbox table mailbox['username']=row["user"]+'@'+row["domain"] encpass=crypt(row["password"], gen_seed(seed_len,chars)) mailbox['password'] = encpass mailbox['name'] = row["name"] mailbox['maildir'] = row["domain"]+'/'+row["user"]+'/' mailbox['local_part'] =row["user"] mailbox['domain'] = row["domain"] # build query data for alias table aliases['address']= mailbox['username'] aliases['goto']= mailbox['username'] aliases['domain'] = row["domain"] # inserting data for mailbox (and relate alias) if optval.has_key('-t'): print "Inserting mailbox" print mailbox print aliases else: insert_record(cursor,'mailbox',mailbox) insert_record(cursor,'alias',aliases) sys.exit(0) postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/0000775000175000017620000000000012301477471021610 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/INSTALL0000664000175000017620000000333211415437006022635 0ustar davidpalepurpleInstalling the postfixadmin Plugin ====================================== Requirements: ============= - PHP 5.2.x with php5-xmlrpc installed (if available; it should be available by default anyway) - http access to a local/remote postfixadmin interface - Zend Framework - download from http://framework.zend.com - the Zend directory needs to be in PHP's include_path, or in the same directory as the plugin. Suggested version 1.10; older versions should work. Installation : ============== - Check out this code (svn co http://squirrelmail-postfixadmin.palepurple.co.uk/svn/trunk postfixadmin) into the Squirrelmail plugins directory. - Edit config.php and specify the remote URL for the Postfixadmin XmlRpc service. There isn't much more to change. - Edit the remote Postfixadmin's XmlRpc service config file and ensure 'xmlrpc_enable' is set to boolean true. - Enable the plugin through 'squirrelmail-configure' or 'config/conf.pl'. Choose option 8 and move the plugin from the "Available Plugins" category to the "Installed Plugins" category. Save and exit. Security : ========== - The XmlRpc client needs to get the user's mailbox password before it will be able to connect to the XmlRpc server (postfixadmin). The plugin prompts the user for their mailbox password, and caches it in their session ($_SESSION['password']). This password is then sent once on every page load to the remote XmlRpc server. - You should consider doing any of the following : - Using https if the server and client are on seperate servers. This will probably require a signed certificate etc, and may require changes to the Zend_XmlRpc_Client's HttpClient. - Using something like stunnel to encrypt traffic between server(s). postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/common.php0000664000175000017620000000215311374336541023613 0ustar davidpalepurple"; } function _display_password_form() { bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); do_header('Postfixadmin Squirrelmail - Login'); echo _('The PostfixAdmin plugin needs your current mailbox password'); echo "
    "; echo _('Password for'); echo " " . $_SESSION['username'] . " :"; echo ""; echo "
    "; do_footer(); } /** * This returns a Zend_XmlRpc_Client instance - unless we can't log you in... */ function get_xmlrpc() { global $CONF; require_once('Zend/XmlRpc/Client.php'); $client = new Zend_XmlRpc_Client($CONF['xmlrpc_url']); $http_client = $client->getHttpClient(); $http_client->setCookieJar(); $login_object = $client->getProxy('login'); if(empty($_SESSION['password'])) { if(empty($_POST['password'])) { _display_password_form(); exit(0); } else { try { $success = $login_object->login($_SESSION['username'], $_POST['password']); } catch(Exception $e) { //var_dump($client->getHttpClient()->getLastResponse()->getBody()); error_log("Failed to login to xmlrpc instance - " . $e->getMessage); die('Failed to login to xmlrpc instance'); } if($success) { $_SESSION['password'] = $_POST['password']; // reload the current page as a GET request. header("Location: {$_SERVER['REQUEST_URI']}"); exit(0); } else { _display_password_form(); exit(0); } } } else { $success = $login_object->login($_SESSION['username'], $_SESSION['password']); } if(!$success) { unset($_SESSION['password']); die("Invalid details cached... refresh this page and re-enter your mailbox password"); } return $client; } function include_if_exists($filename) { if(file_exists($filename)) { include_once($filename); } return; } global $optmode; $optmode = 'display'; // // check_email // Action: Checks if email is valid and returns TRUE if this is the case. // Call: check_email (string email) // function check_email ($email) { $return = filter_var('validate_email', $email); if($return === false) { return false; } return true; } postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/config.php.sample0000664000175000017620000000123611374336541025051 0ustar davidpalepurple, YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: 2004-01-29 17:35+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: setup.php msgid "Forwarding" msgstr "" msgid "Here you can create and edit E-Mail forwards." msgstr "" msgid "Set an OUT OF OFFICE message or auto responder for your mail." msgstr "" msgid "Change your mailbox password." msgstr "" #: postfixadmin_changepass.php msgid "Alias" msgstr "" msgid "Change Password" msgstr "" msgid "Change your login password" msgstr "" #: postfixadmin_forward.php msgid "Edit Alias" msgstr "" msgid "Edit an alias* for your domain.
    One entry per line." msgstr "" msgid "The email address that you have entered is not valid:" msgstr "" msgid "Unable to locate alias!" msgstr "" msgid "Unable to modify the alias!" msgstr "" msgid "*Additional forward-aliase always recieve messages BBC!" msgstr "" msgid "Alias successfully changend!" msgstr "" #: postfixadmin_vacation.php msgid "Auto Response" msgstr "" msgid "Going Away" msgstr "" msgid "Coming Back" msgstr "" msgid "Options" msgstr "" msgid "Out of Office" msgstr "" msgid "Subject" msgstr "" msgid "Body" msgstr "" msgid "Your auto response has been removed!" msgstr "" msgid "Your auto response has been set!" msgstr "" msgid "You already have an auto response configured!" msgstr "" #: postfixadmin_changepass.php:81 postfixadmin_changepass.php:87 msgid "The passwords that you supplied don't match!
    Or are empty!" msgstr "" #: postfixadmin_forward.php:70 postfixadmin_forward.php:152 msgid "To" msgstr "" #: postfixadmin_changepass.php:101 msgid "Unable to change your password!" msgstr "" #: postfixadmin_changepass.php:75 msgid "You didn't supply your current password!" msgstr "" #: postfixadmin_changepass.php:96 msgid "Your password has been changed!" msgstr "" msgid "Password current" msgstr "" msgid "Password new" msgstr "" msgid "Password new again" msgstr "" msgid "Please sign out and log back again with your new password!" msgstr "" msgid "I will be away from until . For urgent matters you can contact ." msgstr "" postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/0000775000175000017620000000000012301477471023047 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/de_DE/0000775000175000017620000000000012301477471024007 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/de_DE/LC_MESSAGES/0000775000175000017620000000000012301477471025574 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/de_DE/LC_MESSAGES/postfixadmin.mo0000664000175000017620000000636511374336541030651 0ustar davidpalepurple",/<717 Tbgw  8  -DL ]j:}=5?4tw-($" Gh$G,.EU,eP!M b r @~    S ;O  + `  (# UL U 2 =+ .i , (      "! *Additional forward-aliase always recieve messages BBC!AliasAlias successfully changend!Auto ResponseBodyChange PasswordChange your login passwordChange your mailbox password.Coming BackEdit AliasEdit an alias* for your domain.
    One entry per line.ForwardingGoing AwayHere you can create and edit E-Mail forwards.OptionsPassword currentPassword newPassword new againPlease sign out and log back again with your new password!Set an OUT OF OFFICE message or auto responder for your mail.SubjectThe email address that you have entered is not valid:The passwords that you supplied don't match!
    Or are empty!ToUnable to change your password!Unable to locate alias!Unable to modify the alias!You already have an auto response configured!You didn't supply your current password!Your auto response has been removed!Your auto response has been set!Your password has been changed!backProject-Id-Version: 0.3-1.4 POT-Creation-Date: 2004-01-28 16:32+0100 PO-Revision-Date: 2004-01-28 16:32+0100 Last-Translator: FLORIAN KIMMERL Language-Team: GERMAN MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit *Zustzliche Weiterleitungen erhalten alle Nachrichten als Kopie (BCC)!E-MailWeiterleitungen wurden erfolgreich gendert!Abwesenheits-AssistentNachrichtentextPasswort ndernndern Sie Ihr Zugangspasswort fr POP3/IMAPHier knnen Sie Passwort ndern. Nach der nderung mssen Sie sich neu anmelden!Ich bin zurckE-Mail Weiterleitungen bearbeitenBearbeiten Sie hier Ihre E-Mail Weiterleitungen*.
    Ein Eintrag pro Zeile.WeiterleitungenIch bin wegHier knnen Sie E-Mail-Weiterleitungen erstellen und bearbeiten.OptionenPasswort aktuellPasswort neuPasswort neu nochmalBitte melden Sie sich hier ab und loggen sich mit Ihrem neuen Passwort erneut ein! Hier knnen Sie den Abwesenheits-Assistenten konfigurieren.BetreffDie angegebene E-Mail-Adresse ist ungltig:Die beiden neuen Passwrter stimmen nicht berein!
    Oder die Felder wurden nicht ausgefllt!AnIhr Passwort kann nicht gendert werden!Ihre Weiterleitungen knnen nicht angefordert werden! Versuchen Sie es spter erneut.Ihre Weiterleitungen knnen nicht modifiziert werden! Versuchen Sie es spter erneut.Ihre Abwesenheits-Nachricht ist bereits aktiviert!Ihr aktuelles Passwort wurde nicht angegeben oder ist falsch!Iher Abwesenheits-Nachricht wurde deaktiviert!Ihre Abwesenheits-Nachricht wurde aktiviert!Ihr Passwort wurde ergolgreich gendert!zurckpostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/de_DE/LC_MESSAGES/postfixadmin.po0000664000175000017620000000727411616351471030652 0ustar davidpalepurple# postfixadmin - Plugin for Squirrelmail. # Copyright (C) 2004 FLORIAN KIMMERL # This file is distributed under the same license as the PACKAGE package. # Florian Kimmerl , 2004. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: 0.3-1.4\n" "POT-Creation-Date: 2004-01-28 16:32+0100\n" "PO-Revision-Date: 2004-01-28 16:32+0100\n" "Last-Translator: FLORIAN KIMMERL \n" "Language-Team: GERMAN \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" #: setup.php msgid "Forwarding" msgstr "Weiterleitungen" msgid "Here you can create and edit E-Mail forwards." msgstr "Hier knnen Sie E-Mail-Weiterleitungen erstellen und bearbeiten." msgid "Set an OUT OF OFFICE message or auto responder for your mail." msgstr "Hier knnen Sie den Abwesenheits-Assistenten konfigurieren." msgid "Change your mailbox password." msgstr "Hier knnen Sie Passwort ndern. Nach der nderung mssen Sie sich neu anmelden!" #: postfixadmin_changepass.php msgid "Alias" msgstr "E-Mail" msgid "Change Password" msgstr "Passwort ndern" msgid "Change your login password" msgstr "ndern Sie Ihr Zugangspasswort fr POP3/IMAP" #: postfixadmin_forward.php msgid "Edit Alias" msgstr "E-Mail Weiterleitungen bearbeiten" msgid "Edit an alias* for your domain.
    One entry per line." msgstr "Bearbeiten Sie hier Ihre E-Mail Weiterleitungen*.
    Ein Eintrag pro Zeile." msgid "The email address that you have entered is not valid:" msgstr "Die angegebene E-Mail-Adresse ist ungltig:" msgid "Unable to locate alias!" msgstr "Ihre Weiterleitungen knnen nicht angefordert werden! Versuchen Sie es spter erneut." msgid "Unable to modify the alias!" msgstr "Ihre Weiterleitungen knnen nicht modifiziert werden! Versuchen Sie es spter erneut." msgid "*Additional forward-aliase always recieve messages BBC!" msgstr "*Zustzliche Weiterleitungen erhalten alle Nachrichten als Kopie (BCC)!" msgid "Alias successfully changend!" msgstr "Weiterleitungen wurden erfolgreich gendert!" #: postfixadmin_vacation.php msgid "Auto Response" msgstr "Abwesenheits-Assistent" msgid "Going Away" msgstr "Ich bin weg" msgid "Coming Back" msgstr "Ich bin zurck" msgid "Options" msgstr "Optionen" msgid "Out of Office" msgstr "" msgid "Subject" msgstr "Betreff" msgid "Body" msgstr "Nachrichtentext" msgid "Your auto response has been removed!" msgstr "Iher Abwesenheits-Nachricht wurde deaktiviert!" msgid "Your auto response has been set!" msgstr "Ihre Abwesenheits-Nachricht wurde aktiviert!" msgid "You already have an auto response configured!" msgstr "Ihre Abwesenheits-Nachricht ist bereits aktiviert!" msgid "back" msgstr "zurck" #: postfixadmin_changepass.php:81 postfixadmin_changepass.php:87 msgid "The passwords that you supplied don't match!
    Or are empty!" msgstr "Die beiden neuen Passwrter stimmen nicht berein!
    Oder die Felder wurden nicht ausgefllt!" #: postfixadmin_forward.php:70 postfixadmin_forward.php:152 msgid "To" msgstr "An" #: postfixadmin_changepass.php:101 msgid "Unable to change your password!" msgstr "Ihr Passwort kann nicht gendert werden!" #: postfixadmin_changepass.php:75 msgid "You didn't supply your current password!" msgstr "Ihr aktuelles Passwort wurde nicht angegeben oder ist falsch!" #: postfixadmin_changepass.php:96 msgid "Your password has been changed!" msgstr "Ihr Passwort wurde ergolgreich gendert!" msgid "Password current" msgstr "Passwort aktuell" msgid "Password new" msgstr "Passwort neu" msgid "Password new again" msgstr "Passwort neu nochmal" msgid "Please sign out and log back again with your new password!" msgstr "Bitte melden Sie sich hier ab und loggen sich mit Ihrem neuen Passwort erneut ein! " postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/pl_PL/0000775000175000017620000000000012301477471024055 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/pl_PL/LC_MESSAGES/0000775000175000017620000000000012301477471025642 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/pl_PL/LC_MESSAGES/postfixadmin.mo0000664000175000017620000000661711374336541030717 0ustar davidpalepurple$<5\071io   8 8 C-N]|  :!=\5?>Zz-($ *K+k2 8 J X ^ 'j '   E 4 B >V q   ) 4 %G Hm  + ,  n    &  &# %J p  #! $  "  *Additional forward-aliase always recieve messages BBC!AliasAlias successfully changend!Auto ResponseBodyChange PasswordChange your login passwordChange your mailbox password.Coming BackEdit AliasEdit an alias* for your domain.
    One entry per line.ForwardingGoing AwayHere you can create and edit E-Mail forwards.I will be away from until . For urgent matters you can contact .OptionsOut of OfficePassword currentPassword newPassword new againPlease sign out and log back again with your new password!Set an OUT OF OFFICE message or auto responder for your mail.SubjectThe email address that you have entered is not valid:The passwords that you supplied don't match!
    Or are empty!ToTo remove an alias, simply delete it's line from the text box.Unable to change your password!Unable to locate alias!Unable to modify the alias!You already have an auto response configured!You didn't supply your current password!Your auto response has been removed!Your auto response has been set!Your password has been changed!Project-Id-Version: PACKAGE VERSION POT-Creation-Date: 2004-01-29 17:35+0100 PO-Revision-Date: 2007-07-20 20:46+0100 Last-Translator: Krzysztof Laska Language-Team: LANGUAGE MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-2 Content-Transfer-Encoding: 8bit *Wszystkie dodatkowe adresy zawsze odbieraj wiadomoci przesyane jako BCC! Caa poczta jest przekazywana i nie jest przechowywana na koncie podstawowym!KontoZmiana zachowana!AutoodpowiedTreZmie hasoZmie haso do swojego konta pocztowegoZmie haso do swojego konta pocztowegoWycz autoodpowiedEdytuj adresy do przekazywaniaEdytuj forward* dla swojego konta.
    Kady adres w nowym wierszu.PrzekazywanieWcz autoodpowiedTutaj moesz ustawi i edytowa opcje przekazywania wiadomociNie bd odbiera poczty pomidzy a . W sprawach pilnych prosz kontaktowa si z OpcjeAutoodpowiedBiece hasoNowe hasoPowtrz nowe hasoWyloguj si i zaloguj z nowym hasem!Ustaw wiadomo wysyan nadawcom podczas Twojej nieobecnoci (Vacation)TematAdres e-mail jaki podae jest niepoprawny:Hasa ktre podae nie pasuj lub s puste!Doeby wyczy forward na dane konto po prostu usu lini z adresem na ktry nie chcesz ju przekazywa poczty.Nie mona zmieni hasa!Nie mona zlokalizowa aliasu!Nie mona zmodyfikowa aliasu!Masz ju skonfigurowan autoodpowied!Nie podae aktualnego hasa!Twoja autoodpowied zostaa wyczona!Twoja autoodpowied zostaa wczona!Twoje haso zostao zmienione!postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/pl_PL/LC_MESSAGES/postfixadmin.po0000664000175000017620000000742611374336541030721 0ustar davidpalepurple# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: 2004-01-29 17:35+0100\n" "PO-Revision-Date: 2007-07-20 20:46+0100\n" "Last-Translator: Krzysztof Laska \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-2\n" "Content-Transfer-Encoding: 8bit\n" #: setup.php msgid "Forwarding" msgstr "Przekazywanie" msgid "Here you can create and edit E-Mail forwards." msgstr "Tutaj moesz ustawi i edytowa opcje przekazywania wiadomoci" msgid "Set an OUT OF OFFICE message or auto responder for your mail." msgstr "Ustaw wiadomo wysyan nadawcom podczas Twojej nieobecnoci (Vacation)" msgid "Change your mailbox password." msgstr "Zmie haso do swojego konta pocztowego" #: postfixadmin_changepass.php msgid "Alias" msgstr "Konto" msgid "Change Password" msgstr "Zmie haso" msgid "Change your login password" msgstr "Zmie haso do swojego konta pocztowego" #: postfixadmin_forward.php msgid "Edit Alias" msgstr "Edytuj adresy do przekazywania" msgid "Edit an alias* for your domain.
    One entry per line." msgstr "Edytuj forward* dla swojego konta.
    Kady adres w nowym wierszu." msgid "The email address that you have entered is not valid:" msgstr "Adres e-mail jaki podae jest niepoprawny:" msgid "Unable to locate alias!" msgstr "Nie mona zlokalizowa aliasu!" msgid "Unable to modify the alias!" msgstr "Nie mona zmodyfikowa aliasu!" msgid "*Additional forward-aliase always recieve messages BBC!" msgstr "*Wszystkie dodatkowe adresy zawsze odbieraj wiadomoci przesyane jako BCC! Caa poczta jest przekazywana i nie jest przechowywana na koncie podstawowym!" msgid "Alias successfully changend!" msgstr "Zmiana zachowana!" msgid "To remove an alias, simply delete it's line from the text box." msgstr "eby wyczy forward na dane konto po prostu usu lini z adresem na ktry nie chcesz ju przekazywa poczty." #: postfixadmin_vacation.php msgid "Auto Response" msgstr "Autoodpowied" msgid "Going Away" msgstr "Wcz autoodpowied" msgid "Coming Back" msgstr "Wycz autoodpowied" msgid "Options" msgstr "Opcje" msgid "Out of Office" msgstr "Autoodpowied" msgid "Subject" msgstr "Temat" msgid "Body" msgstr "Tre" msgid "Your auto response has been removed!" msgstr "Twoja autoodpowied zostaa wyczona!" msgid "Your auto response has been set!" msgstr "Twoja autoodpowied zostaa wczona!" msgid "You already have an auto response configured!" msgstr "Masz ju skonfigurowan autoodpowied!" #: postfixadmin_changepass.php:81 #: postfixadmin_changepass.php:87 msgid "The passwords that you supplied don't match!
    Or are empty!" msgstr "Hasa ktre podae nie pasuj lub s puste!" #: postfixadmin_forward.php:70 #: postfixadmin_forward.php:152 msgid "To" msgstr "Do" #: postfixadmin_changepass.php:101 msgid "Unable to change your password!" msgstr "Nie mona zmieni hasa!" #: postfixadmin_changepass.php:75 msgid "You didn't supply your current password!" msgstr "Nie podae aktualnego hasa!" #: postfixadmin_changepass.php:96 msgid "Your password has been changed!" msgstr "Twoje haso zostao zmienione!" msgid "Password current" msgstr "Biece haso" msgid "Password new" msgstr "Nowe haso" msgid "Password new again" msgstr "Powtrz nowe haso" msgid "Please sign out and log back again with your new password!" msgstr "Wyloguj si i zaloguj z nowym hasem!" msgid "I will be away from until . For urgent matters you can contact ." msgstr "Nie bd odbiera poczty pomidzy a . W sprawach pilnych prosz kontaktowa si z " postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/pt_BR/0000775000175000017620000000000012301477471024055 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/pt_BR/LC_MESSAGES/0000775000175000017620000000000012301477471025642 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/pt_BR/LC_MESSAGES/postfixadmin.mo0000664000175000017620000000622111374336541030706 0ustar davidpalepurple",/<71 N\aq  8  -]>  :=\5d?-1(_$ /1P lz   F " - *4 _   / ; F =\ 4  J >" a &f  $ , 1 . N #m  !   " *Additional forward-aliase always recieve messages BBC!Alias successfully changend!Auto ResponseBodyChange PasswordChange your login passwordChange your mailbox password.Coming BackEdit AliasEdit an alias* for your domain.
    One entry per line.ForwardingGoing AwayHere you can create and edit E-Mail forwards.I will be away from until . For urgent matters you can contact .OptionsOut of OfficePassword currentPassword newPassword new againPlease sign out and log back again with your new password!Set an OUT OF OFFICE message or auto responder for your mail.SubjectThe email address that you have entered is not valid:The passwords that you supplied don't match!
    Or are empty!ToUnable to change your password!Unable to locate alias!Unable to modify the alias!You already have an auto response configured!You didn't supply your current password!Your auto response has been removed!Your auto response has been set!Your password has been changed!Project-Id-Version: PACKAGE VERSION POT-Creation-Date: 2004-01-29 17:35+0100 PO-Revision-Date: 2008-10-16 20:30+3 Last-Translator: Julio Covolato Language-Team: BRAZILIAN PORTUGUESE MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit *Alias adicionais sempre recebem mensagens em BCCAlias alterado com sucesso!Auto respostaMensagemMudar SenhaMude sua senha de loginTroque a senha de seu email.DesativarEditar AliasEditar um alias* para seu domínio.
    Uma entrada por linha.EncaminharAtivarAqui Você pode criar e editar alias.Estarei fora do escritório entre os dias e do mês de .
    Qualquer mensagem urgente, favor enviar para o email .OpçõesFora do escritóriosenha atualNova senhaConfirme a nova senhaPor favor, saia e entre novamente no webmail com a nova senhaConfigurar mensagem de férias para seu email.AssuntoEste endereço de email informado não é válido:A senha digitada não confere!
    Ou está vaziaParaImpossível alterar a sua senha!Alias não encontrado!Impossível modificar o alias!Você ainda tem uma auto resposta ativaVocê não forneceu a sua senha atual!Sua auto resporta foi removida!Sua auto resposta foi ativada!Sua senha foi alterada com sucesso!postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/pt_BR/LC_MESSAGES/postfixadmin.po0000664000175000017620000000710711616351471030713 0ustar davidpalepurple# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: 2004-01-29 17:35+0100\n" "PO-Revision-Date: 2008-10-16 20:30+3\n" "Last-Translator: Julio Covolato \n" "Language-Team: BRAZILIAN PORTUGUESE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" #: setup.php msgid "Forwarding" msgstr "Encaminhar" msgid "Here you can create and edit E-Mail forwards." msgstr "Aqui Você pode criar e editar alias." msgid "Set an OUT OF OFFICE message or auto responder for your mail." msgstr "Configurar mensagem de férias para seu email." msgid "Change your mailbox password." msgstr "Troque a senha de seu email." #: postfixadmin_changepass.php msgid "Alias" msgstr "" msgid "Change Password" msgstr "Mudar Senha" msgid "Change your login password" msgstr "Mude sua senha de login" #: postfixadmin_forward.php msgid "Edit Alias" msgstr "Editar Alias" msgid "Edit an alias* for your domain.
    One entry per line." msgstr "Editar um alias* para seu domínio.
    Uma entrada por linha." msgid "The email address that you have entered is not valid:" msgstr "Este endereço de email informado não é válido:" msgid "Unable to locate alias!" msgstr "Alias não encontrado!" msgid "Unable to modify the alias!" msgstr "Impossível modificar o alias!" msgid "*Additional forward-aliase always recieve messages BBC!" msgstr "*Alias adicionais sempre recebem mensagens em BCC" msgid "Alias successfully changend!" msgstr "Alias alterado com sucesso!" #: postfixadmin_vacation.php msgid "Auto Response" msgstr "Auto resposta" msgid "Going Away" msgstr "Ativar" msgid "Coming Back" msgstr "Desativar" msgid "Options" msgstr "Opções" msgid "Out of Office" msgstr "Fora do escritório" msgid "Subject" msgstr "Assunto" msgid "Body" msgstr "Mensagem" msgid "Your auto response has been removed!" msgstr "Sua auto resporta foi removida!" msgid "Your auto response has been set!" msgstr "Sua auto resposta foi ativada!" msgid "You already have an auto response configured!" msgstr "Você ainda tem uma auto resposta ativa" #: postfixadmin_changepass.php:81 postfixadmin_changepass.php:87 msgid "The passwords that you supplied don't match!
    Or are empty!" msgstr "A senha digitada não confere!
    Ou está vazia" #: postfixadmin_forward.php:70 postfixadmin_forward.php:152 msgid "To" msgstr "Para" #: postfixadmin_changepass.php:101 msgid "Unable to change your password!" msgstr "Impossível alterar a sua senha!" #: postfixadmin_changepass.php:75 msgid "You didn't supply your current password!" msgstr "Você não forneceu a sua senha atual!" #: postfixadmin_changepass.php:96 msgid "Your password has been changed!" msgstr "Sua senha foi alterada com sucesso!" msgid "Password current" msgstr "senha atual" msgid "Password new" msgstr "Nova senha" msgid "Password new again" msgstr "Confirme a nova senha" msgid "Please sign out and log back again with your new password!" msgstr "Por favor, saia e entre novamente no webmail com a nova senha" msgid "I will be away from until . For urgent matters you can contact ." msgstr "Estarei fora do escritório entre os dias e do mês de .
    Qualquer mensagem urgente, favor enviar para o email ." postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/hu_HU/0000775000175000017620000000000012301477471024057 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/hu_HU/LC_MESSAGES/0000775000175000017620000000000012301477471025644 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/hu_HU/LC_MESSAGES/postfixadmin.mo0000664000175000017620000000730111374336541030710 0ustar davidpalepurple&L5|PRQ  < H S`  - ]:  :=2p5x?>-Me-($ '>df       %2 8X   _ o > X  0 7 B R \ 8q Q  ! =$ Ub $   # !0#R&v#  !%#"& $  A copy of each message will go to both your mailbox and the forwarded address(es).AliasAlias successfully changed!Another copy also goes toAuto ResponseBodyChange PasswordChange your login passwordChange your mailbox password.Coming BackEdit AliasEdit ForwardEnter an email address (or addresses) where you would like an additional copy of messages addressed to you sent.
    Enter only one address per line.ForwardingGoing AwayHere you can create and edit E-Mail forwards.I will be away from until . For urgent matters you can contact .One copy always goes toOptionsOut of OfficePassword currentPassword newPassword new againPlease sign out and log back again with your new password!Set an OUT OF OFFICE message or auto responder for your mail.SubjectThe email address that you have entered is not valid:The passwords that you supplied don't match!
    Or are empty!To remove a Forward, simply delete its line from the text box.Unable to change your password!Unable to locate alias!Unable to modify the alias!You already have an auto response configured!You didn't supply your current password!Your auto response has been removed!Your auto response has been set!Your password has been changed!Project-Id-Version: 0.3-1.4 POT-Creation-Date: 2004-01-28 16:32+0100 PO-Revision-Date: 2004-01-28 16:32+0100 Last-Translator: FLORIAN KIMMERL Language-Team: HUNGARIAN MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-2 Content-Transfer-Encoding: 8bit Minden nnek cmzett levl meg fog rkezni a sajt postafikjba s a tovbbtott e-mail cmekre is.E-mailA mdosts sikeres!Tovbbi msolatok ideAutomatikus vlaszLevltrzsJelsz megvltoztatsaBejelentkezsi jelsz megvltoztatsaItt tudod megvltoztatni a belpshez szksges jelszt.VisszajttemLevltovbbts szerkesztseLevltovbbts szerkesztseSorolja fel azokat az e-mail cmeket, amelyekre az nhz rkez leveleket tovbbtani szeretn.
    Soronknt csak egy cmet adjon meg!LevltovbbtsHzonkvl vagyokItt tudod ltrehozni s szerkeszteni az E-mail tovbbtsokat.Hzonkvl leszek s kztt. Srgs esetben rtestend: .Egy msolat mindig ideOpcikHzonkvlAktulis jelszj jelszj jelsz mgegyszerKrjk, jelentkezzen ki, majd jra be az j jelszavval!Itt lehet belltani az automatikus vlasz levl szvegt, ha az ember tvol van.TrgyAz E-mail cm amit bertl hibs:A jelszavak nem egyeznek!
    Vagy resen hagytad a mezket!Ahhoz, hogy trljn egy tovbbtst, ki kell trlnie az adott sort a felsorolsbl.A jelsz megvltoztatsa sikertelen!Hiba az e-mail cmmel.A mdosts sikertelen!Mr ltezik egy automatikus vlasz!Az aktulis jelsz nem megfelel!Az automatikus vlasz trlve lett!Az automatikus vlasz be lett lltva!A jelsz vltoztatsa sikeres volt!postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/hu_HU/LC_MESSAGES/postfixadmin.po0000664000175000017620000001003311616351471030705 0ustar davidpalepurple# postfixadmin - Plugin for Squirrelmail. # Copyright (C) 2004 FLORIAN KIMMERL # This file is distributed under the same license as the PACKAGE package. # Florian Kimmerl , 2004. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: 0.3-1.4\n" "POT-Creation-Date: 2004-01-28 16:32+0100\n" "PO-Revision-Date: 2004-01-28 16:32+0100\n" "Last-Translator: FLORIAN KIMMERL \n" "Language-Team: HUNGARIAN \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-2\n" "Content-Transfer-Encoding: 8bit\n" #: setup.php msgid "Forwarding" msgstr "Levltovbbts" msgid "Here you can create and edit E-Mail forwards." msgstr "Itt tudod ltrehozni s szerkeszteni az E-mail tovbbtsokat." msgid "Set an OUT OF OFFICE message or auto responder for your mail." msgstr "Itt lehet belltani az automatikus vlasz levl szvegt, ha az ember tvol van." msgid "Change your mailbox password." msgstr "Itt tudod megvltoztatni a belpshez szksges jelszt." #: postfixadmin_changepass.php msgid "Alias" msgstr "E-mail" msgid "Change Password" msgstr "Jelsz megvltoztatsa" msgid "Change your login password" msgstr "Bejelentkezsi jelsz megvltoztatsa" #: postfixadmin_forward.php msgid "Edit Forward" msgstr "Levltovbbts szerkesztse" msgid "Edit Alias" msgstr "Levltovbbts szerkesztse" msgid "The email address that you have entered is not valid:" msgstr "Az E-mail cm amit bertl hibs:" msgid "Unable to locate alias!" msgstr "Hiba az e-mail cmmel." msgid "Unable to modify the alias!" msgstr "A mdosts sikertelen!" msgid "Alias successfully changed!" msgstr "A mdosts sikeres!" #: postfixadmin_vacation.php msgid "Auto Response" msgstr "Automatikus vlasz" msgid "Going Away" msgstr "Hzonkvl vagyok" msgid "Coming Back" msgstr "Visszajttem" msgid "Options" msgstr "Opcik" msgid "Out of Office" msgstr "Hzonkvl" msgid "Subject" msgstr "Trgy" msgid "Body" msgstr "Levltrzs" msgid "Your auto response has been removed!" msgstr "Az automatikus vlasz trlve lett!" msgid "Your auto response has been set!" msgstr "Az automatikus vlasz be lett lltva!" msgid "You already have an auto response configured!" msgstr "Mr ltezik egy automatikus vlasz!" #: postfixadmin_changepass.php:81 postfixadmin_changepass.php:87 msgid "The passwords that you supplied don't match!
    Or are empty!" msgstr "A jelszavak nem egyeznek!
    Vagy resen hagytad a mezket!" #: postfixadmin_changepass.php:101 msgid "Unable to change your password!" msgstr "A jelsz megvltoztatsa sikertelen!" #: postfixadmin_changepass.php:75 msgid "You didn't supply your current password!" msgstr "Az aktulis jelsz nem megfelel!" #: postfixadmin_changepass.php:96 msgid "Your password has been changed!" msgstr "A jelsz vltoztatsa sikeres volt!" msgid "Password current" msgstr "Aktulis jelsz" msgid "Password new" msgstr "j jelsz" msgid "Password new again" msgstr "j jelsz mgegyszer" msgid "Please sign out and log back again with your new password!" msgstr "Krjk, jelentkezzen ki, majd jra be az j jelszavval!" msgid "I will be away from until . For urgent matters you can contact ." msgstr "Hzonkvl leszek s kztt. Srgs esetben rtestend: ." msgid "One copy always goes to" msgstr "Egy msolat mindig ide" msgid "Another copy also goes to" msgstr "Tovbbi msolatok ide" msgid "Enter an email address (or addresses) where you would like an additional copy of messages addressed to you sent.
    Enter only one address per line." msgstr "Sorolja fel azokat az e-mail cmeket, amelyekre az nhz rkez leveleket tovbbtani szeretn.
    Soronknt csak egy cmet adjon meg!" msgid "A copy of each message will go to both your mailbox and the forwarded address(es)." msgstr "Minden nnek cmzett levl meg fog rkezni a sajt postafikjba s a tovbbtott e-mail cmekre is." msgid "To remove a Forward, simply delete its line from the text box." msgstr "Ahhoz, hogy trljn egy tovbbtst, ki kell trlnie az adott sort a felsorolsbl." postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/build.sh0000664000175000017620000000015511374336541024504 0ustar davidpalepurple#!/bin/bash for f in $(find . -name postfixadmin.po) do msgfmt -o $(dirname $f)/postfixadmin.mo $f done postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/it_IT/0000775000175000017620000000000012301477471024057 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/it_IT/LC_MESSAGES/0000775000175000017620000000000012301477471025644 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/it_IT/LC_MESSAGES/postfixadmin.po0000664000175000017620000000740411374336541030717 0ustar davidpalepurple# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: 2004-01-29 17:35+0100\n" "PO-Revision-Date: 2010-02-19 11:30+0100\n" "Last-Translator: valentina \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" #: setup.php msgid "Forwarding" msgstr "Inoltro E-MAIL" msgid "Here you can create and edit E-Mail forwards." msgstr "Qui puoi creare e modificare l'inoltro dell' E-MAIL." msgid "Set an OUT OF OFFICE message or auto responder for your mail." msgstr "Imposta un messaggio OUT OF OFFICE / ASSENTE o un risponditore automatico per la tua mail." msgid "Change your mailbox password." msgstr "Modifica la tua password di accesso alla mail" #: postfixadmin_changepass.php msgid "Alias" msgstr "Alias" msgid "Change Password" msgstr "Modifica password" msgid "Change your login password" msgstr "Modifica la tua password di accesso" #: postfixadmin_forward.php msgid "Edit Alias" msgstr "Modifica Alias" msgid "Edit an alias* for your domain.
    One entry per line." msgstr "Modifica un Alias per il tuo dominio.
    Un record per linea." msgid "The email address that you have entered is not valid:" msgstr "L'indirizzo email che hai inserito non è corretto:" msgid "Unable to locate alias!" msgstr "Impossibile trovare l'alias!" msgid "Unable to modify the alias!" msgstr "Impossibile modificare l'alias!" msgid "*Additional forward-aliase always recieve messages BBC!" msgstr "* L'inoltro ad un alias aggiuntivo comporta l'invio del messaggio in BCC!" msgid "Alias successfully changend!" msgstr "Alias modificato correttamente!" #: postfixadmin_vacation.php msgid "Auto Response" msgstr "Risponditore automatico" msgid "Going Away" msgstr "Going Away" msgid "Coming Back" msgstr "Coming Back" msgid "Options" msgstr "Opzioni" msgid "Out of Office" msgstr "Out of Office/Assente" msgid "Subject" msgstr "Oggetto" msgid "Body" msgstr "Messaggio" msgid "Your auto response has been removed!" msgstr "Il risponditore automatico è stato disattivato!" msgid "Your auto response has been set!" msgstr "Il risponditore automatico è stato configurato!" msgid "You already have an auto response configured!" msgstr "Hai gia configurato il risponditore automatico !" #: postfixadmin_changepass.php:81 #: postfixadmin_changepass.php:87 msgid "The passwords that you supplied don't match!
    Or are empty!" msgstr "Le password inserite non coincidono!
    O i campi sono vuoti!" #: postfixadmin_forward.php:70 #: postfixadmin_forward.php:152 msgid "To" msgstr "A" #: postfixadmin_changepass.php:101 msgid "Unable to change your password!" msgstr "Impossibile modificare la password" #: postfixadmin_changepass.php:75 msgid "You didn't supply your current password!" msgstr "Non hai indicato la password attuale!" #: postfixadmin_changepass.php:96 msgid "Your password has been changed!" msgstr "La tua password è stata modificata!" msgid "Password current" msgstr "Password attuale" msgid "Password new" msgstr "Nuova password" msgid "Password new again" msgstr "Insierisci nuovamente la nuova password" msgid "Please sign out and log back again with your new password!" msgstr "Per favore fai log out e riaccedi alla tua mail con la nuova password!" msgid "I will be away from until . For urgent matters you can contact ." msgstr "Mi dispiace sarò assente dal al . Per richieste urgenti vi prego di contattare . I will be away from until . For urgent matters you can contact ." postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/da_DK/0000775000175000017620000000000012301477471024011 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/da_DK/LC_MESSAGES/0000775000175000017620000000000012301477471025576 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/da_DK/LC_MESSAGES/postfixadmin.mo0000664000175000017620000000600011374336541030635 0ustar davidpalepurple#4/L7 AG drw  8  -&]T  :=4r5z?+-G(u$ 9U[j s~$ > / = 3J b~   # /9 Ii  ! 0   - E '` /     "   !# *Additional forward-aliase always recieve messages BBC!AliasAlias successfully changend!Auto ResponseBodyChange PasswordChange your login passwordChange your mailbox password.Coming BackEdit AliasEdit an alias* for your domain.
    One entry per line.ForwardingGoing AwayHere you can create and edit E-Mail forwards.I will be away from until . For urgent matters you can contact .OptionsOut of OfficePassword currentPassword newPassword new againPlease sign out and log back again with your new password!Set an OUT OF OFFICE message or auto responder for your mail.SubjectThe email address that you have entered is not valid:The passwords that you supplied don't match!
    Or are empty!ToUnable to change your password!Unable to locate alias!Unable to modify the alias!You already have an auto response configured!You didn't supply your current password!Your auto response has been removed!Your auto response has been set!Your password has been changed!Project-Id-Version: 0.4.3 POT-Creation-Date: 2004-01-29 17:35+0100 PO-Revision-Date: 2007-11-09 16:07+0100 Last-Translator: JESPER MEYER Language-Team: DANISH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit *Eksta vidersendingsalias modtager altid meddelelser BCC!AliasAlias ændret!AutosvarMeddelelseÆndre adgangskodeÆndre din login-adgangskodeÆndre adgangskoden til din postboksKommer tilbageRediger aliasRediger et alias* for dit domæne.
    En modtager pr. linje.VideresendingTager afstedHer kan du oprette og ændre email-videresendinger.Jeg er ikke tilstede i perioden til . I nødstilfælde kan kontaktes.IndstillingerIkke tilstedeNuværende adgangskodeNy adgangskodeNy adgangskode (igen)Log af og log ind igen med din nye adgangskode!Tilføj en 'ikke tilstede' besked eller et autosvar til din emailadresse.EmneEmailadressen du angav er ugyldigAdgangskoderne er ikke ens!
    Eller er tomme!TilKan ikke ændre adgangskoden!Aliaset eksistere ikke!Kunne ikke ændre aliaset!Du har allerede et autosvar indstillet!Du glemte at skrive din nuværende adgangskode!Autosvar er fjernet!Autosvar er aktiveret!Din adgangskode er ændret!postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/da_DK/LC_MESSAGES/postfixadmin.po0000664000175000017620000000674211374336541030655 0ustar davidpalepurple# Danish translation for Squirrelmail Plugin Postfixadmin. # Copyright (C) 2004 Florian Kimmerl, 2007 David Goodwin # This file is distributed under the same license as the Squirrelmail Plugin Postfixadmin package. # Jesper R. Meyer , 2007. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: 0.4.3\n" "POT-Creation-Date: 2004-01-29 17:35+0100\n" "PO-Revision-Date: 2007-11-09 16:07+0100\n" "Last-Translator: JESPER MEYER \n" "Language-Team: DANISH \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: setup.php msgid "Forwarding" msgstr "Videresending" msgid "Here you can create and edit E-Mail forwards." msgstr "Her kan du oprette og ændre email-videresendinger." msgid "Set an OUT OF OFFICE message or auto responder for your mail." msgstr "Tilføj en 'ikke tilstede' besked eller et autosvar til din emailadresse." msgid "Change your mailbox password." msgstr "Ændre adgangskoden til din postboks" #: postfixadmin_changepass.php msgid "Alias" msgstr "Alias" msgid "Change Password" msgstr "Ændre adgangskode" msgid "Change your login password" msgstr "Ændre din login-adgangskode" #: postfixadmin_forward.php msgid "Edit Alias" msgstr "Rediger alias" msgid "Edit an alias* for your domain.
    One entry per line." msgstr "Rediger et alias* for dit domæne.
    En modtager pr. linje." msgid "The email address that you have entered is not valid:" msgstr "Emailadressen du angav er ugyldig" msgid "Unable to locate alias!" msgstr "Aliaset eksistere ikke!" msgid "Unable to modify the alias!" msgstr "Kunne ikke ændre aliaset!" msgid "*Additional forward-aliase always recieve messages BBC!" msgstr "*Eksta vidersendingsalias modtager altid meddelelser BCC!" msgid "Alias successfully changend!" msgstr "Alias ændret!" #: postfixadmin_vacation.php msgid "Auto Response" msgstr "Autosvar" msgid "Going Away" msgstr "Tager afsted" msgid "Coming Back" msgstr "Kommer tilbage" msgid "Options" msgstr "Indstillinger" msgid "Out of Office" msgstr "Ikke tilstede" msgid "Subject" msgstr "Emne" msgid "Body" msgstr "Meddelelse" msgid "Your auto response has been removed!" msgstr "Autosvar er fjernet!" msgid "Your auto response has been set!" msgstr "Autosvar er aktiveret!" msgid "You already have an auto response configured!" msgstr "Du har allerede et autosvar indstillet!" #: postfixadmin_changepass.php:81 postfixadmin_changepass.php:87 msgid "The passwords that you supplied don't match!
    Or are empty!" msgstr "Adgangskoderne er ikke ens!
    Eller er tomme!" #: postfixadmin_forward.php:70 postfixadmin_forward.php:152 msgid "To" msgstr "Til" #: postfixadmin_changepass.php:101 msgid "Unable to change your password!" msgstr "Kan ikke ændre adgangskoden!" #: postfixadmin_changepass.php:75 msgid "You didn't supply your current password!" msgstr "Du glemte at skrive din nuværende adgangskode!" #: postfixadmin_changepass.php:96 msgid "Your password has been changed!" msgstr "Din adgangskode er ændret!" msgid "Password current" msgstr "Nuværende adgangskode" msgid "Password new" msgstr "Ny adgangskode" msgid "Password new again" msgstr "Ny adgangskode (igen)" msgid "Please sign out and log back again with your new password!" msgstr "Log af og log ind igen med din nye adgangskode!" msgid "I will be away from until . For urgent matters you can contact ." msgstr "Jeg er ikke tilstede i perioden til . I nødstilfælde kan kontaktes." postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/cs_CZ/0000775000175000017620000000000012301477471024050 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/cs_CZ/LC_MESSAGES/0000775000175000017620000000000012301477471025635 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/cs_CZ/LC_MESSAGES/postfixadmin.mo0000664000175000017620000000631211374336541030702 0ustar davidpalepurple$<5\071io   8 8 C-N]|  :!=\5?>Zz-($ *K/k&   & &5 \ f E + c s }   1 E / "7 /Z  A    ' B )^ (   #! $  "  *Additional forward-aliase always recieve messages BBC!AliasAlias successfully changend!Auto ResponseBodyChange PasswordChange your login passwordChange your mailbox password.Coming BackEdit AliasEdit an alias* for your domain.
    One entry per line.ForwardingGoing AwayHere you can create and edit E-Mail forwards.I will be away from until . For urgent matters you can contact .OptionsOut of OfficePassword currentPassword newPassword new againPlease sign out and log back again with your new password!Set an OUT OF OFFICE message or auto responder for your mail.SubjectThe email address that you have entered is not valid:The passwords that you supplied don't match!
    Or are empty!ToTo remove an alias, simply delete it's line from the text box.Unable to change your password!Unable to locate alias!Unable to modify the alias!You already have an auto response configured!You didn't supply your current password!Your auto response has been removed!Your auto response has been set!Your password has been changed!Project-Id-Version: PACKAGE VERSION POT-Creation-Date: 2004-01-29 17:35+0100 PO-Revision-Date: 2007-07-20 20:46+0100 Last-Translator: Michael Heca Language-Team: LANGUAGE MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-2 Content-Transfer-Encoding: 8bit Dal aliasy dostanou e-mail jako BBC!etPesmrovn bylo zmnno!Automatick odpovTlo mailuZmnit hesloZmnt heslo k Vaemu e-mailovmu tuZmnt heslo k Vaemu e-mailovmu tuJsem zptEditace adresy pro pesmrovnEditace pesmrovn pro V et.
    Kad adresa na novm dku.PesmrovnJsem mimoZde mete vytvoit a nastavit pesmrovnNebudy k zastien od do . Pro nalhan poadavky prosm kontaktujte .NastavenMimo kancelStvajc hesloNov hesloNov heslo znovuProsm odhlate se a pihlate se s novm heslem!Zde mete nastavit automatickou odpovd, pokud nebudete k zastien.PedmtZadan e-mailov adresa je chybn:Zadan hesla nejsou stejn a nebo jsou przdn!KomuPro odstranen pesmrovn smate vechny dky v textovm boxu.Nen mon zmnit heslo!Neni mon nalzt et!Nen mon zmnit et!U mte nastavenu automatickou odpov!Stvajc heslo neodpovd!Vae automatick odpov byla odstranna!Vae automatick odpov byla nastavena!Vae heslo bylo zmnno!postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/cs_CZ/LC_MESSAGES/postfixadmin.po0000664000175000017620000000712111374336541030704 0ustar davidpalepurple# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: 2004-01-29 17:35+0100\n" "PO-Revision-Date: 2007-07-20 20:46+0100\n" "Last-Translator: Michael Heca \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-2\n" "Content-Transfer-Encoding: 8bit\n" #: setup.php msgid "Forwarding" msgstr "Pesmrovn" msgid "Here you can create and edit E-Mail forwards." msgstr "Zde mete vytvoit a nastavit pesmrovn" msgid "Set an OUT OF OFFICE message or auto responder for your mail." msgstr "Zde mete nastavit automatickou odpovd, pokud nebudete k zastien." msgid "Change your mailbox password." msgstr "Zmnt heslo k Vaemu e-mailovmu tu" #: postfixadmin_changepass.php msgid "Alias" msgstr "et" msgid "Change Password" msgstr "Zmnit heslo" msgid "Change your login password" msgstr "Zmnt heslo k Vaemu e-mailovmu tu" #: postfixadmin_forward.php msgid "Edit Alias" msgstr "Editace adresy pro pesmrovn" msgid "Edit an alias* for your domain.
    One entry per line." msgstr "Editace pesmrovn pro V et.
    Kad adresa na novm dku." msgid "The email address that you have entered is not valid:" msgstr "Zadan e-mailov adresa je chybn:" msgid "Unable to locate alias!" msgstr "Neni mon nalzt et!" msgid "Unable to modify the alias!" msgstr "Nen mon zmnit et!" msgid "*Additional forward-aliase always recieve messages BBC!" msgstr "Dal aliasy dostanou e-mail jako BBC!" msgid "Alias successfully changend!" msgstr "Pesmrovn bylo zmnno!" msgid "To remove an alias, simply delete it's line from the text box." msgstr "Pro odstranen pesmrovn smate vechny dky v textovm boxu." #: postfixadmin_vacation.php msgid "Auto Response" msgstr "Automatick odpov" msgid "Going Away" msgstr "Jsem mimo" msgid "Coming Back" msgstr "Jsem zpt" msgid "Options" msgstr "Nastaven" msgid "Out of Office" msgstr "Mimo kancel" msgid "Subject" msgstr "Pedmt" msgid "Body" msgstr "Tlo mailu" msgid "Your auto response has been removed!" msgstr "Vae automatick odpov byla odstranna!" msgid "Your auto response has been set!" msgstr "Vae automatick odpov byla nastavena!" msgid "You already have an auto response configured!" msgstr "U mte nastavenu automatickou odpov!" #: postfixadmin_changepass.php:81 #: postfixadmin_changepass.php:87 msgid "The passwords that you supplied don't match!
    Or are empty!" msgstr "Zadan hesla nejsou stejn a nebo jsou przdn!" #: postfixadmin_forward.php:70 #: postfixadmin_forward.php:152 msgid "To" msgstr "Komu" #: postfixadmin_changepass.php:101 msgid "Unable to change your password!" msgstr "Nen mon zmnit heslo!" #: postfixadmin_changepass.php:75 msgid "You didn't supply your current password!" msgstr "Stvajc heslo neodpovd!" #: postfixadmin_changepass.php:96 msgid "Your password has been changed!" msgstr "Vae heslo bylo zmnno!" msgid "Password current" msgstr "Stvajc heslo" msgid "Password new" msgstr "Nov heslo" msgid "Password new again" msgstr "Nov heslo znovu" msgid "Please sign out and log back again with your new password!" msgstr "Prosm odhlate se a pihlate se s novm heslem!" msgid "I will be away from until . For urgent matters you can contact ." msgstr "Nebudy k zastien od do . Pro nalhan poadavky prosm kontaktujte ." postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/nl_NL/0000775000175000017620000000000012301477471024051 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/nl_NL/LC_MESSAGES/0000775000175000017620000000000012301477471025636 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/nl_NL/LC_MESSAGES/postfixadmin.mo0000664000175000017620000000647211374336541030712 0ustar davidpalepurple$<5\081jp   ? B M-X]  :+=f5?"=%c-($ 3T3t#   < 'S { @ $ ' p$     / , D )N Lx  3 ( && $M .r % * +  !#$   "  *Additional forward-aliases always receive messages BBC!AliasAlias successfully changed!Auto ResponseBodyChange PasswordChange your login passwordChange your mailbox password.Coming BackEdit ForwardsEdit an alias* for your email address.
    One entry per line.ForwardingGoing AwayHere you can create and edit E-Mail forwards.I will be away from until . For urgent matters you can contact .OptionsOut of OfficePassword currentPassword newPassword new againPlease sign out and log back again with your new password!Set an OUT OF OFFICE message or auto responder for your mail.SubjectThe email address that you have entered is not valid:The passwords that you supplied don't match!
    Or are empty!ToTo remove an alias, simply delete its line from the text box.Unable to change your password!Unable to locate alias!Unable to modify the alias!You already have an auto response configured!You didn't supply your current password!Your auto response has been removed!Your auto response has been set!Your password has been changed!Project-Id-Version: postfixadmin-squirrelmail 2.1.0 POT-Creation-Date: 2007-11-16 17:35+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: Johan Language-Team: LANGUAGE MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-2 Content-Transfer-Encoding: 8bit Aliassen ontvangen altijd per BCC! AliasAlias succesvol aangepastAutomatisch beantwoordenTekstVerander wachtwoordVerander uw login wachtwoordVerander uw wachtwoordIk ben terug, schakel Out of Office UITBewerk aliassenBewerk uw alias(sen) voor uw emailadres.
    1 alias per regel.DoorsturenIk ben weg, schakel Out of Office INHier kunt u uw doorstuur adres bewerkenIk ben niet aanwezig van tot . Voor dringende zaken kunt u contact opnemen met .OptiesOut of officeHuidig wachtwoordNieuw wachtwoordNieuw wachtwoord nogmaalsLog uit en opnieuw in met het nieuwe wachtwoordConfigureer hier uw automatisch beantwoordenOnderwerpHet ingevoerde adres is geen geldig adresDe wachtwoorden komen niet overeen!
    Of er is geen wachtwoord opgegeven!AanVerwijder de regel om de alias(sen) te verwijderen.Niet in staat uw wachtwoord te wijzigen!Niet in staat opgeven alias te vinden!Niet in staat de alias aan te passenAutomatisch beantwoorden is al geconfigureerd!U moet uw huidige wachtwoord opgeven!Uw automatisch beantwoorden is verwijderd!Uw automatisch beantwoorden is geactiveerd!Uw wachtwoord is gewijzigd!postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/locale/nl_NL/LC_MESSAGES/postfixadmin.po0000664000175000017620000000730411374336541030710 0ustar davidpalepurple# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: postfixadmin-squirrelmail 2.1.0\n" "POT-Creation-Date: 2007-11-16 17:35+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Johan \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-2\n" "Content-Transfer-Encoding: 8bit\n" #: setup.php msgid "Forwarding" msgstr "Doorsturen" msgid "Here you can create and edit E-Mail forwards." msgstr "Hier kunt u uw doorstuur adres bewerken" msgid "Set an OUT OF OFFICE message or auto responder for your mail." msgstr "Configureer hier uw automatisch beantwoorden" msgid "Change your mailbox password." msgstr "Verander uw wachtwoord" #: postfixadmin_changepass.php msgid "Alias" msgstr "Alias" msgid "Change Password" msgstr "Verander wachtwoord" msgid "Change your login password" msgstr "Verander uw login wachtwoord" #: postfixadmin_forward.php msgid "Edit Forwards" msgstr "Bewerk aliassen" msgid "Edit an alias* for your email address.
    One entry per line." msgstr "Bewerk uw alias(sen) voor uw emailadres.
    1 alias per regel." msgid "The email address that you have entered is not valid:" msgstr "Het ingevoerde adres is geen geldig adres" msgid "Unable to locate alias!" msgstr "Niet in staat opgeven alias te vinden!" msgid "Unable to modify the alias!" msgstr "Niet in staat de alias aan te passen" msgid "*Additional forward-aliases always receive messages BBC!" msgstr "Aliassen ontvangen altijd per BCC! " msgid "To remove an alias, simply delete its line from the text box." msgstr "Verwijder de regel om de alias(sen) te verwijderen." msgid "Alias successfully changed!" msgstr "Alias succesvol aangepast" #: postfixadmin_vacation.php msgid "Auto Response" msgstr "Automatisch beantwoorden" msgid "Going Away" msgstr "Ik ben weg, schakel Out of Office IN" msgid "Coming Back" msgstr "Ik ben terug, schakel Out of Office UIT" msgid "Options" msgstr "Opties" msgid "Out of Office" msgstr "Out of office" msgid "Subject" msgstr "Onderwerp" msgid "Body" msgstr "Tekst" msgid "Your auto response has been removed!" msgstr "Uw automatisch beantwoorden is verwijderd!" msgid "Your auto response has been set!" msgstr "Uw automatisch beantwoorden is geactiveerd!" msgid "You already have an auto response configured!" msgstr "Automatisch beantwoorden is al geconfigureerd!" #: postfixadmin_changepass.php:81 postfixadmin_changepass.php:87 msgid "The passwords that you supplied don't match!
    Or are empty!" msgstr "De wachtwoorden komen niet overeen!
    Of er is geen wachtwoord opgegeven!" #: postfixadmin_forward.php:70 postfixadmin_forward.php:152 msgid "To" msgstr "Aan" #: postfixadmin_changepass.php:101 msgid "Unable to change your password!" msgstr "Niet in staat uw wachtwoord te wijzigen!" #: postfixadmin_changepass.php:75 msgid "You didn't supply your current password!" msgstr "U moet uw huidige wachtwoord opgeven!" #: postfixadmin_changepass.php:96 msgid "Your password has been changed!" msgstr "Uw wachtwoord is gewijzigd!" msgid "Password current" msgstr "Huidig wachtwoord" msgid "Password new" msgstr "Nieuw wachtwoord" msgid "Password new again" msgstr "Nieuw wachtwoord nogmaals" msgid "Please sign out and log back again with your new password!" msgstr "Log uit en opnieuw in met het nieuwe wachtwoord" msgid "I will be away from until . For urgent matters you can contact ." msgstr "Ik ben niet aanwezig van tot . Voor dringende zaken kunt u contact opnemen met ." postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/README0000664000175000017620000000350211374336541022471 0ustar davidpalepurpleSquirrelmail Plugin Postfixadmin ******************************** The Postfixadmin SquirrelMail plugin let users change their virtual alias, vacation status/message and password if you are using the great postfixadmin tool from http://high5.net/postfixadmin Version 0.4.3 2007/08/14 Postfixadmin - Postfixadmin+MySQL/PgSQL plugin for Squirrelmail Author: Florian Kimmerl Author: Sam Brookes - Initial conversion to MDB2 - Fix SQL Injections etc Author: David Goodwin - Subsequent tidyup + testing etc Author: Krzysztof 'Mad Max' Laska - - Polish Translation. The Initial Developer of the Original postfixadmin Code is Mischa Peters. Portions created by Mischa Peters are Copyright (c) 2002, 2003, 2004. All Rights Reserved. REQUIREMENTS o SquirrelMail 1.4x o A working Mail-System "Virtual Domains and Users with postfix+Courier-IMAP+MySQL" (or PostgreSQL) See http://high5.net/howto/ o POSTFIXADMIN version 2.2.0 or higher. See http://sf.net/projects/postfixadmin o This plugin only uses the postfixadmin database o Pear MDB2 database abstraction layer - see http://pear.php.net o PHP installation with register globals TURNED OFF (huraren on IRC reports that the MDB2 driver isn't happy with it turned on) INSTALLATION See the included file INSTALL BUGS o Probably vulnerable to cross site scripting, certainly when setting the vacation message. o There may be some remaining SQL injection holes. TODO -Code Cleanup -Tranlation TRANSLATIONS Translations are welcome! Send the *.po-File to: david@NO.codepoets.SPAM.co.uk ACKNOWLEDGMENTS Thanks to the SquirrelMail team for building such a great app and for all the work they do to keep it running. Thanks to high5.net for writing the great Postfixadmin tool postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/postfixadmin_changepass.php0000664000175000017620000001135011374336541027223 0ustar davidpalepurplegetProxy('user'); global $username; do_header(); $USERID_USERNAME = $username; $tmp = preg_split ('/@/', $USERID_USERNAME); $USERID_DOMAIN = $tmp[1]; $stMessage = ''; $tMessage = ''; $pPassword_admin_text = ''; $pPassword_password_current_text = ''; $pPassword_password_text = ''; $error = 0; if ($_SERVER['REQUEST_METHOD'] == "POST") { //$pPassword_password_text = _("pPassword_password_text"); $fPassword_current = $_POST['fPassword_current']; $fPassword = $_POST['fPassword']; $fPassword2 = $_POST['fPassword2']; $username = $USERID_USERNAME; if(!$user->login($_SESSION['username'], $_POST['fPassword_current'])) { $error = 1; bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); $pPassword_password_current_text = _("You didn't supply your current password!"); bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); } $min_length = 0; if(isset($CONF['min_password_length'])) { $min_length = $CONF['min_password_length']; } if (empty ($fPassword) or ($fPassword != $fPassword2) or ($min_length > 0 && strlen($fPassword) < $min_length)) { $error = 1; bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); if(empty($fPassword)) { $pPassword_password_text .= _("The passwords that you supplied are empty!"); } if($fPassword != $fPassword2) { $pPassword_password_text .= _("The passwords that you supplied don't match!"); } if($min_length > 0 && strlen($fPassword) < $min_length) { $pPassword_password_text .= _("The password you supplied is too short!"); } bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); } if ($error != 1) { $success = $user->changePassword($fPassword_current, $fPassword); if ($success) { bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); $tMessage = _("Your password has been changed!"); $stMessage = _("Please sign out and log back again with your new password!"); bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); } else { bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); $tMessage = _("Unable to change your password!"); bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); } } } bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); echo "
    ". _("Options") ." - ". _("Change Password")."

    " ._("Change your login password") ."\n
    $tMessage
    $stMessage ".$pPassword_admin_text."\n ".$pPassword_password_current_text."\n ".$pPassword_password_text."\n
    ". _("Alias") . ":\n {$_SESSION['username']}
    ". _("Password current"). ":\n
    ". _("Password new"). ":\n
    ". _("Password new again"). ":\n
       
     

    "; bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); ?> postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/LICENSE.txt0000664000175000017620000000304511374336541023436 0ustar davidpalepurple 2007/03/29 : Before I (David Goodwin) customised this plugin, it contained the following within all files as a header. /**************************************************************************************** Author ......... Florian Kimmerl Contact ........ info@spacekoeln.de Home Site ...... http://www.spacekoeln.de/ Program ........ postfixadmin Purpose ........ Allows you to change your postfixadmin settings within squirrelmail ************************************************************************************* The Original Code is Postfix Admin. The Initial Developer of the Original Code is Mischa Peters . Portions created by Mischa Peters are Copyright (c) 2002, 2003, 2004. All Rights Reserved. Contributor(s): This project includes work by Mischa Peters and others that is: Copyright (c) 2002,2003,2004 Mischa Peters All rights reserved. ****************************************************************************************/ Contacting the author provided no success, so I took over maintainership. Please note: 1) Changes made by myself (David Goodwin) will be licensed under the GPL 2) PostfixAdmin has itself been relicensed under the GPL; however this took place _after_ this plugin was written. 3) Squirrelmail itself is released under http://squirrelmail.org/wiki/SquirrelMailGPL (GPL) The GNU public license can be found online at : http://www.gnu.org/licenses/gpl.txt postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/version0000664000175000017620000000002311374336541023214 0ustar davidpalepurplepostfixadmin 2.3.0 postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/index.php0000664000175000017620000000151211374336541023430 0ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/setup.php0000664000175000017620000000400711374336541023463 0ustar davidpalepurple _("Forwarding"), 'url' => '../plugins/postfixadmin/postfixadmin_forward.php', 'desc' => _("Here you can create and edit E-Mail forwards."), 'js' => FALSE ); bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); if($AllowVacation) { $optpage_blocks[] = array( 'name' => _("Auto Response"), 'url' => '../plugins/postfixadmin/postfixadmin_vacation.php', 'desc' => _("Set an OUT OF OFFICE message or auto responder for your mail."), 'js' => false ); bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); } bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); if($AllowChangePass) { $optpage_blocks[] = array( 'name' => _("Change Password"), 'url' => '../plugins/postfixadmin/postfixadmin_changepass.php', 'desc' => _("Change your mailbox password."), 'js' => false ); bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); } } ?> postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/postfixadmin_forward.php0000664000175000017620000001116611374336541026560 0ustar davidpalepurplegetProxy('alias'); do_header(); // Normal page request (GET) if ($_SERVER['REQUEST_METHOD'] == "GET") { $row = $alias->get(); if($row === false) { bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); $tMessage = _("Unable to locate alias!"); bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); exit(0); } } if ($_SERVER['REQUEST_METHOD'] == "POST") { $pEdit_alias_goto = _("To"); $fGoto = $_POST['fGoto']; // reform string into a list... $goto = preg_replace ('/\r\n/', ',', $fGoto); $goto = preg_replace ('/[\s]+/i', '', $goto); $goto = preg_replace ('/\,*$/', '', $goto); $array = preg_split ('/,/', $goto); $error = 0; // check that we have valid addresses in the list foreach($array as $email_address) { if (empty($email_address)) { continue; } if (!check_email($email_address)) { $error = 1; $tGoto = $goto; bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); $tMessage = _("The email address that you have entered is not valid:") . " $email_address"; bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); } } if ($error != 1) { $flag = 'forward_and_store'; // goto = $USERID_USERNAME; $success = $alias->update($array, $flag); if(!$success) { bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); $tMessage = _("Unable to modify the alias!"); bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); } else { bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); echo "

    ". _("Alias successfully changed!"). "\n

    "; bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); echo "

    ". _("Click here to go back") ."

    "; exit; } } } bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); echo "
    ". _("Options") ." - ". _("Edit Alias"). "
    ". _("Edit an alias* for your email address.
    One entry per line."). "
    ". _("*Additional forward-aliases always receive messages BCC!"). "\n
    " . _("To remove an alias, simply delete its line from the text box.") . "
    ". _("Edit Forwards"). "
    $tMessage
    ". _("Alias"). ":\n " . $_SESSION['username'] . "
       
    ". _("To"). ":\n
       
     
    "; bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); ?> postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/debian/0000775000175000017620000000000012301477471023032 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/debian/postfixadmin-squirrelmail.dirs0000664000175000017620000000015511374336541031133 0ustar davidpalepurpleusr/share/squirrelmail/plugins/postfixadmin usr/share/doc/squirrelmail-postfixadmin etc/squirrelmail/plugins postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/debian/postinst0000664000175000017620000000042611374336541024643 0ustar davidpalepurple#!/bin/sh echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" echo "WARNING: You need to read /usr/share/doc/squirrelmail-postfixadmin/README.Debian!" echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/debian/changelog0000664000175000017620000000160711374336541024711 0ustar davidpalepurplesquirrelmail-postfixadmin (2.3.0) stable; urgency=low * Using XMLRPC backend (no SQL here) -- David Goodwin Mon, 01 Feb 2010 09:56:00 +0000 squirrelmail-postfixadmin (2.2.0) stable; urgency=low * Changed DB backend to use prepared statements * Changed vacation handling to match that of Postfixadmin (vacation.active etc) * Changed vacation page to support UTF8 -- David Goodwin Wed, 20 Aug 2008 15:25:00 +0000 squirrelmail-postfixadmin (2.1.1-1) stable; urgency=low * Add NL language support * Better db error logging (e.g. if wrong mdb2 driver specified etc) -- David Goodwin Wed, 12 Dec 2007 16:00:00 +0000 squirrelmail-postfixadmin (2.1.0-1) stable; urgency=low * Initial release. -- David Goodwin Thu, 8 Nov 2007 20:00:00 +0000 postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/debian/copyright0000664000175000017620000000042411374336541024766 0ustar davidpalepurpleThis package was debianized by David Goodwin 2007/11/08 It was downloaded from: http://squirremail-postfixadmin.palepurple.co.uk Upstream Author(s): n/a Copyright: Copyright (C) 2007+ by David Goodwin License: GPL v2+ postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/debian/README.Debian0000664000175000017620000000103011374336541025066 0ustar davidpalepurpleSquirrelmail PostfixAdmin Plugin for Debian =========================================== After installing the package, you will need to : 1) Edit the config.inc.php file to point to the PostfixAdmin server. 2) Ensure the xmlrpc interface is available and enabled on the Postfixadmin server 3) Run the squirrelmail-configure script. Where to get help ================= See http://squirrelmail-postfixadmin.palepurple.co.uk Try also : david [at] pale purple dot co dot uk Or #postfixadmin on irc.freenode.net might be a good bet. postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/debian/conffiles0000664000175000017620000000006211374336541024724 0ustar davidpalepurple/etc/squirrelmail/plugins/postfixadmin-config.php postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/debian/files0000664000175000017620000000006611374336541024062 0ustar davidpalepurplesquirrelmail-postfixadmin_2.2.0_all.deb mail optional postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/debian/rules0000775000175000017620000000262311374336541024116 0ustar davidpalepurple#!/usr/bin/make -f # debian/rules makefile for squirrelmail # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 build: build-stamp build-stamp: dh_testdir clean: dh_testdir dh_testroot dh_clean install: build $(checkdir) dh_testdir dh_testroot dh_clean -k dh_installdirs dh_install mkdir -p debian/tmp/usr/share/squirrelmail/plugins/postfixadmin cp -a *.php version debian/tmp/usr/share/squirrelmail/plugins/postfixadmin cp -a locale debian/tmp/usr/share/squirrelmail/plugins/postfixadmin cp -a po debian/tmp/usr/share/squirrelmail/plugins/postfixadmin mkdir -p debian/tmp/etc/squirrelmail/plugins/ cp -a *.sample debian/tmp/etc/squirrelmail/plugins/postfixadmin-config.php mkdir -p debian/tmp/DEBIAN cp debian/postinst debian/tmp/DEBIAN/postinst chmod 555 debian/tmp/DEBIAN/postinst ln -s /etc/squirrelmail/plugins/postfixadmin-config.php debian/tmp/usr/share/squirrelmail/plugins/postfixadmin/config.php find debian/tmp -name .svn | xargs -r rm -r # Build architecture-independent files here. binary-indep: build install dh_testdir dh_testroot dh_installdebconf dh_installdocs -X.svn dh_installexamples dh_installman dh_installcron dh_link dh_compress dh_fixperms -X/var dh_installdeb dh_gencontrol dh_md5sums dh_builddeb # Build architecture-dependent files here. binary-arch: binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/debian/control0000664000175000017620000000132211374336541024434 0ustar davidpalepurpleSource: squirrelmail-postfixadmin Section: mail Priority: optional Maintainer: David Goodwin Standards-Version: 3.6.1 Package: squirrelmail-postfixadmin Architecture: all Depends: squirrelmail, php-pear Suggests: postfixadmin Description: Plugin for Squirrelmail to integrate with Postfixadmin Postfixadmin is a web based interface for managing mail domains and users. This package integrates Squirrelmail with it. Users can change their password, forwarding and vacation settings from within Squirrelmail when this package is installed, and enabled through the ./squirrelmail-configure command. . For further information see http://squirrelmail-postfixadmin.palepurple.co.uk postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/debian/docs0000775000175000017620000000006011374336541023705 0ustar davidpalepurpleLICENSE.txt README INSTALL debian/README.Debian postfixadmin-2.3.7/ADDITIONS/squirrelmail-plugin/postfixadmin_vacation.php0000664000175000017620000001437211374336541026722 0ustar davidpalepurplegetProxy('vacation'); $VACCONFTXT = _("I will be away from until . For urgent matters you can contact ."); bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); $VACCONF = <<getDetails(); if($vacation->checkVacation()) { bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); $tMessage = _("You already have an auto response configured!"); bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); echo "
    ". _("Options") ." - ". _("Auto Response") ."

    ". _("Auto Response") ."\n
    $tMessage

     

    "; bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); } else { $tSubject = "Out of Office"; $tSubject = $details['subject']; $VACCONF = $details['body']; $tMessage = ''; bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); echo "
    ". _("Options") ." - ". _("Auto Response") ."

    " . _("Auto Response") ."\n
    $tMessage
    ". _("Subject") .":\n      
    ". _("Body") .":\n     
         
     

    "; bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); } } if ($_SERVER['REQUEST_METHOD'] == "POST") { $fBack = null; $fAway = null; foreach(array('fBack', 'fAway', 'fSubject', 'fBody') as $key) { $$key = null; if(isset($_POST[$key])) { $$key = $_POST[$key]; } } if (!empty($fBack)) { $success = $vacation->remove(); if(!$success) { bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); $tMessage = _("Unable to update your auto response settings!"); echo "

    This may signify an error; please contact support (1)

    "; bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); } else { bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); echo "

    ". _("Your auto response has been removed!") ."

    "; bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); } } if (!empty ($fAway)) { // add record into vacation $success = $vacation->setAway($fSubject, $fBody); if(!$success) { $error = 1; bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); $tMessage = _("Unable to update your auto response settings!"); bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); } else { bindtextdomain('postfixadmin', SM_PATH . 'plugins/postfixadmin/locale'); textdomain('postfixadmin'); echo "

    ". _("Your auto response has been set!") ."

    "; bindtextdomain('squirrelmail', SM_PATH . 'locale'); textdomain('squirrelmail'); } } } ?> postfixadmin-2.3.7/ADDITIONS/virtualmaildel.php0000664000175000017620000001024610715711016021326 0ustar davidpalepurple // // You can run this from your crontab with something like // // 0 4 * * * * vmail php -q virtualmaildel.php >/dev/null // // Setup location of postfixadmin config files. Needed to login to mysql // $conf = '/home/httpd/mail/admin/config.inc.php'; // // Where's the homedir accounts stored. (GET THIS RIGHT OTHERWISE IT THINK NONE EXIST AND DELETES ALL) // $homedir = '/home/virtual'; // // Make sure everything is everything before continuing // if ( ! file_exists( $conf ) ) die( "Cannot find config file $conf\n" ); if ( ! is_dir( $homedir ) ) die( "Cannot find home directory for virtual mailboxes in $homedir\n" ); // // Load mysql authentication from postfixadmin // include( $conf ); // // Recursive Delete Function // function deldir($dir) { $current_dir = opendir($dir); while($entryname = readdir($current_dir)) { if(is_dir("$dir/$entryname") and ($entryname != "." and $entryname!="..")) { deldir("${dir}/${entryname}"); } elseif($entryname != "." and $entryname!="..") { unlink("${dir}/${entryname}"); } } closedir($current_dir); @rmdir(${dir}); } // --- Main Start --- // // Get list of directories // $fr = opendir( $homedir ); while ( ($domain = readdir($fr)) !== false) { // // Check if it's a dir // if ( $domain != "." and $domain != ".." and filetype($homedir .'/'. $domain) == "dir" ) { // // Open the (assumed) DOMAIN directory // $ff = opendir( $homedir .'/'. $domain ); while ( ($user = readdir($ff)) !== false) { // // Check for directories assuming it's a user account // if ( $user!="." and $user!=".." and filetype($homedir .'/'. $domain .'/'. $user) == "dir" ) { // // if the dir 'new' exists inside then it's an account // if ( file_exists($homedir .'/'. $domain .'/'. $user .'/'. "new") ) { $dir[$domain][$user] = ""; } else { // // Alert that the dir doesn't have a 'new' dir, possibly not an account. Leave it. // echo "UNKNOWN : " . $homedir ."/". $domain ."/". $user ."/new NOT FOUND. Possibly not an account. Leaving untouched\n"; } } } } } // // OK, got an array of accounts from the dir, Now connect to the DB and check them // $conx = mysql_connect( $CONF['database_host'],$CONF['database_user'],$CONF['database_password'] ); // // Is there a problem connecting? // if ( $conx != false ) { // // Select the database // mysql_select_db( $CONF['database_name'] , $conx) or die ("Can't access database postfix : " . mysql_error()); // // Select all mailboxes to verify against dirs listed in array // $query = "SELECT * FROM mailbox"; $result = mysql_query( $query ); // // Query the mailbox table // if ( $result != false ) { // // Fetch the list of results // while ( $row = mysql_fetch_assoc( $result ) ) { // // Pull apart the maildir field, needed to figure out the directory structure to compare // $strip = explode("/",$row['maildir']); // // Unset the array if it exists. This stops it being erased later. // unset( $dir[ $strip[0] ][ $strip[1] ] ); } // // If there are results. unset the domain too. // if ( count($dir[$strip[0]])==0 and mysql_num_rows($result)>0 ) unset( $dir[$strip[0]] ); } else die( "Failed SELECT in mailboxes\n" ); } else die( 'Cannot connect to the database!\n' ); // // OK, time to clean up. All known users/domains have been removed from the list. // // // If the array still exists (incase nothing there) // if ( is_array($dir) ) { // // Go through each dir // foreach ( $dir as $key => $value ) { // // Is this a user array? // if ( is_array( $value) ) { // // Go through and nuke the folders // foreach ( $value as $user => $value2 ) { // // Nuke.. need any more explanations? // echo "REMOVING : " . $homedir."/".$key."/".$user."\n" ; deldir( $homedir."/".$key."/".$user ) ; } } } } // // And we are outta here.... // echo "Cleanup process completed\n"; ?> postfixadmin-2.3.7/ADDITIONS/README.TXT0000664000175000017620000000256610715711016017143 0ustar davidpalepurple# # Postfix Admin ADDITIONS # BEFORE YOU START ---------------- **** ALL THESE SCRIPTS ARE CREATED BY THIRD PARTIES **** **** THEY ARE AS IS, USE AT YOUR OWN RISK! **** ADDITIONS --------- In this directory you will find additional scripts that are build by others. - change_password.tgz by George Vieira SquirrelMail plugin to change your passwor - cleanupdirs.pl by jared bell Displays a list of mailboxes that need to be deleted - mailbox_remover.pl by Petr Znojemsky Deletes all unused mailboxes - mkeveryone.pl by Joshua Preston Generate an 'everybody' alias for a domain. - pfa_maildir_cleanup.pl by Stephen Fulton Deletes all unused mailboxes - postfixadmin-0.3-1.4.tar.gz by Florian Kimmerl The Postfixadmin SquirrelMail plugin let users change their virtual alias, vacation status/message and password. - virtualmaildel.php by George Vieira Deletes all unused mailboxes - postfixadmin-mailbox-postcreation.sh - postfixadmin-mailbox-postdeletion.sh - postfixadmin-domain-postdeletion.sh by Troels Arvin Examples of scripts relevant to the optional $CONF['mailbox_postcreation_script'], $CONF['mailbox_postdeletion_script'] and $CONF['domain_postdeletion_script'] configuration options. postfixadmin-2.3.7/ADDITIONS/mailbox_remover.pl0000664000175000017620000000744510715711016021335 0ustar davidpalepurple#!/usr/bin/perl # # by Petr Znojemsky (c) 2004 # Mailbox remover 0.1a 23/10/2004 - the very first version for MySQL # removes maildirs from disk when they are not found in a database # # Added subdir support and pause --- Alan Batie 2007 # Lists directories to be deleted then pauses for 5 seconds for chance to abort # $Id: mailbox_remover.pl 211 2007-11-11 23:36:46Z christian_boltz $ # # All your maildirs or other directories could be accidentally removed. # Use it at own risk. No warranties! use strict; use DBI; use File::Path; ########## # Set these variables according to your configuration # when mailboxes are removed, save their tarballs here my $archdir="/var/archive/mailboxes"; # expected to support z option, tweak invocation if you want different my $archcmd="/usr/bin/tar"; # trailing slash not needed my $maildir_path="/var/mail"; # find out if we need to check subdirs for mailboxes or just maildir_path # $CONF['domain_path'] = 'YES'; my $pfadmin_config="/usr/local/www/postfixadmin/config.inc.php"; # database information my $host="localhost"; my $port="3306"; my $userid="dbuser"; my $passwd="dbpw"; my $db="dbname"; ############ my $connectionInfo="DBI:mysql:database=$db;$host:$port"; # make connection to database my $dbh = DBI->connect($connectionInfo,$userid,$passwd); # prepare and execute query my $query = "SELECT maildir FROM mailbox"; my $sth = $dbh->prepare($query); $sth->execute(); # assign fields to variables my ($db_maildir, %db_maildirs); $sth->bind_columns(\$db_maildir); # load up directory list while($sth->fetch()) { $db_maildirs{$db_maildir} = 1; } $sth->finish(); # disconnect from database $dbh->disconnect; # # find out if we need to check subdirs for mailboxes or just maildir_path # $CONF['domain_path'] = 'YES'; # my $use_subdirs = 0; open(CONFIG, "<$pfadmin_config") || die "Can't open '$pfadmin_config': $!\n"; while() { if (/\$CONF\['domain_path'\] *= *'([^']*)'/) { $use_subdirs = ($1 =~ /yes/i); } } close(CONFIG); # store maildir list to %directories # key is path, value is username to use in archive file my %directories; opendir(DIR, $maildir_path) || die "Cannot open dir $maildir_path: $!\n"; foreach my $name (readdir(DIR)) { next if ($name eq '.' || $name eq '..' || ! -d "$maildir_path/$name"); if ($use_subdirs) { opendir(SUBDIR, "$maildir_path/$name") || die "Cannot open dir $maildir_path/$name: $!\n"; foreach my $subname (readdir(SUBDIR)) { next if ($subname eq '.' || $subname eq '..' || ! -d "$maildir_path/$name/$subname"); # db entry has trailing slash... if (!defined($db_maildirs{"$name/$subname/"})) { print "marking $maildir_path/$name/$subname for deletion.\n"; $directories{"$name/$subname"} = "$name-$subname"; } } closedir(SUBDIR); } else { # db entry has trailing slash... if (!defined($db_maildirs{"$name/"})) { print "marking $maildir_path/$name for deletion.\n"; $directories{"$name"} = $name; } } } closedir(DIR); print "Ctrl-C in 5 seconds to abort before removal starts...\n"; sleep 5; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); # yyyymmddhhmm my $tstamp = sprintf("%04d%02d%02d%02d%02d", $year+1900, $mon+1, $mday, $hour, $min); # compare two arrays and erase maildirs not found in database chdir $maildir_path || die "Can't change to maildir '$maildir_path': $!\n";; my @args; foreach my $maildir (keys(%directories)) { my $archive = "$archdir/$directories{$maildir}-$tstamp.tgz"; # quick permissions check open(TOUCH, ">$archive") || die "Can't create archive file $archive: $!\n"; close(TOUCH); print "Archiving $maildir\n"; @args = ($archcmd, "cvzf", $archive, $maildir); system(@args) == 0 or die "Creating archive for $maildir failed: $?" rmtree($maildir); print localtime() . " $maildir has been deleted.\n"; } postfixadmin-2.3.7/ADDITIONS/postfixadmin-domain-postdeletion.sh0000664000175000017620000000357210715711016024620 0ustar davidpalepurple#!/bin/sh # Example script for removing a Maildir domain top-level folder # from a Courier-IMAP virtual mail hierarchy. # The script only looks at argument 1, assuming that it # indicates the relative name of a domain, such as # "somedomain.com". If $basedir/somedomain.com exists, it will # be removed. # The script will not actually delete the directory. I moves it # to a special directory which may once in a while be cleaned up # by the system administrator. # This script should be run as the user which owns the maildirs. If # the script is actually run by the apache user (e.g. through PHP), # then you could use "sudo" to grant apache the rights to run # this script as the relevant user. # Assume this script has been saved as # /usr/local/bin/postfixadmin-domain-postdeletion.sh and has been # made executable. Now, an example /etc/sudoers line: # apache ALL=(courier) NOPASSWD: /usr/local/bin/postfixadmin-domain-postdeletion.sh # The line states that the apache user may run the script as the # user "courier" without providing a password. # Change this to where you keep your virtual mail users' maildirs. basedir=/var/spool/maildirs # Change this to where you would like deleted maildirs to reside. trashbase=/var/spool/deleted-maildirs if [ `echo $1 | fgrep '..'` ]; then echo "First argument contained a double-dot sequence; bailing out." exit 1 fi if [ ! -e "$trashbase" ]; then echo "trashbase '$trashbase' does not exist; bailing out." exit 1 fi trashdir="${trashbase}/`date +%F_%T`_$1" domaindir="${basedir}/$1" if [ ! -e "$domaindir" ]; then echo "Directory '$domaindir' does not exits; nothing to do." exit 0; fi if [ ! -d "$domaindir" ]; then echo "'$domaindir' is not a directory; bailing out." exit 1 fi if [ -e "$trashdir" ]; then echo "Directory '$trashdir' already exits; bailing out." exit 1; fi mv $domaindir $trashdir exit $? postfixadmin-2.3.7/ADDITIONS/cyrus/0000775000175000017620000000000012301477471016750 5ustar davidpalepurplepostfixadmin-2.3.7/ADDITIONS/cyrus/README.txt0000664000175000017620000000033411374336541020447 0ustar davidpalepurple Configuration ------------- - Edit cyrus.conf and set $cyrus_* variables correctly. User must have permission over all accounts. - Edit cyrus-*.pl and change path to cyrus.conf (require '/path/to/cyrus.conf'; line) postfixadmin-2.3.7/ADDITIONS/cyrus/Changelog0000664000175000017620000000020111374336541020554 0ustar davidpalepurple Version 0.1 -- 26/10/2009 --------------------------- * Public Release. * Postcreation, Postdeletion and Postedit hooks. postfixadmin-2.3.7/ADDITIONS/cyrus/cyrus.conf0000664000175000017620000000071711374336541020772 0ustar davidpalepurple#!/usr/bin/perl # Config $cyrus_user = 'cyrus'; $cyrus_password = 'cyruspass'; $cyrus_host = 'localhost'; # unixhierarchysep => 1 (yes) / 0 (no) $unixhierarchysep = 1; # Common routines sub mailbox_name { my $mailbox = shift; if($unixhierarchysep) { $mailbox = 'user/'.$ARGV[0]; } else { $mailbox = 'user.'.$ARGV[0]; } return $mailbox; } sub die_on_error { my $cyradm = shift; if($cyradm->error) { die $cyradm->error; } } 1; postfixadmin-2.3.7/ADDITIONS/cyrus/README-ES.txt0000664000175000017620000000040111374336541020747 0ustar davidpalepurple Configuración ------------- - Edita el fichero cyrus.conf y modifica las variables $cyrus_*. El usuario debe tener permisos sobre todas las cuentas. - Edita los ficheros cyrus-*.pl y cambia la ruta de cyrus.conf (linea require '/path/to/cyrus.conf';) postfixadmin-2.3.7/ADDITIONS/cyrus/cyrus-mailbox-postdelete.pl0000775000175000017620000000140511374336541024255 0ustar davidpalepurple#!/usr/bin/perl # Cyrus Mailbox deletion # # Iñaki Rodriguez (irodriguez@virtualminds.es / irodriguez@ackstorm.es) # # LICENSE # This source file is subject to the GPL license that is bundled with # this package in the file LICENSE.TXT. # # (26/10/2009) use Cyrus::IMAP::Admin; require '/etc/mail/postfixadmin/cyrus.conf'; use strict; use vars qw($cyrus_user $cyrus_password $cyrus_host); my %opts; my $mailbox = mailbox_name($ARGV[0]); my $client = Cyrus::IMAP::Admin->new($cyrus_host); die_on_error($client); $opts{-user} = $cyrus_user; $opts{-password} = $cyrus_password; $client->authenticate(%opts); die_on_error($client); $client->setacl($mailbox,$cyrus_user => 'all'); die_on_error($client); $client->deletemailbox($mailbox); die_on_error($client); postfixadmin-2.3.7/ADDITIONS/cyrus/cyrus-mailbox-postedit.pl0000775000175000017620000000134111374336541023737 0ustar davidpalepurple#!/usr/bin/perl # Cyrus Mailbox edition # # Iñaki Rodriguez (irodriguez@virtualminds.es / irodriguez@ackstorm.es) # # LICENSE # This source file is subject to the GPL license that is bundled with # this package in the file LICENSE.TXT. # # (26/10/2009) use Cyrus::IMAP::Admin; require '/etc/mail/postfixadmin/cyrus.conf'; use strict; use vars qw($cyrus_user $cyrus_password $cyrus_host); my %opts; my $mailbox = mailbox_name($ARGV[0]); my $client = Cyrus::IMAP::Admin->new($cyrus_host); die_on_error($client); $opts{-user} = $cyrus_user; $opts{-password} = $cyrus_password; $client->authenticate(%opts); die_on_error($client); $client->setquota($mailbox,'STORAGE',scalar $ARGV[3]) if ($ARGV[3] > 0); die_on_error($client); postfixadmin-2.3.7/ADDITIONS/cyrus/cyrus-mailbox-postcreation.pl0000775000175000017620000000142711374336541024623 0ustar davidpalepurple#!/usr/bin/perl # Cyrus Mailbox creation # # Iñaki Rodriguez (irodriguez@virtualminds.es / irodriguez@ackstorm.es) # # LICENSE # This source file is subject to the GPL license that is bundled with # this package in the file LICENSE.TXT. # # (26/10/2009) use Cyrus::IMAP::Admin; require '/etc/mail/postfixadmin/cyrus.conf'; use strict; use vars qw($cyrus_user $cyrus_password $cyrus_host); my %opts; my $mailbox = mailbox_name($ARGV[0]); my $client = Cyrus::IMAP::Admin->new($cyrus_host); die_on_error($client); $opts{-user} = $cyrus_user; $opts{-password} = $cyrus_password; $client->authenticate(%opts); die_on_error($client); $client->create($mailbox); die_on_error($client); $client->setquota($mailbox,'STORAGE',scalar $ARGV[3]) if ($ARGV[3] > 0); die_on_error($client); postfixadmin-2.3.7/ADDITIONS/quota_usage.pl0000664000175000017620000001020511136633551020451 0ustar davidpalepurple#!/usr/bin/perl # vim:ts=4:sw=4:et # Virtual quota_usage 0.3 # Contributed to Postfixadmin by Jose Nilton # # See also : http://www.russelldare.net/media/perl/dirsizeSource.pdf # License: GPL v2. # Usage: # perl quota_usage.pl --list # perl quota_usage.pl --list --addmysql # for add mysql database postfix # # Requirements - the following perl modules are required: # DBD::Pg or DBD::mysql; perl perl-DBD-mysql perl-DBD (may be named differently depending on your platform). # and the 'du' binary in $ENV{'PATH'} (see below). # # You will need to modify the postfix DATABASE to add a quota_usage column. # Mysql: # ALTER TABLE mailbox ADD quota_usage INT(11) NOT NULL DEFAULT '0' AFTER modified, # ADD quota_usage_date DATE NOT NULL DEFAULT '0000-00-00' AFTER quota_usage; # PostgreSQL: # ALTER TABLE mailbox ADD COLUMN quota_usage INTEGER NOT NULL DEFAULT 0; # ALTER TABLE mailbox ADD COLUMN quota_usage_date DATE NOT NULL DEFAULT current_date; # use strict; use warnings; use File::Path; use DBI; use Getopt::Long; ##EDIT## my $db_host = 'localhost'; my $db_database = 'postfix'; my $db_user = 'postfix'; my $db_password = '123456'; my $root_path = '/home/vmail'; # Pg or mysql my $db_type = 'mysql'; ##END EDIT## (help()) if (!$ARGV[0]); $ENV{'PATH'} = "/sbin:/bin:/usr/sbin:/usr/bin"; my($domain_dir, $full_domain_dir, $user_dir, $usage, $email, $sql, $dbh); my $list = 0; my $insert_db = 0; my $total_mailbox = 0; my $total_domain = 0; GetOptions ('l|list' => \$list, 'i|addmysql' => \$insert_db, 'help|h|man' => \&help) or (help()); (list_quota_usage()) if ($list == 1 || $insert_db == 1 ); sub list_quota_usage { opendir(DOMAINDIR, $root_path) or die ("Unable to access directory '$root_path' ($!)"); if($insert_db == 1){ $dbh = DBI->connect("DBI:$db_type:database=$db_database;host=$db_host", $db_user, $db_password) or die ("cannot connect the database"); execSql("UPDATE mailbox set quota_usage = 0"); } foreach $domain_dir (sort readdir DOMAINDIR) { next if $domain_dir =~ /^\./; # skip dotted dirs $full_domain_dir = "$root_path/$domain_dir"; #print "$full_domain_dir\n"; $total_domain++; opendir(USERDIR, $full_domain_dir) or die ("Unable to access directory '$full_domain_dir' ($!)"); foreach $user_dir (sort readdir USERDIR) { next if $user_dir =~ /^\./; # skip dotted dirs $email = "$user_dir\@$domain_dir"; $total_mailbox++; my $i = `du -0 --summarize $full_domain_dir/$user_dir`; ($usage) = split(" ", $i); if ($usage < 100) { $usage = 0; } elsif ($usage < 1000) { $usage = 1; } else { $usage = $usage + 500; $usage = int $usage / 1000; } if($insert_db == 1){execSql("UPDATE mailbox set quota_usage = $usage, quota_usage_date = CAST(NOW() AS DATE) WHERE username = '$email'");} print_list() if ($list == 1); } } close(DOMAINDIR); close(USERDIR); (print_total()) if ($list == 1); } sub execSql { my $sql = shift; my $ex; $ex = $dbh->do($sql) or die ("error when running $sql"); } sub print_total{ print "---------------------------------------------------------\n"; print "TOTAL DOMAIN\t\t\t\tTOTAL MAILBOX\n"; print "---------------------------------------------------------\n"; print "$total_domain\t\t\t\t\t\t$total_mailbox\n"; } sub print_list { format STDOUT_TOP = Report of Quota Used --------------------------------------------------------- EMAIL QUOTA USED --------------------------------------------------------- . format = @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<< $email, "$usage MB" . write; } sub help { print "$0 [options...]\n"; print "-l|--list List quota used\n"; print "-i|--addmysql For insert quota used in database mysql\n"; } postfixadmin-2.3.7/ADDITIONS/cleanupdirs.pl0000664000175000017620000001071111177341326020450 0ustar davidpalepurple#!/usr/bin/perl -w ################################################################################ # # cleanupdirs 1.2 by jared bell # # display/remove maildir & domains directory tree's not listed in the postfix # mysql database. currently setup for use with postfixadmin, but can be # adapted. edit settings where it says 'change settings as needed.' by default # this program will display a list of directories which need deleted, nothing # is actually deleted. to change this behavior, look into the command line # arguments. # # command line arguments: # --delete # force automatic deletion of directories. instead of displaying a list # of deleted directories, they will be logged in the specified logfile. # --print # display deleted directories as well as log them. only valid when # '--delete' has been specified. # # settings: # $root_path = "/home/vmail"; # if maildir is '/home/vmail/domain.tld/user' then '/home/vmail' is the # $root_path. if your maildirs are '/home/vmail/user@domain.tld' then # this program will need to be modified in order to work right. # $logfile = "/var/log/removed_maildirs.log"; # the logfile to use when $delete_old_dirs is set to 1 # $db_* = "*"; # sets the host, port, database, user and pass to your mysql server # # version history: # 1.2 - removed uneeded settings. added '--print' command line argument # 1.1 - added '--delete' command line argument # 1.0 - initial release # ################################################################################ use strict; use DBI; use File::Path; use Getopt::Long; ### change settings as needed, see notes above ################################# our $root_path = "/home/vmail"; our $logfile = "/var/log/removed_maildirs.log"; our $db_hostname = "localhost"; our $db_port = "3306"; # this script currently supports MySQL only our $db_database = "postfix"; our $db_username = "someuser"; our $db_password = "somepass"; # instead of changing this script, you can put your settings to /etc/mail/postfixadmin/cleanupdirs.conf # just use perl syntax there to fill the variables listed above (without the "our" keyword). Example: # $db_username = 'mail'; if (-f "/etc/mail/postfixadmin/cleanupdirs.conf") { require "/etc/mail/postfixadmin/cleanupdirs.conf"; } ################################################################################ ### begin program ############################################################## my(@dirs_to_delete, $logfile_open); my $delete_old_dirs = 0; # do not delete by default, use cmdline to change this my $print_also = 0; # also print items when deleting, use cmdline to change this GetOptions ('delete' => \$delete_old_dirs, 'print' => \$print_also); my $conn_info = "DBI:mysql:database=$db_database;hostname=$db_hostname;port=$db_port"; my $dbh = DBI->connect($conn_info, $db_username, $db_password) or die $DBI::errstr; opendir DOMAINDIR, $root_path or die "Unable to access directory '$root_path' ($!)"; foreach my $domain_dir (sort readdir DOMAINDIR) { next if $domain_dir =~ /^\./; # skip dotted dirs next if (! -d "$root_path/$domain_dir"); # skip everything that is not a directory my $full_domain_dir = "$root_path/$domain_dir"; opendir USERDIR, $full_domain_dir or die "Unable to access directory '$full_domain_dir' ($!)"; foreach my $user_dir (sort readdir USERDIR) { next if $user_dir =~ /^\./; # skip dotted dirs push @dirs_to_delete, "$full_domain_dir/$user_dir" if &check_dir("SELECT maildir FROM mailbox WHERE maildir = ?", "$domain_dir/$user_dir/"); # end slash needed for checkdir } push @dirs_to_delete, $full_domain_dir if &check_dir("SELECT domain FROM domain WHERE domain = ?", $domain_dir); } closedir USERDIR; closedir DOMAINDIR; $dbh->disconnect; if (@dirs_to_delete) { foreach my $to_delete (@dirs_to_delete) { if ($delete_old_dirs == 1) { $logfile_open = open LOGFILE, ">> $logfile" or die "Unable to append logfile '$logfile' ($!)" unless $logfile_open; rmtree $to_delete; print LOGFILE localtime() . " Deleting directory '$to_delete'\n"; print localtime() . " Deleting directory '$to_delete'\n" if $print_also; } else { print localtime() . " Need to delete directory '$to_delete'\n"; } } } close LOGFILE if $logfile_open; sub check_dir { my($query, $dir) = @_; my $sth = $dbh->prepare($query); my $num_rows = $sth->execute($dir); $sth->finish; ($num_rows eq "0E0") ? 1 : 0; } postfixadmin-2.3.7/ADDITIONS/postfixadmin-mailbox-postdeletion.sh0000664000175000017620000000432510715711016025001 0ustar davidpalepurple#!/bin/sh # Example script for removing a Maildir from a Courier-IMAP virtual mail # hierarchy. # The script looks at arguments 1 and 2, assuming that they # indicate username and domain, respectively. # The script will not actually delete the maildir. I moves it # to a special directory which may once in a while be cleaned up # by the system administrator. # This script should be run as the user which owns the maildirs. If # the script is actually run by the apache user (e.g. through PHP), # then you could use "sudo" to grant apache the rights to run # this script as the relevant user. # Assume this script has been saved as # /usr/local/bin/postfixadmin-mailbox-postdeletion.sh and has been # made executable. Now, an example /etc/sudoers line: # apache ALL=(courier) NOPASSWD: /usr/local/bin/postfixadmin-mailbox-postdeletion.sh # The line states that the apache user may run the script as the # user "courier" without providing a password. # Change this to where you keep your virtual mail users' maildirs. basedir=/var/spool/maildirs # Change this to where you would like deleted maildirs to reside. trashbase=/var/spool/deleted-maildirs if [ ! -e "$trashbase" ]; then echo "trashbase '$trashbase' does not exist; bailing out." exit 1 fi if [ `echo $1 | fgrep '..'` ]; then echo "First argument contained a double-dot sequence; bailing out." exit 1 fi if [ `echo $2 | fgrep '..'` ]; then echo "First argument contained a double-dot sequence; bailing out." exit 1 fi subdir=`echo "$1" | sed 's/@.*//'` maildir="${basedir}/$2/${subdir}" trashdir="${trashbase}/$2/`date +%F_%T`_${subdir}" parent=`dirname "$trashdir"` if [ ! -d "$parent" ]; then if [ -e "$parent" ]; then echo "Strainge - directory '$parent' exists, but is not a directory." echo "Bailing out." exit 1 else mkdir -p "$parent" if [ $? -ne 0 ]; then echo "mkdir -p '$parent' returned non-zero; bailing out." exit 1 fi fi fi if [ ! -e "$maildir" ]; then echo "maildir '$maildir' does not exist; nothing to do." exit 1 fi if [ -e "$trashdir" ]; then echo "trashdir '$trashdir' already exists; bailing out." exit 1 fi mv $maildir $trashdir exit $? postfixadmin-2.3.7/ADDITIONS/fetchmail.pl0000664000175000017620000000705111167452431020075 0ustar davidpalepurple#!/usr/bin/perl use DBI; use MIME::Base64; # use Data::Dumper; use File::Temp qw/ mkstemp /; use Sys::Syslog; # require liblockfile-simple-perl use LockFile::Simple qw(lock trylock unlock); ###################################################################### ########## Change the following variables to fit your needs ########## # database settings # database backend - uncomment one of these our $db_type = 'Pg'; #my $db_type = 'mysql'; # host name our $db_host="127.0.0.1"; # database name our $db_name="postfix"; # database username our $db_username="mail"; # database password our $db_password="CHANGE_ME!"; # instead of changing this script, you can put your settings to /etc/mail/postfixadmin/fetchmail.conf # just use perl syntax there to fill the variables listed above (without the "our" keyword). Example: # $db_username = 'mail'; if (-f "/etc/mail/postfixadmin/fetchmail.conf") { require "/etc/mail/postfixadmin/fetchmail.conf"; } #################### Don't change anything below! #################### ###################################################################### openlog("fetchmail-all", "pid", "mail"); sub log_and_die { my($message) = @_; syslog("err", $message); die $message; } # read options and arguments $configfile = "/etc/fetchmail-all/config"; @ARGS1 = @ARGV; while ($_ = shift @ARGS1) { if (/^-/) { if (/^--config$/) { $configfile = shift @ARGS1 } } } $run_dir="/var/run/fetchmail"; # use specified config file if (-e $configfile) { do $configfile; } if($db_type eq "Pg" || $db_type eq "mysql") { $dsn = "DBI:$db_type:database=$db_name;host=$db_host"; } else { log_and_die "unsupported db_type $db_type"; } $lock_file=$run_dir . "/fetchmail-all.lock"; $lockmgr = LockFile::Simple->make(-autoclean => 1, -max => 1); $lockmgr->lock($lock_file) || log_and_die "can't lock ${lock_file}"; # database connect $dbh = DBI->connect($dsn, $db_username, $db_password) || log_and_die "cannot connect the database"; if($db_type eq "Pg") { $sql_cond = "date_part('epoch',now())-date_part('epoch',date)"; } elsif($db_type eq "mysql") { $sql_cond = "unix_timestamp(now())-unix_timestamp(date)"; } $sql = " SELECT id,mailbox,src_server,src_auth,src_user,src_password,src_folder,fetchall,keep,protocol,mda,extra_options,usessl FROM fetchmail WHERE $sql_cond > poll_time*60 "; my (%config); map{ my ($id,$mailbox,$src_server,$src_auth,$src_user,$src_password,$src_folder,$fetchall,$keep,$protocol,$mda,$extra_options,$usessl)=@$_; syslog("info","fetch ${src_user}@${src_server} for ${mailbox}"); $cmd="user '${src_user}' there with password '".decode_base64($src_password)."'"; $cmd.=" folder '${src_folder}'" if ($src_folder); $cmd.=" mda ".$mda if ($mda); # $cmd.=" mda \"/usr/local/libexec/dovecot/deliver -m ${mailbox}\""; $cmd.=" is '${mailbox}' here"; $cmd.=" keep" if ($keep); $cmd.=" fetchall" if ($fetchall); $cmd.=" ssl" if ($usessl); $cmd.=" ".$extra_options if ($extra_options); $text=<quote($ret).", date=now() WHERE id=".$id; $dbh->do($sql); }@{$dbh->selectall_arrayref($sql)}; $lockmgr->unlock($lock_file); closelog(); postfixadmin-2.3.7/ADDITIONS/pfa_maildir_cleanup.pl0000664000175000017620000000621210715711016022110 0ustar davidpalepurple#!/usr/bin/perl # ## ## pfa_maildir_cleanup.pl ## ## (c) 2004 by Stephen Fulton (sfulton@esoteric.ca) ## ## based on a script by Petr Znojemsky (thanks!) ## ## Simple script to remove maildirs/domains not listed in a MySQL database. ## Set up for use with those using PostfixAdmin, but can be adapted. ## ## Edit the variables between the ##EDIT## to match your setup. ## ## USE AT YOUR OWN RISK. I ASSUME NO RESPONSIBILITY. ## use DBI; use File::Path; ##EDIT## $root_path = "/home/mail"; $logfile = "/var/log/removed_maildirs.log"; $db_host = "localhost"; $db_database = "database"; $db_user = "username"; $db_password = 'password'; ##END EDIT## $connectionInfo = "DBI:mysql:database=$db_database;$db_host:3306"; ## Read a list of domain directories in the root path /remote/mail1 opendir(DIRHANDLE, $root_path) || die "Cannot access directory $maildir_path: $!"; my @directories = (); foreach $directory (sort readdir(DIRHANDLE)) { push (@directories, $directory); } closedir(DIRHANDLE); ## Strip the "." and ".." from the directories array ($dot, $doubledot, @directories) = @directories; ## For each of the domain directories.. foreach $domain_dir (@directories) { $complete_domain_path = "$root_path/$domain_dir"; ## Get a list of user directories within each domain directory... opendir(DOMAINHANDLE, $complete_domain_path) || die "Cannot access directory $complete_domain_path: $!"; my @user_directories = (); foreach $dir (sort readdir(DOMAINHANDLE)) { push(@user_directories, $dir); } close(DOMAINHANDLE); ## Now remove any "." or ".." directory entries and construct a domain/maildir variable ## valid for one iteration of loop. foreach $user_directory (@user_directories) { if( not($user_directory eq '..') && not($user_directory eq '.') ) { $short_user_dir = "$domain_dir/$user_directory/"; ## Here is where the $short_user_dir is compared against the DB entry. $dbh = DBI->connect($connectionInfo,$db_user,$db_password); $user_query = "SELECT maildir FROM mailbox WHERE maildir = '$short_user_dir'"; $sth = $dbh->prepare($user_query); $rows = $sth->execute(); ## If there are no rows that match, then directory is orphaned and can ## be deleted. if($rows == 0) { $maildir_path = "$root_path/$short_user_dir"; open(INFO, ">>$logfile") || die "Cannot write to the logfile: $logfile."; rmtree($maildir_path); print INFO localtime()." Maildir ".$maildir_path." has been deleted.\n"; (INFO); } $sth->finish; $dbh->disconnect; } } $dbh2 = DBI->connect($connectionInfo,$db_user,$db_password); $domain_query = "SELECT domain FROM domain WHERE domain = '$domain_dir'"; $sth2 = $dbh2->prepare($domain_query); $domain_rows = $sth2->execute(); if($domain_rows == 0) { open(INFO, ">>$logfile") || die "Cannot write to the logfile: $logfile."; rmtree($complete_domain_path); print INFO localtime()." Domain directory ".$complete_domain_path." has been deleted.\n"; close(INFO); } $sth2->finish; $dbh2->disconnect; } postfixadmin-2.3.7/ADDITIONS/postfixadmin-mailbox-postcreation.sh0000664000175000017620000000341211076676002025004 0ustar davidpalepurple#!/bin/sh # Example script for adding a Maildir to a Courier-IMAP virtual mail # hierarchy. # The script only looks at argument 3, assuming that it # indicates the relative name of a maildir, such as # "somedomain.com/peter/". # This script should be run as the user which owns the maildirs. If # the script is actually run by the apache user (e.g. through PHP), # then you could use "sudo" to grant apache the rights to run # this script as the relevant user. # Assume this script has been saved as # /usr/local/bin/postfixadmin-mailbox-postcreation.sh and has been # made executable. Now, an example /etc/sudoers line: # apache ALL=(courier) NOPASSWD: /usr/local/bin/postfixadmin-mailbox-postcreation.sh # The line states that the apache user may run the script as the # user "courier" without providing a password. # Change this to where you keep your virtual mail users' maildirs. basedir=/var/spool/maildirs if [ ! -e "$basedir" ]; then echo "$0: basedir '$basedir' does not exist; bailing out." exit 1 fi if [ `echo $3 | fgrep '..'` ]; then echo "$0: An argument contained a double-dot sequence; bailing out." exit 1 fi maildir="${basedir}/$3" parent=`dirname "$maildir"` if [ ! -d "$parent" ]; then if [ -e "$parent" ]; then echo "$0: strange - directory '$parent' exists, but is not a directory; bailing out." exit 1 else mkdir -p "${parent}" if [ $? -ne 0 ]; then echo "$0: mkdir -p '$parent' returned non-zero; bailing out." exit 1 fi fi fi if [ -e "$maildir" ]; then echo "$0: Directory '$maildir' already exists! bailing out" exit 1 fi maildirmake "$maildir" if [ ! -d "$maildir" ]; then echo "$0: maildirmake didn't produce a directory; bailing out." exit 1 fi exit 0 postfixadmin-2.3.7/ADDITIONS/mkeveryone.pl0000664000175000017620000001002010715711016020306 0ustar davidpalepurple#!/usr/bin/perl # # Generate an 'everybody' alias for a domain. # # Create the file /etc/mkeveryone.conf # chmod 640 /etc/mkeveryone.conf # Example of mkeveryone.conf # # userid=postfix # passwd=postfix # db=postfix # host=localhost # port=3306 # domain=domain.tld # target=everybody@domain.tld # ignore=vacation@domain.tld # ignore=spam@domain.tld # ignore=newsletter@domain.tld # ignore=root@domain.tld # # Save this file in, for example, /usr/local/sbin/mkeveryone.pl # chmod 750 /usr/local/sbin/mkeveryone.pl # # Run the script! # use DBI; use Time::Local; use POSIX qw(EAGAIN); use Fcntl; use IO; use IO::File; my $timeNow=time(); my $DATFILE = "/etc/mkeveryone.conf"; my $FILEHANDLE = ""; # database information my $db="postfix"; my $host="localhost"; my $port="3306"; my $userid="postfix"; my $passwd="postfix"; my $domain="domain.tld"; my $target="everyone@$domain"; my @ignore; my @dest; open (FILEHANDLE, $DATFILE); while ( $LINE = ) { if ( length $LINE > 0 ) { chomp $LINE; $RETURNCODE = 0; SWITCH: { $LINE =~ /^ignore/i and do { $LINE =~ s/^ignore// && $LINE =~ s/=// && $LINE =~ s/^ //g; @ignore = (@ignore,$LINE); }; $LINE =~ /^userid/i and do { # Userid found."; $LINE =~ s/^userid// && $LINE =~ s/=// && $LINE =~ s/^ //g; $userid = $LINE; }; $LINE =~ /^passwd/i and do { # Passwd found."; $LINE =~ s/^passwd// && $LINE =~ s/=// && $LINE =~ s/^ //g; $passwd = $LINE; }; $LINE =~ /^db/i and do { # Database found."; $LINE =~ s/^db// && $LINE =~ s/=// && $LINE =~ s/^ //g; $db = $LINE; }; $LINE =~ /^host/i and do { # Database host found."; $LINE =~ s/^host// && $LINE =~ s/=// && $LINE =~ s/^ //g; $host = $LINE; }; $LINE =~ /^port/i and do { # Database host found."; $LINE =~ s/^port// && $LINE =~ s/=// && $LINE =~ s/^ //g; $port = $LINE; }; $LINE =~ /^target/i and do { # Database host found."; $LINE =~ s/^target// && $LINE =~ s/=// && $LINE =~ s/^ //g; $target = $LINE; }; $LINE =~ /^domain/i and do { # Database host found."; $LINE =~ s/^domain// && $LINE =~ s/=// && $LINE =~ s/^ //g; $domain = $LINE; }; } } } print "Connecting to database $db on $host:$port...\n\r"; print "Target email address is $target...\n\r"; my $connectionInfo="DBI:mysql:database=$db;$host:$port"; # make connection to database $dbh = DBI->connect($connectionInfo,$userid,$passwd); # Delete the old message...prepare and execute query $query = "SELECT username FROM mailbox WHERE domain='$domain';"; $sth = $dbh->prepare($query); $sth->execute(); # assign fields to variables $sth->bind_columns(\$username); my $ign="false"; while($sth->fetch()) { $ign = "false"; foreach $ignored ( @ignore ) { if ( $username eq $ignored ){ $ign = "true"; } } if ( $ign eq "false" ) { @dest = (@dest,$username); } } # Delete the old aliases...prepare and execute query $query = "DELETE FROM alias WHERE address='$target';"; $sth = $dbh->prepare($query); $sth->execute(); print "Record deleted from the database.\r\n"; $sth->finish(); $goto = join(",",@dest); print "$goto\n\r\n\r"; # Insert the new message...prepare and execute query $query = "INSERT INTO alias (address,goto,domain,created,modified) VALUES ('$target','$goto','$domain',now(),now());"; $sth = $dbh->prepare($query); $sth->execute(); print "Record added to the database.\r\n"; $sth->finish(); # disconnect from databse $dbh->disconnect; postfixadmin-2.3.7/ADDITIONS/change_password.tgz0000664000175000017620000001740310601151304021466 0ustar davidpalepurpleA=zHwx6,Nq`p/8Y>5XkOUwn2A3R)Y*c WP)Wɯ'^,ZRbiRT3ejm:M86[ׁG_.wײoybPTVJ\Ī;Ũ}Cjt٫ ˱IΠN=qym>K<]KZ&Ӿ_쟇;+lykNucJ3oZfmñuʶFcW_*)|<>m狹b~kސb+R^-RPiLiκ?5 ҴlR,~P 5ƎnLBW@W|h݃ M+Qǵ$dy-$> Q TrPQ's't+46> ;IZoTwת+nb9.M_+?:UCmj@ΤH쭻woԀ v/+~dJ j329dbڄL7Ĺe@1B `_Osu63o I,jCUGeV,H qLo̴ИHzם7&ښp&  DIR&KnU m0\6/ahYdPyݘ9f$Ff"9Cm˛#$i~mw=/hHv:f-'cb1u㚴,{llSjqjYx|_)u:n4.}_kKu_zHS{:V`\\{4SR)nzi k}L UO{0㭙Їp}_-@ccR?wKD" 3gneZ>rHz!/^ar ("rfc :ǎ'j6v鞓7g'9ڴĝ͈C9# Ᵹt$}S Lۿ'zMQ{:xF=X@(iGb3ӔllSjHC UD%1ayN4q˜ 99_KAWX:2Y>VṈz.9#M瞀lʘ~Cɕ{yoATZ׊Os .sFvٯTL&m F5H{vM+zC9qnUva^qplUW̽O+q#jYw|:3/Ir>F=zM,?P)4onj.Sސ7J)%^?s a,]HdVV!X#s[~R2>RQ!Yr|QDŽ. Yu;#1Ņ A=F@gD.LuV^}3c1n<{ sldi]#x] Z=W"E Si =xC3 [A;9@5`1l~?$,^+a=xYs0x+pEڙmE9W@Z=~Ӌ1v_zgBa,έ4Ͼα EwGx҈oO(|PE xX ""79H;]E]R,>RrޓI!s P/8ijM z -ϔ%A09w$ϔ5b b?lŨݣqzF^w'ǃS$k|aX8צ`~w9k } _ĔνE I|M ~^]Zb/eIJIdSt$}4DMT7.$" NG DcLb y&/y9G9'V1g-cgctQ780ggJke+nƆT(J.'}y(O<_?U79kXiiOG5#Yd*66{ djSjG<2\2 dO1N\3F5L.ͻT@ Kcecg`%cF~ѧ9i!u Y&rs_I,o0Aby cKN Cd1ΰ׬UA._(ʕjm/7o;iw`xۻz9d Jz= tԽ'Tf+$?А]ydWz呈E#[<@ " J Ǡ! ږ^ZtrlDFݔ 8]"5t[Ǿ'xUh2ei{HL/ xȜ 81]KBO '֐xfqȃT6 ~>^\EV{בo(((F՘}ۀ1plI'Ձl2(pq(FR'|ZKrcNH{zNtPL+]oN<0AƫA 9 IZs8t\Gj&!Cǜl! P:GR tQ §^u(, 8 p"(jH\ȾW&~\*I 94l QJ G>;OiBN|D1Explp.tb_y0bb7x!wr =)GN~B x]y8t7k'g.}תo/j])grԁ/ sE`1r~53ݙ:^8 XX_onxL˂,dh*l /Ru&DwRǰuGcpXu ŪL59/" ]?JxLaFY^rǑf_ J׼ ʋ8Bu`f%94 ci7,D3KR*+vՙOUֻ~&47͉3(;"-e%ţ XB n^?UaT"CH"yW$]$^AY'&U㦂ǎ_/3jP Os#NShDS3g_ڒSlaLy'K%#ӕg7V( ׌'( xH6,i(fX&1y׎7LX# ^oLHIYd2 J&˓Y iZ(yO<'pR&&vp+ BqU`>3;;qHfGḑH柭.3lKz?nߚ#r;ʩ7gŜO=*zr,y:辉J{)Xs p s8SY)mC@O0 `4N'K qtj?~6OO9C ?}*fNPqOd2HI{f2< 8O!$Ç ʀJuřAMhF%m aXhp@*53 M3- KU%te ؕN \Q VuL*#7ܪ;/0]È3-HyuvuiE}SE[bw10}Rz5fqA@=qoa[{NS-Ia5>֟5,vr8_JĦs ʫX9$A+{{bp1Dcr+(v,9(ߴ@dR i$4K'M2K?}B0#RP2iYHJגb*~i4$>/5JeRT$%F0{ȈdRdA;TCQMRLVS$. DXsցiնV)5 AغP2F+[M1drc@ O(_/(:,"lv_8s%7jwv@_`VgHܹ0U]qeƂU]7lſP>@GBg]쇏zEqo͒r8}wAD9Yt܁s?oɷ:wp[!Js.lV"x6zeSlmm]ٳkS[w`V+y)XjȣYxYTdJ녁 Jd!>J`9+ ٽ2ޱ%#!A]*s bj-!L\r(xKS`+N\‹ϥlg 2JdL_tSj;2LNWN8I{L<0bO0#޽P/@`?~wф4,a؇G}x>+wG}=t-..MH[N,>94% @vR-[ J%d A٧0x4wS48,{s.@<Z$j:Y 0Jh dbmwK~44+dKa_E_,„H@M; ^:U@UuL _ꆪA1݉s+?&[6&q0VW7Qixg8S{6+RڌL2D]\n`W#ޡK ۰;8Zͷ<('~VH - 2007/10/05. # use strict; open(FH, ') { my ($username, $password) = split(':', $_); next if $password eq '!'; next if $password eq '*'; my $maildir = "$username\@$mydomain/"; print "insert into mailbox (username, password, domain, active, maildir) values ('$username', '$password', '$mydomain', $true, '$maildir');\n"; } postfixadmin-2.3.7/list-virtual.php0000664000175000017620000002560011643702036017434 0ustar davidpalepurple 0)) { if (empty ($fDomain)) { $fDomain = $list_domains[0]; } } if(!in_array($fDomain, $list_domains)) { flash_error( $PALANG['invalid_parameter'] ); header("Location: list-domain.php"); # invalid domain, or not owned by this admin exit; } if (!check_owner(authentication_get_username(), $fDomain)) { flash_error( $PALANG['invalid_parameter'] . " If you see this message, please open a bugreport"); # this check is most probably obsoleted by the in_array() check above header("Location: list-domain.php"); # domain not owned by this admin exit(0); } // store fDomain in $_SESSION so after adding/editing aliases/mailboxes we can // take the user back to the appropriate domain listing. (see templates/menu.php) if($fDomain) { $_SESSION['list_virtual_sticky_domain'] = $fDomain; } # # alias domain # # TODO: add search support for alias domains if (boolconf('alias_domain')) { # Alias-Domains # first try to get a list of other domains pointing # to this currently chosen one (aka. alias domains) $query = "SELECT $table_alias_domain.alias_domain,$table_alias_domain.target_domain,$table_alias_domain.modified,$table_alias_domain.active FROM $table_alias_domain WHERE target_domain='$fDomain' ORDER BY $table_alias_domain.alias_domain LIMIT $fDisplay, $page_size"; if ('pgsql'==$CONF['database_type']) { $query = "SELECT alias_domain,target_domain,extract(epoch from modified) as modified,active FROM $table_alias_domain WHERE target_domain='$fDomain' ORDER BY alias_domain LIMIT $page_size OFFSET $fDisplay"; } $result = db_query ($query); $tAliasDomains = array(); if ($result['rows'] > 0) { while ($row = db_array ($result['result'])) { if ('pgsql'==$CONF['database_type']) { $row['modified']=gmstrftime('%c %Z',$row['modified']); $row['active']=('t'==$row['active']) ? 1 : 0; } $tAliasDomains[] = $row; } } # now let's see if the current domain itself is an alias for another domain $query = "SELECT $table_alias_domain.alias_domain,$table_alias_domain.target_domain,$table_alias_domain.modified,$table_alias_domain.active FROM $table_alias_domain WHERE alias_domain='$fDomain'"; if ('pgsql'==$CONF['database_type']) { $query = "SELECT alias_domain,target_domain,extract(epoch from modified) as modified,active FROM $table_alias_domain WHERE alias_domain='$fDomain'"; } $result = db_query ($query); $tTargetDomain = ""; if ($result['rows'] > 0) { if($row = db_array ($result['result'])) { if ('pgsql'==$CONF['database_type']) { $row['modified']=gmstrftime('%c %Z',$row['modified']); $row['active']=('t'==$row['active']) ? 1 : 0; } $tTargetDomain = $row; } } } # # aliases # if ($search == "") { $sql_domain = " $table_alias.domain='$fDomain' "; $sql_where = ""; } else { $sql_domain = db_in_clause("$table_alias.domain", $list_domains); $sql_where = " AND ( address LIKE '%$search%' OR goto LIKE '%$search%' ) "; } $query = "SELECT $table_alias.address, $table_alias.goto, $table_alias.modified, $table_alias.active FROM $table_alias LEFT JOIN $table_mailbox ON $table_alias.address=$table_mailbox.username WHERE ($sql_domain AND $table_mailbox.maildir IS NULL $sql_where) ORDER BY $table_alias.address LIMIT $fDisplay, $page_size"; if ('pgsql'==$CONF['database_type']) { # TODO: is the different query for pgsql really needed? The mailbox query below also works with both... $query = "SELECT address, goto, modified, active FROM $table_alias WHERE $sql_domain AND NOT EXISTS(SELECT 1 FROM $table_mailbox WHERE username=$table_alias.address $sql_where) ORDER BY address LIMIT $page_size OFFSET $fDisplay"; } $result = db_query ($query); if ($result['rows'] > 0) { while ($row = db_array ($result['result'])) { if ('pgsql'==$CONF['database_type']) { //. at least in my database, $row['modified'] already looks like : 2009-04-11 21:38:10.75586+01, // while gmstrftime expects an integer value. strtotime seems happy though. //$row['modified']=gmstrftime('%c %Z',$row['modified']); $row['modified'] = date('Y-m-d H:i', strtotime($row['modified'])); $row['active']=('t'==$row['active']) ? 1 : 0; } $tAlias[] = $row; } } # # mailboxes # $display_mailbox_aliases = boolconf('alias_control_admin'); # build the sql query $sql_select = " SELECT $table_mailbox.* "; $sql_from = " FROM $table_mailbox "; $sql_join = ""; $sql_where = " WHERE "; $sql_order = " ORDER BY $table_mailbox.username "; $sql_limit = " LIMIT $page_size OFFSET $fDisplay"; if ($search == "") { $sql_where .= " $table_mailbox.domain='$fDomain' "; } else { $sql_where .= db_in_clause("$table_mailbox.domain", $list_domains) . " "; $sql_where .= " AND ( $table_mailbox.username LIKE '%$search%' OR $table_mailbox.name LIKE '%$search%' "; if ($display_mailbox_aliases) { $sql_where .= " OR $table_alias.goto LIKE '%$search%' "; } $sql_where .= " ) "; # $search is already escaped } if ($display_mailbox_aliases) { $sql_select .= ", $table_alias.goto "; $sql_join .= " LEFT JOIN $table_alias ON $table_mailbox.username=$table_alias.address "; } if (boolconf('vacation_control_admin')) { $sql_select .= ", $table_vacation.active AS v_active "; $sql_join .= " LEFT JOIN $table_vacation ON $table_mailbox.username=$table_vacation.email "; } if (boolconf('used_quotas') && boolconf('new_quota_table')) { $sql_select .= ", $table_quota2.bytes as current "; $sql_join .= " LEFT JOIN $table_quota2 ON $table_mailbox.username=$table_quota2.username "; } if (boolconf('used_quotas') && ( ! boolconf('new_quota_table') ) ) { $sql_select .= ", $table_quota.current "; $sql_join .= " LEFT JOIN $table_quota ON $table_mailbox.username=$table_quota.username "; $sql_where .= " AND ( $table_quota.path='quota/storage' OR $table_quota.path IS NULL ) "; } $query = "$sql_select\n$sql_from\n$sql_join\n$sql_where\n$sql_order\n$sql_limit"; $result = db_query ($query); if ($result['rows'] > 0) { $delimiter = preg_quote($CONF['recipient_delimiter'], "/"); $goto_single_rec_del = ""; while ($row = db_array ($result['result'])) { if ($display_mailbox_aliases) { $goto_split = explode(",", $row['goto']); $row['goto_mailbox'] = 0; $row['goto_other'] = array(); foreach ($goto_split as $goto_single) { if (!empty($CONF['recipient_delimiter'])) { $goto_single_rec_del = preg_replace('/' .$delimiter. '[^' .$delimiter. '@]*@/', "@", $goto_single); } if ($goto_single == $row['username'] || $goto_single_rec_del == $row['username']) { # delivers to mailbox $row['goto_mailbox'] = 1; } elseif (boolconf('vacation') && strstr($goto_single, '@' . $CONF['vacation_domain']) ) { # vacation alias - TODO: check for full vacation alias # skip the vacation alias, vacation status is detected otherwise } else { # forwarding to other alias $row['goto_other'][] = $goto_single; } } } if ('pgsql'==$CONF['database_type']) { // XXX $row['modified'] = date('Y-m-d H:i', strtotime($row['modified'])); $row['created'] = date('Y-m-d H:i', strtotime($row['created'])); $row['active']=('t'==$row['active']) ? 1 : 0; if($row['v_active'] == NULL) { $row['v_active'] = 'f'; } $row['v_active']=('t'==$row['v_active']) ? 1 : 0; } $tMailbox[] = $row; } } $tCanAddAlias = false; $tCanAddMailbox = false; # TODO: needs reworking for $search... $limit = get_domain_properties($fDomain); if (isset ($limit)) { if ($fDisplay >= $page_size) { $tDisplay_back_show = 1; $tDisplay_back = $fDisplay - $page_size; } if (($limit['alias_count'] > $page_size) or ($limit['mailbox_count'] > $page_size)) { $tDisplay_up_show = 1; } if ((($fDisplay + $page_size) < $limit['alias_count']) or (($fDisplay + $page_size) < $limit['mailbox_count'])) { $tDisplay_next_show = 1; $tDisplay_next = $fDisplay + $page_size; } if($limit['aliases'] == 0) { $tCanAddAlias = true; } elseif($limit['alias_count'] < $limit['aliases']) { $tCanAddAlias = true; } if($limit['mailboxes'] == 0) { $tCanAddMailbox = true; } elseif($limit['mailbox_count'] < $limit['mailboxes']) { $tCanAddMailbox = true; } } // this is why we need a proper template layer. $fDomain = htmlentities($fDomain, ENT_QUOTES); include ("templates/header.php"); include ("templates/menu.php"); include ("templates/list-virtual.php"); include ("templates/footer.php"); /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ ?> postfixadmin-2.3.7/edit-active-admin.php0000664000175000017620000000266410724535105020266 0ustar davidpalepurple postfixadmin-2.3.7/fetchmail.php0000664000175000017620000002326112044065417016733 0ustar davidpalepurple array(0, 0, 'id' ), "mailbox" => array(1, 1, 'enum' ), "src_server" => array(1, 1, 'text' ), "src_auth" => array(1, 1, 'enum' ), "src_user" => array(1, 1, 'text' ), "src_password" => array(1, 0, 'password' ), "src_folder" => array(1, 1, 'text' ), "poll_time" => array(1, 1, 'num' ), "fetchall" => array(1, 1, 'bool' ), "keep" => array(1, 1, 'bool' ), "protocol" => array(1, 1, 'enum' ), "usessl" => array(1, 1, 'bool' ), "extra_options" => array($extra_options, $extra_options, 'longtext' ), "mda" => array($extra_options, $extra_options, 'longtext' ), "date" => array(0, $display_status, 'text' ), "returned_text" => array(0, $display_status, 'longtext' ), ); # labels and descriptions are taken from $PALANG['pFetchmail_field_xxx'] and $PALANG['pFetchmail_desc_xxx'] # TODO: After pressing save or cancel in edit form, date and returned text are not displayed in list view. # TODO: Reason: $display_status is set before $new and $edit are reset to 0. # TODO: Fix: split the "display field?" column into "display in list" and "display in edit mode". $SESSID_USERNAME = authentication_get_username(); if (!$SESSID_USERNAME ) exit; $fm_defaults=array( "id" =>0, "mailbox" => array($SESSID_USERNAME), "poll_time" => 10, "src_auth" => array('password','kerberos_v5','kerberos','kerberos_v4','gssapi','cram-md5','otp','ntlm','msn','ssh','any'), "protocol" => array('POP3','IMAP','POP2','ETRN','AUTO'), ); $table_fetchmail = table_by_key('fetchmail'); $table_mailbox = table_by_key('mailbox'); if (authentication_has_role('global-admin')) { $list_domains = list_domains (); } else { $list_domains = list_domains_for_admin(authentication_get_username()); } $user_domains=implode(", ",array_values($list_domains)); # for displaying $user_domains_sql=implode("','",escape_string(array_values($list_domains))); # for SQL $sql="SELECT username FROM $table_mailbox WHERE domain in ('".$user_domains_sql."')"; # TODO: replace with domain selection dropdown $res = db_query ($sql); if ($res['rows'] > 0){ $fm_defaults["mailbox"]=array(); while ($name = db_array ($res['result'])){ $fm_defaults["mailbox"][] = $name["username"]; } } else{ $fm_defaults["mailbox"]=array(); $fm_defaults["mailbox"][]=$SESSID_USERNAME; # TODO: Does this really make sense? Or should we display a message "please create a mailbox first!"? } $row_id = 0; if ($delete) { $row_id = $delete; } elseif ($edit) { $row_id = $edit; } $user_mailboxes_sql= "'" . implode("','",escape_string(array_values($fm_defaults["mailbox"]))) . "'"; # mailboxes as SQL if ($row_id) { $result = db_query ("SELECT ".implode(",",escape_string(array_keys($fm_struct)))." FROM $table_fetchmail WHERE id=$row_id AND mailbox IN ($user_mailboxes_sql)"); # TODO: the "AND mailbox IN ..." part should obsolete the check_owner call. Remove it after checking again. if ($result['rows'] > 0) { $edit_row = db_array ($result['result']); $account = $edit_row['src_user'] . " @ " . $edit_row['src_server']; } $edit_row_domain = explode('@', $edit_row['mailbox']); if ($result['rows'] <= 0 || !check_owner($SESSID_USERNAME, $edit_row_domain[1])) { # owner check for $edit and $delete flash_error(sprintf($PALANG['pFetchmail_error_invalid_id'], $row_id)); $edit = 0; $delete = 0; } } if ($cancel) { # cancel $new or $edit $edit=0; $new=0; } elseif ($delete) { # delete an entry $result = db_query ("delete from $table_fetchmail WHERE id=".$delete); if ($result['rows'] != 1) { flash_error($PALANG['pDelete_delete_error']) . ''; } else { flash_info(sprintf($PALANG['pDelete_delete_success'],$account)); } $delete=0; } elseif ( ($edit || $new) && $save) { # $edit or $new AND save button pressed $formvars=array(); foreach($fm_struct as $key=>$row){ list($editible,$view,$type)=$row; if ($editible != 0){ $func="_inp_".$type; $val=safepost($key); if ($type!="password" || strlen($val) > 0) { # skip on empty (aka unchanged) password $formvars[$key]= escape_string( function_exists($func) ?$func($val) :$val); } } } $formvars['id'] = $edit; # results in 0 on $new if($CONF['database_type'] == 'pgsql' && $new) { // skip - shouldn't need to specify this as it will default to the next available value anyway. unset($formvars['id']); } if (!in_array($formvars['mailbox'], $fm_defaults['mailbox'])) { flash_error($PALANG['pFetchmail_invalid_mailbox']); $save = 0; } if ($formvars['src_server'] == '') { flash_error($PALANG['pFetchmail_server_missing']); # TODO: validate domain name $save = 0; } if (empty($formvars['src_user']) ) { flash_error($PALANG['pFetchmail_user_missing']); $save = 0; } if ($new && empty($formvars['src_password']) ) { flash_error($PALANG['pFetchmail_password_missing']); $save = 0; } if ($save) { if ($new) { $sql="INSERT INTO $table_fetchmail (".implode(",",escape_string(array_keys($formvars))).") VALUES ('".implode("','",escape_string($formvars))."')"; } else { # $edit foreach(array_keys($formvars) as $key) { $formvars[$key] = escape_string($key) . "='" . escape_string($formvars[$key]) . "'"; } $sql="UPDATE $table_fetchmail SET ".implode(",",$formvars).",returned_text='', date=NOW() WHERE id=".$edit; } $result = db_query ($sql); if ($result['rows'] != 1) { flash_error($PALANG['pFetchmail_database_save_error']); } else { flash_info($PALANG['pFetchmail_database_save_success']); $edit = 0; $new = 0; # display list after saving } } else { $formvars['src_password'] = ''; # never display password } } elseif ($edit) { # edit entry form $formvars = $edit_row; $formvars['src_password'] = ''; if ('pgsql'==$CONF['database_type']) { $formvars['fetchall']=('t'==$formvars['fetchall']) ? 1 : 0; $formvars['keep']=('t'==$formvars['keep']) ? 1 : 0; $formvars['usessl']=('t'==$formvars['usessl']) ? 1 : 0; } } elseif ($new) { # create entry form foreach (array_keys($fm_struct) as $value) { if (isset($fm_defaults[$value])) { $formvars[$value] = $fm_defaults[$value]; } else { $formvars[$value] = ''; } } } $tFmail = array(); if ($edit + $new == 0) { # display list # TODO: ORDER BY would even be better if it would order by the _domain_ of the target mailbox first $res = db_query ("SELECT ".implode(",",escape_string(array_keys($fm_struct)))." FROM $table_fetchmail WHERE mailbox IN ($user_mailboxes_sql) ORDER BY mailbox,src_server,src_user"); if ($res['rows'] > 0) { while ($row = db_array ($res['result'])) { if ('pgsql'==$CONF['database_type']) { //. at least in my database, $row['modified'] already looks like : 2009-04-11 21:38:10.75586+01, // while gmstrftime expects an integer value. strtotime seems happy though. //$row['date']=gmstrftime('%c %Z',$row['date']); $row['date'] = date('Y-m-d H:i:s', strtotime($row['date'])); $row['fetchall']=('t'==$row['fetchall']) ? 1 : 0; $row['keep']=('t'==$row['keep']) ? 1 : 0; $row['usessl']=('t'==$row['usessl']) ? 1 : 0; } $tFmail[] = $row; } } } function _inp_num($val){ return (int)($val); } function _inp_bool($val){ return $val ? db_get_boolean(true): db_get_boolean(false); } function _inp_password($val){ return base64_encode($val); } include ("./templates/header.php"); include ("./templates/menu.php"); include ("./templates/fetchmail.php"); include ("./templates/footer.php"); /* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/index.php0000664000175000017620000000701711173600051016076 0ustar davidpalepurple Welcome to Postfix Admin

    Welcome to Postfix Admin

    What is it?

    Postfix Admin is a web based interface to configure and manage a Postfix based email server for many users.

    Postfix Admin can also be used to

    • Forward email to other addresses
    • Configure vacation/out-of-office auto responses
    • Add/edit/remove mail accounts
    • Add/edit/remove domains
    • Broadcast emails to all users of the system
    • Set quota on mailboxes
    • And more...

    Licensing

    Postfix admin is released under the following license :

    This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License 2 as published by the Free Software Foundation.

    See the following FSF GPL2 page for further information on the license.

    What now?

    1. Read the INSTALL.txt file
    2. Configure Postfix to use your chosen database - see (for example) the following pages :
    3. Use it

    When you have configured Postfixadmin, this page will be replaced with a login page.

    You can now run setup to make sure that all the PHP functions are available for Postfix Admin to run.

    If you still encounter any problems, please check the documentation and website for more information.

    Postfix Admin Web sites

    For further help, or documentation please check out - Postfix Admin web site
    Knowledge Base

    postfixadmin-2.3.7/edit-mailbox.php0000664000175000017620000001300712157365110017350 0ustar davidpalepurple"; } $result = db_query("SELECT * FROM $table_mailbox WHERE username = '$fUsername' AND domain = '$fDomain'"); if($result['rows'] != 1) { die("Invalid username chosen; user does not exist in mailbox table"); } $user_details = db_array($result['result']); if ($_SERVER['REQUEST_METHOD'] == "GET") { if (check_owner($SESSID_USERNAME, $fDomain) || authentication_has_role('global-admin')) { $tName = $user_details['name']; $tQuota = divide_quota($user_details['quota']); $tActive = $user_details['active']; if ('pgsql'==$CONF['database_type']) { $tActive = ('t'==$user_details['active']) ? 1 : 0; } $result = db_query ("SELECT * FROM $table_domain WHERE domain='$fDomain'"); if ($result['rows'] == 1) { $row = db_array ($result['result']); $tMaxquota = $row['maxquota']; } } } if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['cancel'])) { header("Location: list-virtual.php?domain=$fDomain"); exit(0); } if ($_SERVER['REQUEST_METHOD'] == "POST") { if (isset ($_POST['fPassword'])) $fPassword = escape_string ($_POST['fPassword']); if (isset ($_POST['fPassword2'])) $fPassword2 = escape_string ($_POST['fPassword2']); if (isset ($_POST['fName'])) $fName = escape_string ($_POST['fName']); if (isset ($_POST['fQuota'])) $fQuota = intval ($_POST['fQuota']); if (isset ($_POST['fActive'])) $fActive = escape_string ($_POST['fActive']); if($fPassword != $user_details['password'] || $fPassword2 != $user_details['password']){ $min_length = $CONF['min_password_length']; if($fPassword == $fPassword2) { if ($fPassword != "") { if($min_length > 0 && strlen($fPassword) < $min_length) { flash_error(sprintf($PALANG['pPasswordTooShort'], $CONF['min_password_length'])); $error = 1; } $formvars['password'] = pacrypt($fPassword); } } else { flash_error($PALANG['pEdit_mailbox_password_text_error']); $error = 1; } } if ($CONF['quota'] == "YES") { if (!check_quota ($fQuota, $fDomain)) { $error = 1; $tName = $fName; $tQuota = $fQuota; $tActive = $fActive; $pEdit_mailbox_quota_text = $PALANG['pEdit_mailbox_quota_text_error']; } } if ($error != 1) { if (!empty ($fQuota)) { $quota = multiply_quota ($fQuota); } else { $quota = 0; } if ($fActive == "on") { $sqlActive = db_get_boolean(True); $fActive = 1; } else { $sqlActive = db_get_boolean(False); $fActive = 0; } $formvars['name'] = $fName; $formvars['quota'] =$quota; $formvars['active']=$sqlActive; if(preg_match('/^(.*)@/', $fUsername, $matches)) { $formvars['local_part'] = $matches[1]; } $result = db_update('mailbox', "username='$fUsername' AND domain='$fDomain'", $formvars, array('modified')); $maildir = $user_details['maildir']; if ($result != 1 || !mailbox_postedit($fUsername,$fDomain,$maildir, $quota)) { $tMessage = $PALANG['pEdit_mailbox_result_error']; } else { db_log ($SESSID_USERNAME, $fDomain, 'edit_mailbox', $fUsername); $result = db_query ("UPDATE $table_alias SET active=$sqlActive WHERE address='$fUsername' AND domain='$fDomain'"); if ($result['rows'] != 1) { $error = 1; $tMessage = $PALANG['pEdit_mailbox_result_error']; } else { db_log ($SESSID_USERNAME, $fDomain, 'edit_alias_state', $fUsername); } header ("Location: list-virtual.php?domain=$fDomain"); exit(0); } } else { # error detected. Put the values the user entered in the form again. $tName = $fName; $tQuota = $fQuota; $tActive = $fActive; } } include ("templates/header.php"); include ("templates/menu.php"); include ("templates/edit-mailbox.php"); include ("templates/footer.php"); /* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */ ?> postfixadmin-2.3.7/setup.php0000664000175000017620000003470212167246242016144 0ustar davidpalepurple

    Postfix Admin Setup Checker

    Running software:

      Error: Depends on: PHP v5
      \n"; $error += 1; } if (phpversion() >= 5) { $phpversion = 5; print "
    • PHP version " . phpversion () . "
    • \n"; } } else { print "
    • Unable to check for PHP version. (missing function: phpversion())
    • \n"; } // // Check for Apache version // if ($f_apache_get_version == 1) { print "
    • " . apache_get_version() . "
    • \n"; } else { # not running on Apache. # However postfixadmin _is_ running, so obviously we are on a supported webserver ;-)) # No need to confuse the user with a warning. } print "
    "; print "

    Checking for dependencies:\n"; print "

      \n"; // // Check for Magic Quotes // if ($f_get_magic_quotes_gpc == 1) { if (get_magic_quotes_gpc () == 0) { print "
    • Magic Quotes: Disabled - OK
    • \n"; } else { print "
    • Warning: Magic Quotes: ON (internal workaround used)
    • \n"; } } else { print "
    • Unable to check for Magic Quotes. (missing function: get_magic_quotes_gpc())
    • \n"; } // // Check for config.inc.php // $config_loaded = 0; if ($file_config == 1) { print "
    • Depends on: presence config.inc.php - OK
    • \n"; require_once($incpath.'/config.inc.php'); $config_loaded = 1; if(isset($CONF['configured'])) { if($CONF['configured'] === TRUE) { print "
    • Checking \$CONF['configured'] - OK\n"; } else { print "
    • Warning: \$CONF['configured'] is 'false'.
      \n"; print "You must edit your config.inc.php and change this to true (this indicates you've created the database and user)
      \n"; } } } else { print "
    • Error: Depends on: presence config.inc.php - NOT FOUND
    • \n"; print "Create the file, and edit as appropriate (e.g. select database type etc)
      "; print "For example:
      \n"; print "
      cp config.inc.php.sample config.inc.php
      \n"; $error =+ 1; } // // Check if there is support for at least 1 database // if (($f_mysql_connect == 0) and ($f_mysqli_connect == 0) and ($f_pg_connect == 0)) { print "
    • Error: There is no database support in your PHP setup
      \n"; print "To install MySQL 3.23 or 4.0 support on FreeBSD:
      \n"; print "
      % cd /usr/ports/databases/php$phpversion-mysql/\n";
          print "% make clean install\n";
          print " - or with portupgrade -\n";
          print "% portinstall php$phpversion-mysql
      \n"; if ($phpversion >= 5) { print "To install MySQL 4.1 support on FreeBSD:
      \n"; print "
      % cd /usr/ports/databases/php5-mysqli/\n";
              print "% make clean install\n";
              print " - or with portupgrade -\n";
              print "% portinstall php5-mysqli
      \n"; } print "To install PostgreSQL support on FreeBSD:
      \n"; print "
      % cd /usr/ports/databases/php$phpversion-pgsql/\n";
          print "% make clean install\n";
          print " - or with portupgrade -\n";
          print "% portinstall php$phpversion-pgsql
    • \n"; $error =+ 1; } // // MySQL 3.23, 4.0 functions // if ($f_mysql_connect == 1) { print "
    • Depends on: MySQL 3.23, 4.0 - OK
    • \n"; } // // MySQL 4.1 functions // if ($phpversion >= 5) { if ($f_mysqli_connect == 1) { print "
    • Depends on: MySQL 4.1 - OK\n"; if ( !($config_loaded && $CONF['database_type'] == 'mysqli') ) { print "(change the database_type to 'mysqli' in config.inc.php!!)\n"; } print "
    • "; } } // // PostgreSQL functions // if ($f_pg_connect == 1) { print "
    • Depends on: PostgreSQL - OK \n"; if ( !($config_loaded && $CONF['database_type'] == 'pgsql') ) { print "(change the database_type to 'pgsql' in config.inc.php!!)\n"; } print "
    • "; } // // Database connection // if ($config_loaded) { list ($link, $error_text) = db_connect(TRUE); if ($error_text == "") { print "
    • Testing database connection - OK - {$CONF['database_type']}://{$CONF['database_user']}:xxxxx@{$CONF['database_host']}/{$CONF['database_name']}
    • "; } else { print "
    • Error: Can't connect to database
      \n"; print "Please edit the \$CONF['database_*'] parameters in config.inc.php.\n"; print "$error_text
    • \n"; $error ++; } } // // Session functions // if ($f_session_start == 1) { print "
    • Depends on: session - OK
    • \n"; } else { print "
    • Error: Depends on: session - NOT FOUND
      \n"; print "To install session support on FreeBSD:
      \n"; print "
      % cd /usr/ports/www/php$phpversion-session/\n";
          print "% make clean install\n";
          print " - or with portupgrade -\n";
          print "% portinstall php$phpversion-session
    • \n"; $error =+ 1; } // // PCRE functions // if ($f_preg_match == 1) { print "
    • Depends on: pcre - OK
    • \n"; } else { print "
    • Error: Depends on: pcre - NOT FOUND
      \n"; print "To install pcre support on FreeBSD:
      \n"; print "
      % cd /usr/ports/devel/php$phpversion-pcre/\n";
          print "% make clean install\n";
          print " - or with portupgrade -\n";
          print "% portinstall php$phpversion-pcre
    • \n"; $error =+ 1; } // // Multibyte functions // if ( $f_mb_encode_mimeheader == 1 ) { print "
    • Depends on: multibyte string - OK
    • \n"; } else { print "
    • Error: Depends on: multibyte string - NOT FOUND
      \n"; print "To install multibyte string support, install php$phpversion-mbstring
    • \n"; $error =+ 1; } // // Imap functions // if ( $f_imap_open == 1) { print "
    • Depends on: IMAP functions - OK
    • \n"; } else { print "
    • Warning: Depends on: IMAP functions - NOT FOUND
      \n"; print "To install IMAP support, install php$phpversion-imap
      \n"; print "Without IMAP support, you won't be able to create subfolders when creating mailboxes.
    • \n"; # $error =+ 1; } print "
    "; if ($error != 0) { print "

    Please fix the errors listed above.

    "; } else { print "

    Everything seems fine... attempting to create/update database structure

    \n"; require_once($incpath.'/upgrade.php'); $pAdminCreate_admin_username_text = $PALANG['pAdminCreate_admin_username_text']; $pAdminCreate_admin_password_text = ""; $tUsername = ''; $tMessage = ''; $lostpw_error = 0; $setuppw = ""; if (isset($CONF['setup_password'])) $setuppw = $CONF['setup_password']; if (safepost("form") == "setuppw") { # "setup password" form submitted if (safepost('setup_password') != safepost('setup_password2')) { $tMessage = "The two passwords differ!"; $lostpw_error = 1; } else { list ($lostpw_error, $lostpw_result) = check_setup_password(safepost('setup_password'), 1); $tMessage = $lostpw_result; $setuppw = "changed"; } } elseif (safepost("form") == "createadmin") { # "create admin" form submitted list ($pw_check_error, $pw_check_result) = check_setup_password(safepost('setup_password')); if ($pw_check_result != 'pass_OK') { $error += 1; $tMessage = $pw_check_result; } if($error == 0 && $pw_check_result == 'pass_OK') { if (isset ($_POST['fUsername'])) $fUsername = escape_string ($_POST['fUsername']); if (isset ($_POST['fPassword'])) $fPassword = escape_string ($_POST['fPassword']); if (isset ($_POST['fPassword2'])) $fPassword2 = escape_string ($_POST['fPassword2']); // XXX need to ensure domains table includes an 'ALL' entry. $table_domain = table_by_key('domain'); $r = db_query("SELECT * FROM $table_domain WHERE domain = 'ALL'"); if($r['rows'] == 0) { db_insert('domain', array('domain' => 'ALL', 'description' => '', 'transport' => '') ); // all other fields should default through the schema. } list ($error, $tMessage, $pAdminCreate_admin_username_text, $pAdminCreate_admin_password_text) = create_admin($fUsername, $fPassword, $fPassword2, array('ALL'), TRUE); if ($error != 0) { if (isset ($_POST['fUsername'])) $tUsername = escape_string ($_POST['fUsername']); } } } if ( ($setuppw == "" || $setuppw == "changeme" || safeget("lostpw") == 1 || $lostpw_error != 0) /* && $_SERVER['REQUEST_METHOD'] != "POST" */ ) { # show "create setup password" form ?>

    Change setup password

    Setup password
    Setup password (again)

    Create superadmin account

    Setup password Lost password?
     
    Since version 2.3 there is no requirement to delete setup.php!

    \n"; print "Check the config.inc.php file for any other settings that you might need to change!
    \n"; } ?>
    0 (or 1), 'message => text ) */ function check_setup_password($password, $lostpw_mode = 0) { global $CONF; $error = 1; # be pessimistic $setuppw = ""; if (isset($CONF['setup_password'])) $setuppw = $CONF['setup_password']; list($confsalt, $confpass, $trash) = explode(':', $setuppw . '::'); $pass = encrypt_setup_password($password, $confsalt); if ($password == "" ) { # no password specified? $result = "Setup password must be specified
    If you didn't set up a setup password yet, enter the password you want to use."; } elseif (strlen($password) < $CONF['min_password_length']) { # password too short? $result = "The setup password you entered is too short. Please choose a better one."; } elseif ($pass == $setuppw && $lostpw_mode == 0) { # correct passsword (and not asking for a new password) $result = "pass_OK"; $error = 0; } else { $pass = encrypt_setup_password($password, generate_setup_password_salt()); $result = ""; if ($lostpw_mode == 1) { $error = 0; # non-matching password is expected when the user asks for a new password } else { $result = '

    Setup password not specified correctly

    '; } $result .= '

    If you want to use the password you entered as setup password, edit config.inc.php and set

    '; $result .= "
    \$CONF['setup_password'] = '$pass';
    "; } return array ($error, $result); } /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ ?> postfixadmin-2.3.7/VIRTUAL_VACATION/0000775000175000017620000000000012301477472016700 5ustar davidpalepurplepostfixadmin-2.3.7/VIRTUAL_VACATION/tests/0000775000175000017620000000000012301477472020042 5ustar davidpalepurplepostfixadmin-2.3.7/VIRTUAL_VACATION/tests/mailing-list.txt0000664000175000017620000001517111046137027023173 0ustar davidpalepurpleReturn-Path: X-Original-To: david@example.org Delivered-To: david@example.org Received: by mail.palepurple.co.uk (Postfix, from userid 1007) id A41BE894CF8; Tue, 5 Aug 2008 19:46:09 +0100 (BST) Received: from localhost (localhost [127.0.0.1]) by mail.palepurple.co.uk (Postfix) with ESMTP id 6786E894CF9 for ; Tue, 5 Aug 2008 19:46:09 +0100 (BST) X-Virus-Scanned: by Amavis+SpamAssassin+ClamAV and more at palepurple.co.uk X-Spam-Score: -2.478 X-Spam-Level: X-Spam-Status: No, score=-2.478 tagged_above=-99 required=5 tests=[AWL=0.545, BAYES_00=-2.599, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_LOW=-1, SPF_HELO_NEUTRAL=0.576, SPF_PASS=-0.001] Received: from mail.palepurple.co.uk ([127.0.0.50]) by localhost (oak.palepurple.co.uk [127.0.0.50]) (amavisd-new, port 10024) with ESMTP id F7C1kX6O4LsN for ; Tue, 5 Aug 2008 19:46:01 +0100 (BST) Received: from www.zend.com (lists.zend.com [67.15.86.102]) by mail.palepurple.co.uk (Postfix) with SMTP id 83287894CF8 for ; Tue, 5 Aug 2008 19:46:01 +0100 (BST) Received: (qmail 28760 invoked by uid 505); 5 Aug 2008 18:45:46 -0000 Mailing-List: contact fw-general-help@lists.zend.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: Delivered-To: mailing list fw-general@lists.zend.com Received: (qmail 28753 invoked from network); 5 Aug 2008 18:45:46 -0000 DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=s1024; d=yahoo.com; h=Received:X-Mailer:Date:From:Subject:To:Cc:MIME-Version:Content-Type:Message-ID; b=RX7cjkrkpdsfHOXg2TRzzF2P5UXe0S5UVRucVl9FdqyE070/mV2za8ehvsGVRTh11tjkhkzh9QJoijpzHTTyu8F4HUHHoql4wUS6zJJC/PgdcCpBVXf0Im4RkyXqhIOAndNk1d9tCPmUnKDjC6SvO6i0Xd5+CqFH9f+eaKzUFAI=; X-Mailer: YahooMailRC/1042.48 YahooMailWebService/0.7.218 Date: Tue, 5 Aug 2008 11:45:44 -0700 (PDT) From: =?iso-8859-1?Q?P=E1draic_Brady?= To: Some one Else Cc: Zend Framework General MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="0-283769398-1217961944=:498" Message-ID: <944272.498.qm@web55003.mail.re4.yahoo.com> X-pstn-neptune: 0/0/0.00/0 X-pstn-levels: (S:99.90000/99.90000 CV:99.0000 P:95.9108 M:97.0282 C:98.6951 ) X-pstn-settings: 1 (0.1500:0.1500) cv gt3 gt2 gt1 p m c X-pstn-addresses: from [638/31] Subject: Re: [fw-general] Zend_Paginate how to integrate? Content-Length: 4072 Lines: 60 --0-283769398-1217961944=:498 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: quoted-printable I do pretty much what Giorgio suggests and tie it into the Model as much as= possible - fits into the concept of doing as little as possible in your co= ntrollers by pushing reusable code into Model (or other) objects if appropr= iate.=0A=0A P=E1draic Brady=0A=0Ahttp://blog.astrumfutura.com=0Ahttp://www.= patternsforphp.com=0AOpenID Europe Foundation=0A=0A=0A=0A=0A----- Original = Message ----=0AFrom: Giorgio Sironi =0ATo= : Axel W=FCstemann =0ACc: fw-general@xxlists.zend.com=0ASent: Tu= esday, August 5, 2008 7:20:48 PM=0ASubject: Re: [fw-general] Zend_Paginate = how to integrate?=0A=0A2008/8/5 Axel W=FCstemann :=0A> Yes, it= seems to me a good idea to let reside the paginator in the model.=0A> What= happens in the controller? How the view comes into play?=0A=0AThe controll= er simply calls the method prepareArticles with the right=0Apage (a param o= f request) and pass the paginator to the view, so the=0Aview script can use= it for helpers like PaginationControl. Note that=0Abecause the paginator g= oes into the view, it return only=0Amultidimensional array and not objects.= =0A=0A-- =0AGiorgio Sironi=0APiccolo Principe & Ossigeno Scripter=0Ahttp://= www.sourceforge.net/projects/ossigeno=0A --0-283769398-1217961944=:498 Content-Type: text/html; charset=iso-8859-1 Content-Transfer-Encoding: quoted-printable
    I do pretty much what Giorgio suggests and tie i= t into the Model as much as possible - fits into the concept of doing as li= ttle as possible in your controllers by pushing reusable code into Model (o= r other) objects if appropriate.
     
    P=E1draic Bra= dy

    http://blog= .astrumfutura.com
    http://www.patternsforphp.comOpenID Europe Foundation


    ----- Original Message ----
    From: Giorgio Sironi <pic= coloprincipeazzurroxxxxx@gxxxmail.com>
    To: Axel W=FCstemann <awuxx@qbus.de&g= t;
    Cc: fw-general@xxxlists.zend.com
    Sent: Tuesday, August 5, 2008 7:20:4= 8 PM
    Subject: Re: [fw-general] Zend_Paginate how to integrate?

    = =0A2008/8/5 Axel W=FCstemann <xxawu@qxxxbus.de>:
    > Yes, it seems to me a good= idea to let reside the paginator in the model.
    > What happens in the= controller? How the view comes into play?

    The controller simply cal= ls the method prepareArticles with the right
    page (a param of request) a= nd pass the paginator to the view, so the
    view script can use it for hel= pers like PaginationControl. Note that
    because the paginator goes into t= he view, it return only
    multidimensional array and not objects.

    -= -
    Giorgio Sironi
    Piccolo Principe & Ossigeno Scripter
    http://= www.sourceforge.net/projects/ossigeno
    --0-283769398-1217961944=:498-- postfixadmin-2.3.7/VIRTUAL_VACATION/tests/spam.txt0000664000175000017620000001056311046137027021542 0ustar davidpalepurpleReturn-Path: X-Original-To: david@codepoets.co.uk Delivered-To: david@codepoets.co.uk Received: by mail.palepurple.co.uk (Postfix, from userid 1007) id A7BB7894CF8; Tue, 5 Aug 2008 19:32:19 +0100 (BST) Received: from localhost (localhost [127.0.0.1]) by mail.palepurple.co.uk (Postfix) with ESMTP id 673E4894CF9 for ; Tue, 5 Aug 2008 19:32:19 +0100 (BST) X-Quarantine-ID: X-Virus-Scanned: by Amavis+SpamAssassin+ClamAV and more at palepurple.co.uk X-Spam-Flag: YES X-Spam-Score: 35.511 X-Spam-Level: *********************************** X-Spam-Status: Yes, score=35.511 tagged_above=-99 required=5 tests=[BAYES_99=3.5, DIGEST_MULTIPLE=0.001, FH_HELO_EQ_D_D_D_D=0.001, HELO_DYNAMIC_HCC=4.295, HELO_DYNAMIC_IPADDR2=4.395, HTML_EXTRA_CLOSE=2.809, HTML_MESSAGE=0.001, PYZOR_CHECK=3.7, RAZOR2_CF_RANGE_51_100=0.5, RAZOR2_CF_RANGE_E4_51_100=1.5, RAZOR2_CF_RANGE_E8_51_100=1.5, RAZOR2_CHECK=0.5, RCVD_IN_PBL=0.905, RDNS_DYNAMIC=0.1, TVD_RCVD_IP=1.931, URIBL_AB_SURBL=1.86, URIBL_BLACK=1.955, URIBL_JP_SURBL=1.501, URIBL_OB_SURBL=1.5, URIBL_RHS_DOB=1.083, URIBL_SC_SURBL=0.474, URIBL_WS_SURBL=1.5] X-Spam-Report: * 3.5 BAYES_99 BODY: Bayesian spam probability is 99 to 100% * [score: 0.9982] * 4.3 HELO_DYNAMIC_HCC Relay HELO'd using suspicious hostname (HCC) * 4.4 HELO_DYNAMIC_IPADDR2 Relay HELO'd using suspicious hostname (IP addr * 2) * 0.0 FH_HELO_EQ_D_D_D_D Helo is d-d-d-d * 1.9 TVD_RCVD_IP TVD_RCVD_IP * 0.9 RCVD_IN_PBL RBL: Received via a relay in Spamhaus PBL * [189.31.157.78 listed in zen.spamhaus.org] * 2.8 HTML_EXTRA_CLOSE BODY: HTML contains far too many close tags * 0.0 HTML_MESSAGE BODY: HTML included in message * 1.5 RAZOR2_CF_RANGE_E8_51_100 Razor2 gives engine 8 confidence level * above 50% * [cf: 100] * 1.5 RAZOR2_CF_RANGE_E4_51_100 Razor2 gives engine 4 confidence level * above 50% * [cf: 100] * 0.5 RAZOR2_CHECK Listed in Razor2 (http://razor.sf.net/) * 0.5 RAZOR2_CF_RANGE_51_100 Razor2 gives confidence level above 50% * [cf: 100] * 3.7 PYZOR_CHECK Listed in Pyzor (http://pyzor.sf.net/) * 1.1 URIBL_RHS_DOB Contains an URI of a new domain (Day Old Bread) * [URIs: heartremember.com] * 2.0 URIBL_BLACK Contains an URL listed in the URIBL blacklist * [URIs: heartremember.com] * 1.9 URIBL_AB_SURBL Contains an URL listed in the AB SURBL blocklist * [URIs: heartremember.com] * 1.5 URIBL_WS_SURBL Contains an URL listed in the WS SURBL blocklist * [URIs: heartremember.com] * 1.5 URIBL_JP_SURBL Contains an URL listed in the JP SURBL blocklist * [URIs: heartremember.com] * 1.5 URIBL_OB_SURBL Contains an URL listed in the OB SURBL blocklist * [URIs: heartremember.com] * 0.5 URIBL_SC_SURBL Contains an URL listed in the SC SURBL blocklist * [URIs: heartremember.com] * 0.0 DIGEST_MULTIPLE Message hits more than one network digest check * 0.1 RDNS_DYNAMIC Delivered to trusted network by host with * dynamic-looking rDNS Received: from mail.palepurple.co.uk ([127.0.0.50]) by localhost (oak.palepurple.co.uk [127.0.0.50]) (amavisd-new, port 10024) with ESMTP id KOCPqIot+eWP for ; Tue, 5 Aug 2008 19:32:13 +0100 (BST) Received: from 189-31-157-78.gnace704.dsl.brasiltelecom.net.br (189-31-157-78.gnace704.dsl.brasiltelecom.net.br [189.31.157.78]) by mail.palepurple.co.uk (Postfix) with ESMTP id 02E02894CF8 for ; Tue, 5 Aug 2008 19:32:11 +0100 (BST) Date: Tue, 05 Aug 2008 16:44:31 +0000 Message-ID: <45605.clarke@shan> From: "ferd clarke" To: Subject: *** SPAM *** Super eustace proposition MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="=_xjl52j6iKNOFLD" Content-Length: 628 Lines: 26 This is a multi-part message in MIME format. --=_xjl52j6iKNOFLD Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable view, medicine todays best solution check out here --=_xjl52j6iKNOFLD Content-Type: text/html; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable

    view, medicine todays best solution check out here

    --=_xjl52j6iKNOFLD-- postfixadmin-2.3.7/VIRTUAL_VACATION/tests/test.sh0000664000175000017620000000641011135335057021352 0ustar davidpalepurple#!/bin/bash # This is an extremely simplistic test harness for the vacation functionality. # To judge success or failure you (unfortunately) need to tail -f the log file, which sucks a little, # but hey - it's better than no tests, right? # Original author: David Goodwin (hence all the palepurple.co.uk references!) # It would be nice if we could get some sort of status back from the vacation.pl script to indicate mail being sent, or not. export PGPASSWORD=gingerdog export PGUSER=dg export PGDATABASE=postfix export PGHOST=pgsqlserver echo "DELETE FROM vacation WHERE email = 'david@example.org'" | psql # First time around, there should be no vacation record for david@example.org, so these should all not cause mail to be sent. # some will trip up spam/mailing list protection etc though echo echo "NONE OF THESE SHOULD RESULT IN MAIL BEING SENT" echo #echo "On: mailing-list.txt:" # cat mailing-list.txt | perl ../vacation.pl -t yes -f fw-general-return-20540-david=example.org@lists.zend.com -- david\#example.org@autoreply.example.org echo "On: test-email.txt:" cat test-email.txt | perl ../vacation.pl -t yes -f david1@example.org -- david\#example.org@autoreply.example.org echo "On: spam.txt:" cat spam.txt | perl ../vacation.pl -t yes -f mary@ccr.org -- david\#example.org@autoreply.example.org echo "On: asterisk-email.txt:" cat asterisk-email.txt | perl ../vacation.pl -t yes -f www-data@palepurple.net -- david\#example.org@autoreply.example.org # do not reply to facebook echo "On: facebook.txt:" cat facebook.txt | perl ../vacation.pl -t yes -f notification+meynbxsa@facebookmail.com -- david\#example.org@autoreply.example.org # do not send yourself a vacation notice. echo "On: mail-myself.txt:" cat mail-myself.txt | perl ../vacation.pl -t yes -f david@example.org -- david\#example.org@autoreply.example.org # do not send yourself a vacation notice. echo "On: teodor-smtp-envelope-headers.txt:" cat teodor-smtp-envelope-headers.txt | perl ../vacation.pl -t yes -f david@example.org -- david\#example.org@autoreply.example.org echo "INSERT INTO vacation (email, subject, body, created, active, domain) VALUES ('david@example.org', 'I am on holiday', 'Yeah, that is right', NOW(), true, 'example.org')" | psql echo echo "VACATION TURNED ON " echo echo "Still ignore mailing list" cat mailing-list.txt | perl ../vacation.pl -t yes -f fw-general-return-20540-david=example.org@lists.zend.com -- david\#example.org@autoreply.example.org echo " * Should send vacation message for this *" cat test-email.txt | perl ../vacation.pl -t yes -f david1@example.org -- david\#example.org@autoreply.example.org echo " * Spam - no vacation message for this" cat spam.txt | perl ../vacation.pl -t yes -f mary@xxccr.org -- david\#example.org@autoreply.example.org echo " * OK - should send vacation message for this" cat asterisk-email.txt | perl ../vacation.pl -t yes -f www-data@palepurple.net -- david\#example.org@autoreply.example.org echo " * Facebook - should not send vacation message for" cat facebook.txt | perl ../vacation.pl -t yes -f notification+meynbxsa@facebookmail.com -- david\#example.org@autoreply.example.org echo " * Mailing myself - should not send vacation message" cat mail-myself.txt | perl ../vacation.pl -t yes -f david@example.org -- david\#example.org@autoreply.example.org echo postfixadmin-2.3.7/VIRTUAL_VACATION/tests/test-email.txt0000664000175000017620000000336311056576123022653 0ustar davidpalepurpleReturn-Path: X-Original-To: david@example.org Delivered-To: david@example.org Received: by mail.palepurple.co.uk (Postfix, from userid 1007) id 83AE0894CF8; Tue, 5 Aug 2008 20:15:53 +0100 (BST) Received: from localhost (localhost [127.0.0.1]) by mail.palepurple.co.uk (Postfix) with ESMTP id 4A249894CF9 for ; Tue, 5 Aug 2008 20:15:53 +0100 (BST) X-Virus-Scanned: by Amavis+SpamAssassin+ClamAV and more at palepurple.co.uk X-Spam-Score: -2.836 X-Spam-Level: X-Spam-Status: No, score=-2.836 tagged_above=-99 required=5 tests=[AWL=-0.237, BAYES_00=-2.599] Received: from mail.palepurple.co.uk ([127.0.0.50]) by localhost (oak.palepurple.co.uk [127.0.0.50]) (amavisd-new, port 10024) with ESMTP id gHB1TKpjKIKX for ; Tue, 5 Aug 2008 20:15:50 +0100 (BST) Received: from irc.palepurple.co.uk (irc.palepurple.co.uk [89.16.169.131]) by mail.palepurple.co.uk (Postfix) with ESMTP id CAF82894CF8 for ; Tue, 5 Aug 2008 20:15:50 +0100 (BST) Received: by irc.palepurple.co.uk (Postfix, from userid 1000) id 8869450146; Tue, 5 Aug 2008 20:15:50 +0100 (BST) Date: Tue, 5 Aug 2008 20:15:50 +0100 From: David Goodwin To: "DG" , "Fred@Work" , "Barney Rubble" , "Rover Dog" , roger@example.org Subject: test email Message-ID: <20080805191549.GA27905@codepoets.co.uk> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline X-GnuPG-Key-URL: http://codepoets.co.uk/files/pubkey.txt X-PGP-Key: 0x117957A6 User-Agent: Mutt/1.5.13 (2006-08-11) Content-Length: 136 Lines: 7 hello world; this is in plain text only. -- David Goodwin [ http://www.codepoets.co.uk ] postfixadmin-2.3.7/VIRTUAL_VACATION/tests/mail-myself.txt0000664000175000017620000000327311135335572023025 0ustar davidpalepurpleReturn-Path: X-Original-To: david@example.org Delivered-To: david@example.org Received: by mail.palepurple.co.uk (Postfix, from userid 1007) id 83AE0894CF8; Tue, 5 Aug 2008 20:15:53 +0100 (BST) Received: from localhost (localhost [127.0.0.1]) by mail.palepurple.co.uk (Postfix) with ESMTP id 4A249894CF9 for ; Tue, 5 Aug 2008 20:15:53 +0100 (BST) X-Virus-Scanned: by Amavis+SpamAssassin+ClamAV and more at palepurple.co.uk X-Spam-Score: -2.836 X-Spam-Level: X-Spam-Status: No, score=-2.836 tagged_above=-99 required=5 tests=[AWL=-0.237, BAYES_00=-2.599] Received: from mail.palepurple.co.uk ([127.0.0.50]) by localhost (oak.palepurple.co.uk [127.0.0.50]) (amavisd-new, port 10024) with ESMTP id gHB1TKpjKIKX for ; Tue, 5 Aug 2008 20:15:50 +0100 (BST) Received: from irc.palepurple.co.uk (irc.palepurple.co.uk [89.16.169.131]) by mail.palepurple.co.uk (Postfix) with ESMTP id CAF82894CF8 for ; Tue, 5 Aug 2008 20:15:50 +0100 (BST) Received: by irc.palepurple.co.uk (Postfix, from userid 1000) id 8869450146; Tue, 5 Aug 2008 20:15:50 +0100 (BST) Date: Tue, 5 Aug 2008 20:15:50 +0100 From: David Goodwin To: david@example.org, fred@example.org, barney@example.org, rover@example.org, roger@example.org Subject: test email Message-ID: <20080805191549.GA27905@codepoets.co.uk> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline X-GnuPG-Key-URL: http://codepoets.co.uk/files/pubkey.txt X-PGP-Key: 0x117957A6 User-Agent: Mutt/1.5.13 (2006-08-11) Content-Length: 136 Lines: 7 hello world; this is in plain text only. -- David Goodwin [ http://www.codepoets.co.uk ] postfixadmin-2.3.7/VIRTUAL_VACATION/tests/teodor-smtp-envelope-headers.txt0000664000175000017620000000123411135335057026300 0ustar davidpalepurpleX-Original-To: david@example.org Delivered-To: david@example.org X-Virus-Scanned: amavisd-new at mx.ro From: "Teodor Iacob" To: Subject: estsgf Date: Mon, 19 Jan 2009 14:49:17 +0200 X-Mailer: Microsoft Office Outlook 11 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.5579 Thread-Index: Acl6NFZyC+AImZ1WQSS0cPUO/Y2FqA== X-BRO-MailScanner-Information: Please contact the ISP for more information X-BRO-MailScanner-ID: n0JCoUwB014357 X-BRO-MailScanner: Found to be clean X-MailScanner-From: david@example.org X-BRO-MailScanner-Watermark: 1232974231.00027@11VRmWFJ18WRflEdvrILlQ dsgsgfsgfg -- Teodor Iacob postfixadmin-2.3.7/VIRTUAL_VACATION/tests/facebook.txt0000664000175000017620000000437411046137027022356 0ustar davidpalepurpleReturn-Path: X-Original-To: david@example.org Delivered-To: david@example.org Received: by mail.palepurple.co.uk (Postfix, from userid 1007) id B735A894CF8; Mon, 4 Aug 2008 16:28:13 +0100 (BST) Received: from localhost (localhost [127.0.0.1]) by mail.palepurple.co.uk (Postfix) with ESMTP id 79230894CF9 for ; Mon, 4 Aug 2008 16:28:13 +0100 (BST) X-Virus-Scanned: by Amavis+SpamAssassin+ClamAV and more at palepurple.co.uk X-Spam-Score: -3.565 X-Spam-Level: X-Spam-Status: No, score=-3.565 tagged_above=-99 required=5 tests=[AWL=0.035, BAYES_00=-2.599, RCVD_IN_DNSWL_LOW=-1, SPF_PASS=-0.001] Received: from mail.palepurple.co.uk ([127.0.0.50]) by localhost (oak.palepurple.co.uk [127.0.0.50]) (amavisd-new, port 10024) with ESMTP id AajG3+FXGWMd for ; Mon, 4 Aug 2008 16:28:10 +0100 (BST) Received: from mx-out.facebook.com (outmail003.ash1.tfbnw.net [69.63.184.103]) by mail.palepurple.co.uk (Postfix) with ESMTP id 36DD4894CF8 for ; Mon, 4 Aug 2008 16:28:09 +0100 (BST) Received: from www.new.facebook.com (intlb01-mip1.sctm.tfbnw.net [10.1.240.6]) by mx-out.facebook.com [email023.ash1.facebook.com] (8.13.7/8.13.6) with ESMTP id m74FS8Oa030908 for ; Mon, 4 Aug 2008 08:28:09 -0700 X-Facebook: from zuckmail ([207.118.59.216]) by www.new.facebook.com with HTTP (ZuckMail); Date: Mon, 4 Aug 2008 08:28:08 -0700 To: David Goodwin From: Facebook Reply-to: noreply Subject: Mark Spencer also commented on Jon Masters's note... Message-ID: X-Priority: 3 X-Mailer: ZuckMail [version 1.00] X-Facebook-Notify: note_reply Errors-To: notification+meynbxsa@facebookmail.com MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="UTF-8" Content-Length: 374 Lines: 14 Mark also commented on Jon Masters's note "Visiting the UK" To read all the comments, follow the link below: http://www.facebook.com/n/?note.php¬e_id=whatever Thanks, The Facebook Team ___ Want to control which emails you receive from Facebook? Go to: http://www.facebook.com/editaccount.php?notifications&md=sheepmightfly postfixadmin-2.3.7/VIRTUAL_VACATION/tests/asterisk-email.txt0000664000175000017620000000162411056576123023517 0ustar davidpalepurpleReturn-Path: X-Original-To: david@example.org Delivered-To: david@example.org Received: by mail.palepurple.co.uk (Postfix, from userid 33) id 1942F894CF9; Fri, 1 Aug 2008 11:23:45 +0100 (BST) To: "" Subject: New Phone call - annotate it! X-PHP-Script: admin.palepurple.co.uk/contacts/dispatch.php for 78.105.97.55 From: "asterisk@example.org" Date: Fri, 01 Aug 2008 11:23:45 +0100 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Message-Id: <20080801102345.1942F894CF9@mail.palepurple.co.uk> Content-Length: 250 Lines: 5 =0AVisit the following URL(s) to annotate these phone calls... :=0A=0A htt= ps://admin.palepurple.co.uk/contacts/phone_communication/browse.php=0Ahttp= s://admin.palepurple.co.uk/contacts/phone_communication/view.php?phone_com= munication_id=3D3532 postfixadmin-2.3.7/VIRTUAL_VACATION/INSTALL.TXT0000664000175000017620000001471211151216001020371 0ustar davidpalepurple################################################## # Virtual Vacation for Postfix Admin Release 2.x # ################################################## # # Postfix Admin (Virtual Vacation) # Originally authored by Mischa Peters # Copyright (c) 2002 - 2005 High5! # Licensed under GPL for more info check GPL-LICENSE.TXT # REQUIRED! --------- There are a bunch of Perl modules which need installing, depending on your distribution these may be available through your package management tool, or will need installing through CPAN. A full list of required modules can be found in the source of vacation.pl. It obviously relies on Perl About Virtual Vacation ---------------------- The vacation script runs as service within Postfix's master.cf configuration file. Mail is sent to the vacation service via a transport table mapping. When users mark themselves as away on vacation, an alias is added to their account sending a copy of all mail to them to the vacation service. e.g. mail to billy@goat.com will be delivered to billy@goat.com AND billy#goat.com@autoreply.goat.com Mail to @autoreply.goat.com is caught by the vacation.pl script and a reply will be sent based on various settings. By default a reply is only sent once. Install Virtual Vacation ------------------------ 1. Create a local account ------------------------- Create a dedicated local user account called "vacation". This user handles all potentially dangerous mail content - that is why it should be a separate account. Do not use "nobody", and most certainly do not use "root" or "postfix". The user will never log in, and can be given a "*" password and non-existent shell and home directory. This should look like this: #/etc/passwd vacation:*:65501:65501::0:0:Virtual Vacation:/nonexistent:/sbin/nologin #/etc/group vacation:*:65501: 2. Create a directory --------------------- Create a directory, for example /var/spool/vacation, that is accessible only to the "vacation" user. This is where the vacation script is supposed to store its temporary files. 3. Copy the files ----------------- Copy the vacation.pl file to the directory you created above: $ cp vacation.pl /vacation.pl $ chown -R vacation:vacation Which will then look something like: -rwx------ 1 vacation vacation 3356 Dec 21 00:00 vacation.pl* 4. Setup the transport type --------------------------- Define the transport type in the Postfix master file: #/etc/postfix/master.cf: vacation unix - n n - - pipe flags=Rq user=vacation argv=/var/spool/vacation/vacation.pl -f ${sender} -- ${recipient} 5. Setup the transport maps file -------------------------------- Tell Postfix to use a transport maps file, so add the following to your Postfix main.cf: #/etc/postfix/main.cf: transport_maps = hash:/etc/postfix/transport Then add the transport definition to the newly created transport file. Obviously, change yourdomain.com to your own domain. This can be any arbitrary domain, and it is easiest if you just choose one that will be used for all your domains. #/etc/postfix/transport autoreply.yourdomain.com vacation: (You may need to create an entry in /etc/hosts for your non-existant domain) Execute "postmap /etc/postfix/transport" to build the hashed database. Execute "postfix reload" to complete the change. 6. Configure vacation.pl ------------------------ The perl vacation.pl script needs to know which database you are using, and also how to connect to the database. Namely : Change any variables starting with '$db_' and '$db_type' to either 'mysql' or 'pgsql'. Change the $vacation_domain variable to match what you entered in your /etc/postfix/transport file. You can do this in two ways: a) edit vacation.pl directly b) create /etc/mail/postfixadmin/vacation.conf and enter your settings there Just use perl syntax there to fill the config variables listed in vacation.pl (without the "our" keyword). Example: $db_username = 'mail'; 7. Check the alias expansion ---------------------------- Depending on your setup, you may have multiple 'smtpd' service definitions within your postfix master.cf file. This is especially the case if you are also using AMAVIS or another content filtering system when mail is re-injected into Postfix using the smtpd daemon. If you are, it's likely that alias expansion may happen more than once, in which case you may see vacation-style responses duplicated. To suppress this behaviour, you need to add : -o receive_override_options=no_address_mappings For example : smtp inet n - - - 12 smtpd -o content_filter=amavis:[127.0.0.50]:10024 ^^^ Alias expansion occurs here, so we don't want it to happen again for the other smtpd daemon (below) which receives email out of amavis on port 10025. 127.0.0.1:10025 inet n - - - - smtpd -o smtpd_autorized_xforward_hosts=127.0.0.0/8 -o smtpd_client_restrictions= -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o mynetworks=127.0.0.0/8 -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks,no_address_mappings 8. Security ----------- If security is an issue for you, read ../DOCUMENTS/Security.txt What do these files do? ----------------------- When a user enables a vacation message on their account, the alias definition is changed so that in addition to delivering to their own mailbox, it also delivers to a dummy alias which calls the vacation.pl program. In other words, if joeuser@domain.com enables their vacation, the entry in the alias database table will deliver mail to joeuser@something.com, as well as joeuser#something.com@autoreply.yourdomain.com vacation.pl then checks the database to see wether a user is on holiday and what message to send back. Make sure that vacation.pl is able to communicate to your database. In the first couple of lines you have to specify the database, username and password for it. NOTE: Make sure that the path to perl is correct. I'm in trouble! --------------- When something is not working there are a couple of files that you can have a look at. The most important one is your maillog (usually in /var/log/). Vacation.pl also has some debugging and logging capabilties. Check the top of vacation.pl. Done! ----- When this is all in place you need to have a look at the Postfix Admin config.inc.php. Here you need to enable Virtual Vacation for the site. postfixadmin-2.3.7/VIRTUAL_VACATION/FILTER_README0000664000175000017620000005056210715711016020625 0ustar davidpalepurpleIntroduction ============ This is a very first implementation of Postfix content filtering. A Postfix content filter receives unfiltered mail from Postfix and does one of the following: - re-injects the mail back into Postfix, perhaps after changing content - rejects the mail (by sending a suitable status code back to Postfix) so that it is returned to sender. - sends the mail somewhere else This document describes two approaches to content filtering: simple and advanced. Both filter all the mail by default. At the end are examples that show how to filter only mail from users, about using different filters for different domains that you provide MX service for, and about selective filtering on the basis of message envelope and/or header/body patterns. Simple content filtering example ================================ The first example is simple to set up. It uses a shell script that receives unfiltered mail from the Postfix pipe delivery agent, and that feeds filtered mail back into the Postfix sendmail command. Only mail arriving via SMTP will be content filtered. .................................. : Postfix : Unfiltered mail----->smtpd \ /local---->Filtered mail : -cleanup->queue- : ---->pickup / \smtp----->Filtered mail ^ : | : | : \pipe-----+ | .................................. | | | | | +-Postfix sendmail<----filter script<--+ Mail is filtered by a /some/where/filter program. This can be a simple shell script like this: #!/bin/sh # Localize these. INSPECT_DIR=/var/spool/filter SENDMAIL="/usr/sbin/sendmail -i" # Exit codes from EX_TEMPFAIL=75 EX_UNAVAILABLE=69 # Clean up when done or when aborting. trap "rm -f in.$$" 0 1 2 3 15 # Start processing. cd $INSPECT_DIR || { echo $INSPECT_DIR does not exist; exit $EX_TEMPFAIL; } cat >in.$$ || { echo Cannot save mail to file; exit $EX_TEMPFAIL; } # filter smtpd \ /local----> : -cleanup->queue- : ---->pickup / ^ | \smtp-----> : | v : : smtpd smtp : : 10026 | : ......................|........... ^ | | v ....|............ : | 10025 : : filter : : : ................. To enable content filtering in this manner, specify in main.cf a new parameter: /etc/postfix/main.cf: content_filter = scan:localhost:10025 This causes Postfix to add one extra content filtering record to each incoming mail message, with content scan:localhost:10025. The content filtering records are added by the smtpd and pickup servers. When a queue file has content filtering information, the queue manager will deliver the mail to the specified content filter regardless of its final destination. In this example, "scan" is an instance of the Postfix SMTP client with slightly different configuration parameters. This is how one would set up the service in the Postfix master.cf file: /etc/postfix/master.cf: scan unix - - n - 10 smtp Instead of a limit of 10 concurrent processes, use whatever process limit is feasible for your machine. Content inspection software can gobble up a lot of system resources, so you don't want to have too much of it running at the same time. The content filter can be set up with the Postfix spawn service, which is the Postfix equivalent of inetd. For example, to instantiate up to 10 content filtering processes on demand: /etc/postfix/master.cf: localhost:10025 inet n n n - 10 spawn user=filter argv=/some/where/filter localhost 10026 "filter" is a dedicated local user account. The user will never log in, and can be given a "*" password and non-existent shell and home directory. This user handles all potentially dangerous mail content - that is why it should be a separate account. In the above example, Postfix listens on port localhost:10025. If you want to have your filter listening on port localhost:10025 instead of Postfix, then you must run your filter as a stand-alone program. Note: the localhost port 10025 SMTP server filter should announce itself as "220 localhost...". Postfix aborts delivery when it connects to an SMTP server that uses the same hostname as Postfix ("host greeted me with my own hostname"), because that normally means you have a mail delivery loop problem. The example here assumes that the /some/where/filter command is a PERL script. PERL has modules that make talking SMTP easy. The command-line specifies that mail should be sent back into Postfix via localhost port 10026. The simplest content filter just copies SMTP commands and data between its inputs and outputs. If it has a problem, all it has to do is to reply to an input of `.' with `550 content rejected', and to disconnect without sending `.' on the connection that injects mail back into Postfix. The job of the content filter is to either bounce mail with a suitable diagnostic, or to feed the mail back into Postfix through a dedicated listener on port localhost 10026: /etc/postfix/master.cf: localhost:10026 inet n - n - 10 smtpd -o content_filter= -o local_recipient_maps= -o relay_recipient_maps= -o myhostname=localhost.domain.tld -o smtpd_helo_restrictions= -o smtpd_client_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o mynetworks=127.0.0.0/8 Warning for Postfix version 2 users: in this SMTP server after the content filter, do not override main.cf settings for virtual_alias_maps or virtual_alias_domains. That would cause mail to be rejected with "User unknown". This SMTP server has the same process limit as the "filter" master.cf entry. The "-o content_filter=" requests no content filtering for incoming mail. The "-o local_recipient_maps=" and "-o relay_recipient_maps=" avoid unnecessary table lookups. The "-o myhostname=localhost.domain.tld" avoids false alarms ("host greeted me with my own hostname") if your content filter is based on a proxy that simply relays SMTP commands. The "-o smtpd_xxx_restrictions" and "-o mynetworks=127.0.0.0/8" turn off UCE controls that would only waste time here. Squeezing out more performance ============================== Many refinements are possible, such as running a specially-configured smtp delivery agent for feeding mail into the content filter, and turning off address rewriting before content filtering. As the example below shows, things quickly become very complex, because a lot of main.cf like information gets listed in the master.cf file. This makes the system hard to understand. Even worse, details change as Postfix evolves and different configuration parameters are implemented by different programs. If you need to squeeze out more performance, it is probably simpler to run multiple Postfix instances, one before and one after the content filter. That way, each instance can have simple main.cf and master.cf files, each instance can have its own mail queue, and the system will be easier to understand. As before, we will set up a content filtering program that receives SMTP mail via localhost port 10025, and that submits SMTP mail back into Postfix via localhost port 10026. ....................................... : Postfix : ----->smtpd \ : : -pre-cleanup-\ /local----> ---->pickup / -queue- : : -cleanup-/ | \smtp-----> : bounces/ ^ v : : and locally | v : : forwarded smtpd scan : : messages 10026 | : ...........................|........... ^ | | v ....|............. : | 10025 : : filter : : : .................. To enable content filtering in this manner, specify in main.cf a new parameter: /etc/postfix/main.cf: content_filter = scan:localhost:10025 /etc/postfix/master.cf: # # These are the usual input "smtpd" and local "pickup" servers already # present in master.cf. We add an option to select a non-default # cleanup service (defined further below). # smtp inet n - n - - smtpd -o cleanup_service_name=pre-cleanup pickup fifo n - n 60 1 pickup -o cleanup_service_name=pre-cleanup # # ------------------------------------------------------------------ # # This is the cleanup daemon that handles messages in front of # the content filter. It does header_checks and body_checks (if # any), but does no virtual alias or canonical address mapping, # so that mail passes through your content filter with the original # recipient addresses mostly intact. # # Virtual alias or canonical address mapping happens in the second # cleanup phase after the content filter. This gives the content_filter # access to *largely* unmodified addresses for maximum flexibility. # # Some sites may specifically want to perform canonical or virtual # address mapping in front of the content_filter. In that case you # still have to enable address rewriting in the after-filter cleanup # instance, in order to correctly process forwarded mail or bounced # mail. # pre-cleanup unix n - n - 0 cleanup -o canonical_maps= -o sender_canonical_maps= -o recipient_canonical_maps= -o masquerade_domains= -o virtual_alias_maps= # # ------------------------------------------------------------------ # # This is the delivery agent that injects mail into the content # filter. It is tuned for low concurrency, because most content # filters burn CPU and use lots of memory. The process limit of 10 # re-enforces the effect of $default_destination_concurrency_limit. # Even without an explicit process limit, the concurrency is bounded # because all messages heading into the content filter have the same # destination. # scan unix - - n - 10 smtp # # ------------------------------------------------------------------ # # This is the SMTP listener that receives filtered messages from # the content filter. It *MUST* clear the content_filter # parameter to avoid loops, and use a different hostname to avoid # triggering the Postfix SMTP loop detection code. # # This "smtpd" uses the normal cleanup service which is also used # for bounces and for internally forwarded mail. # # The parameters from mynetworks onward disable all access # control other than insisting on connections from one of the IP # addresses of the host. This is typically overkill, but can # reduce resource usage, if the default restrictions use lots of # tables. # localhost:10026 inet n - n - - smtpd -o content_filter= -o myhostname=localhost.domain.tld -o local_recipient_maps= -o relay_recipient_maps= -o mynetworks=127.0.0.0/8 -o mynetworks_style=host -o smtpd_restriction_classes= -o smtpd_client_restrictions= -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject # # Do not override main.cf settings here for virtual_alias_maps or # virtual_mailbox_maps. This causes mail to be rejected with "User # unknown in virtual (alias|mailbox) recipient table". # # ------------------------------------------------------------------ # # This is the normal cleanup daemon for use after content filtering. # No header or body checks, because those have already been taken # care of by the pre-cleanup service before the content filter. # # The normal cleanup instance does all the virtual alias and canonical # address mapping that was disabled in the pre-cleanup instance before # the content filter. This rewriting must be done even when you didn't # disable address rewriting in the pre-cleanup instance, in order to # correctly process bounces and locally forwarded mail. # cleanup unix n - n - 0 cleanup -o header_checks= -o mime_header_checks= -o nested_header_checks= -o body_checks= # # ------------------------------------------------------------------ # # The normal "smtp" delivery agent for contrast with "scan". # smtp unix - - n - - smtp The above example causes Postfix to add one content filtering record to each incoming mail message, with content scan:localhost:10025. You can use the same syntax as in the right-hand side of a Postfix transport table. The content filtering records are added by the smtpd and pickup servers. The "scan" transport is a dedicated instance of the "smtp" delivery agent for injecting messages into the SMTP content filter. Using a dedicated "smtp" transport allows one to tune it for the specific task of delivering mail to a local content filter (low latency, low concurrency, throughput dependent on predictably low latency). See the previous example for setting up the content filter with the Postfix spawn service; you can of course use any server that can be run stand-alone outside the Postfix environment. Filtering mail from outside users only ====================================== The easiest approach is to configure ONE Postfix instance with TWO SMTP server addresses in master.cf: - One SMTP server address for inside users only that never invokes content filtering. - One SMTP server address for outside users that always invokes content filtering. /etc/postfix.master.cf: # SMTP service for internal users only, no content filtering. 1.2.3.4:smtp inet n - n - - smtpd -o smtpd_client_restrictions=permit_mynetworks,reject 127.0.0.1:smtp inet n - n - - smtpd -o smtpd_client_restrictions=permit_mynetworks,reject # SMTP service for external users, with content filtering. 1.2.3.5:smtp inet n - n - - smtpd -o content_filter=foo:bar Getting really nasty ==================== The above filtering configurations are static. Mail that follows a given path is either always filtered or it is never filtered. As of Postfix 2.0 you can also turn on content filtering on the fly. The Postfix UCE features allow you to specify a filtering action on the fly: FILTER foo:bar You can do this in smtpd access maps as well as the cleanup server's header/body_checks. This feature must be used with great care: you must disable all the UCE features in the after-filter smtpd and cleanup daemons or else you will have a content filtering loop. Limitations: - There can be only one content filter action per message. - FILTER actions from smtpd access maps and header/body_checks take precedence over filters specified with the main.cf content_filter parameter. - Only the last FILTER action from smtpd access maps or from header/body_checks takes effect. - The same content filter is applied to all the recipients of a given message. postfixadmin-2.3.7/VIRTUAL_VACATION/index.php0000664000175000017620000000053610715711016020514 0ustar davidpalepurple // Copyright (c) 2002 - 2005 High5! // Licensed under GPL for more info check GPL-LICENSE.TXT // // File: index.php // // Template File: -none- // // Template Variables: // // -none- // // Form POST \ GET Variables: // // -none- // header ("Location: ../login.php"); exit; ?> postfixadmin-2.3.7/VIRTUAL_VACATION/vacation.pl0000664000175000017620000005766612257624172021066 0ustar davidpalepurple#!/usr/bin/perl -w # # Virtual Vacation 4.0 # $Revision: 1616 $ # Originally by Mischa Peters # # Copyright (c) 2002 - 2005 High5! # Licensed under GPL for more info check GPL-LICENSE.TXT # # Additions: # 2004/07/13 David Osborn # strict, processes domain level aliases, more # subroutines, send reply from original to address # # 2004/11/09 David Osborn # Added syslog support # Slightly better logging which includes messageid # Avoid infinite loops with domain aliases # # 2005-01-19 Troels Arvin # PostgreSQL-version. # Normalized DB schema from one vacation table ("vacation") # to two ("vacation", "vacation_notification"). Uses # referential integrity CASCADE action to simplify cleanup # when a user is no longer on vacation. # Inserting variables into queries stricly by prepare() # to try to avoid SQL injection. # International characters are now handled well. # # 2005-01-21 Troels Arvin # Uses the Email::Valid package to avoid sending notices # to obviously invalid addresses. # # 2007-08-15 David Goodwin # Use the Perl Mail::Sendmail module for sending mail # Check for headers that start with blank lines (patch from forum) # # 2007-08-20 Martin Ambroz # Added initial Unicode support # # 2008-05-09 Fabio Bonelli # Properly handle failed queries to vacation_notification. # Fixed log reporting. # # 2008-07-29 Patch from Luxten to add repeat notification after timeout. See: # https://sourceforge.net/tracker/index.php?func=detail&aid=2031631&group_id=191583&atid=937966 # # 2008-08-01 Luigi Iotti # Use envelope sender/recipient instead of using # From: and To: header fields; # Support to good vacation behavior as in # http://www.irbs.net/internet/postfix/0707/0954.html # (needs to be tested); # # 2008-08-04 David Goodwin # Use Log4Perl # Added better testing (and -t option) # # 2009-06-29 Stevan Bajic # Add Mail::Sender for SMTP auth + more flexibility # # 2009-07-07 Stevan Bajic # Add better alias lookups # Check for more heades from Anti-Virus/Anti-Spam solutions # # Requirements - the following perl modules are required: # DBD::Pg or DBD::mysql # Mail::Sender, Email::Valid MIME::Charset, Log::Log4perl, Log::Dispatch, MIME::EncWords and GetOpt::Std # # You may install these via CPAN, or through your package tool. # CPAN: 'perl -MCPAN -e shell', then 'install Module::Whatever' # # On Debian based systems : # libmail-sender-perl # libdbd-pg-perl # libemail-valid-perl # libmime-perl # liblog-log4perl-perl # liblog-dispatch-perl # libgetopt-argvfile-perl # libmime-charset-perl (currently in testing, see instructions below) # libmime-encwords-perl (currently in testing, see instructions below) # # Note: When you use this module, you may start seeing error messages # like "Cannot insert a duplicate key into unique index # vacation_notification_pkey" in your system logs. This is expected # behavior, and not an indication of trouble (see the "already_notified" # subroutine for an explanation). # # You must also have the Email::Valid and MIME-tools perl-packages # installed. They are available in some package collections, under the # names 'perl-Email-Valid' and 'perl-MIME-tools', respectively. # One such package collection (for Linux) is: # http://dag.wieers.com/home-made/apt/packages.php # use DBI; use MIME::Base64; use MIME::EncWords qw(:all); use Email::Valid; use strict; use Mail::Sender; use Getopt::Std; use Log::Log4perl qw(get_logger :levels); use File::Basename; # ========== begin configuration ========== # IMPORTANT: If you put passwords into this script, then remember # to restrict access to the script, so that only the vacation user # can read it. # db_type - uncomment one of these our $db_type = 'Pg'; #our $db_type = 'mysql'; # leave empty for connection via UNIX socket our $db_host = ''; # connection details our $db_username = 'user'; our $db_password = 'password'; our $db_name = 'postfix'; our $vacation_domain = 'autoreply.example.org'; # smtp server used to send vacation e-mails our $smtp_server = 'localhost'; our $smtp_server_port = 25; # SMTP authentication protocol used for sending. # Can be 'PLAIN', 'LOGIN', 'CRAM-MD5' or 'NTLM' # see "perldoc Mail::Sender" (search for "auth") for more options and details # Leave it blank if you don't use authentification our $smtp_auth = undef; # username used to login to the server our $smtp_authid = 'someuser'; # password used to login to the server our $smtp_authpwd = 'somepass'; # use TLS for the SMTP connection? # while in general this would be a good idea, TLS with Mail::Sender 0.8.22 is buggy - https://rt.cpan.org/Public/Bug/Display.html?id=85438 our $smtp_tls_allowed = 0; # Set to 1 to enable logging to syslog. our $syslog = 0; # path to logfile, when empty logging is supressed # change to e.g. /dev/null if you want nothing logged. # if we can't write to this, and $log_to_file is 1 (below) the script will abort. our $logfile='/var/log/vacation.log'; # 2 = debug + info, 1 = info only, 0 = error only our $log_level = 2; # Whether to log to file or not, 0 = do not write to a log file our $log_to_file = 0; # notification interval, in seconds # set to 0 to notify only once # e.g. 1 day ... #my $interval = 60*60*24; # disabled by default our $interval = 0; # instead of changing this script, you can put your settings to /etc/mail/postfixadmin/vacation.conf # or /etc/postfixadmin/vacation.conf just use Perl syntax there to fill the variables listed above # (without the "our" keyword). Example: # $db_username = 'mail'; if (-f "/etc/mail/postfixadmin/vacation.conf") { require "/etc/mail/postfixadmin/vacation.conf"; } elsif (-f "/etc/postfixadmin/vacation.conf") { require "/etc/postfixadmin/vacation.conf"; } # =========== end configuration =========== if($log_to_file == 1) { if (( ! -w $logfile ) && (! -w dirname($logfile))) { # Cannot log; no where to write to. die("Cannot create logfile : $logfile"); } } my ($from, $to, $cc, $replyto , $subject, $messageid, $lastheader, $smtp_sender, $smtp_recipient, %opts, $spam, $test_mode, $logger); $subject=''; $messageid='unknown'; # Setup a logger... # getopts('f:t:', \%opts) or die "Usage: $0 [-t yes] -f sender -- recipient\n\t-t for testing only\n"; $opts{f} and $smtp_sender = $opts{f} or die "-f sender not present on command line"; $test_mode = 0; $opts{t} and $test_mode = 1; $smtp_recipient = shift or die "recipient not given on command line"; my $log_layout = Log::Log4perl::Layout::PatternLayout->new("%d %p> %F:%L %M - %m%n"); if($test_mode == 1) { $logger = get_logger(); # log to stdout my $appender = Log::Log4perl::Appender->new('Log::Dispatch::Screen'); $appender->layout($log_layout); $logger->add_appender($appender); $logger->debug("Test mode enabled"); } else { $logger = get_logger(); if($log_to_file == 1) { # log to file my $appender = Log::Log4perl::Appender->new( 'Log::Dispatch::File', filename => $logfile, mode => 'append'); $appender->layout($log_layout); $logger->add_appender($appender); } if($syslog == 1) { my $syslog_appender = Log::Log4perl::Appender->new( 'Log::Dispatch::Syslog', facility => 'mail', ); $logger->add_appender($syslog_appender); } } # change to $DEBUG, $INFO or $ERROR depending on how much logging you want. $logger->level($ERROR); if($log_level == 1) { $logger->level($INFO); } if($log_level == 2) { $logger->level($DEBUG); } binmode (STDIN,':utf8'); my $dbh; if ($db_host) { $dbh = DBI->connect("DBI:$db_type:dbname=$db_name;host=$db_host","$db_username", "$db_password", { RaiseError => 1 }); } else { $dbh = DBI->connect("DBI:$db_type:dbname=$db_name","$db_username", "$db_password", { RaiseError => 1 }); } if (!$dbh) { $logger->error("Could not connect to database"); # eval { } etc better here? exit(0); } my $db_true; # MySQL and PgSQL use different values for TRUE, and unicode support... if ($db_type eq "mysql") { $dbh->do("SET CHARACTER SET utf8;"); $db_true = '1'; } else { # Pg $dbh->do("SET CLIENT_ENCODING TO 'UTF8'"); $db_true = 'True'; } # used to detect infinite address lookup loops my $loopcount=0; sub already_notified { my ($to, $from) = @_; my $logger = get_logger(); my $query = qq{INSERT into vacation_notification (on_vacation,notified) values (?,?)}; my $stm = $dbh->prepare($query); if (!$stm) { $logger->error("Could not prepare query '$query' to: $to, from:$from"); return 1; } $stm->{'PrintError'} = 0; $stm->{'RaiseError'} = 0; if (!$stm->execute($to,$from)) { my $e=$dbh->errstr; # Violation of a primay key constraint may happen here, and that's # fine. All other error conditions are not fine, however. if ($e !~ /(?:_pkey|^Duplicate entry)/) { $logger->error("Failed to insert into vacation_notification table (to:$to from:$from error:'$e' query:'$query')"); # Let's play safe and notify anyway return 1; } if ($interval) { $query = qq{SELECT NOW()-notified_at FROM vacation_notification WHERE on_vacation=? AND notified=?}; $stm = $dbh->prepare($query) or panic_prepare($query); $stm->execute($to,$from) or panic_execute($query,"on_vacation='$to', notified='$from'"); my @row = $stm->fetchrow_array; my $int = $row[0]; if ($int > $interval) { $logger->info("[Interval elapsed, sending the message]: From: $from To:$to"); $query = qq{UPDATE vacation_notification SET notified_at=NOW() WHERE on_vacation=? AND notified=?}; $stm = $dbh->prepare($query); if (!$stm) { $logger->error("Could not prepare query '$query' (to: '$to', from: '$from')"); return 0; } if (!$stm->execute($to,$from)) { $e=$dbh->errstr; $logger->error("Error from running query '$query' (to: '$to', from: '$from', error: '$e')"); } return 0; } else { $logger->debug("Notification interval not elapsed; not sending vacation reply (to: '$to', from: '$from')"); return 1; } } else { return 1; } } return 0; } # try and determine if email address has vacation turned on; we # have to do alias searching, and domain aliasing resolution for this. # If found, return ($num_matches, $real_email); sub find_real_address { my ($email) = @_; my $logger = get_logger(); if (++$loopcount > 20) { $logger->error("find_real_address loop! (more than 20 attempts!) currently: $email"); exit(1); } my $realemail = ''; my $query = qq{SELECT email FROM vacation WHERE email=? AND active=$db_true}; my $stm = $dbh->prepare($query) or panic_prepare($query); $stm->execute($email) or panic_execute($query,"email='$email'"); my $rv = $stm->rows; # Recipient has vacation if ($rv == 1) { $realemail = $email; $logger->debug("Found '$email' has vacation active"); } else { my $vemail = $email; $vemail =~ s/\@/#/g; $vemail = $vemail . "\@" . $vacation_domain; $logger->debug("Looking for alias records that '$email' resolves to with vacation turned on"); $query = qq{SELECT goto FROM alias WHERE address=? AND (goto LIKE ? OR goto LIKE ? OR goto LIKE ? OR goto = ?)}; $stm = $dbh->prepare($query) or panic_prepare($query); $stm->execute($email,"$vemail,%","%,$vemail","%,$vemail,%", "$vemail") or panic_execute($query,"address='$email'"); $rv = $stm->rows; # Recipient is an alias, check if mailbox has vacation if ($rv == 1) { my @row = $stm->fetchrow_array; my $alias = $row[0]; if ($alias =~ /,/) { for (split(/\s*,\s*/, lc($alias))) { my $singlealias = $_; $logger->debug("Found alias \'$singlealias\' for email \'$email\'. Looking if vacation is on for alias."); $query = qq{SELECT email FROM vacation WHERE email=? AND active=$db_true}; $stm = $dbh->prepare($query) or panic_prepare($query); $stm->execute($singlealias) or panic_execute($query,"email='$singlealias'"); $rv = $stm->rows; # Alias has vacation if ($rv == 1) { $realemail = $singlealias; last; } } } else { $query = qq{SELECT email FROM vacation WHERE email=? AND active=$db_true}; $stm = $dbh->prepare($query) or panic_prepare($query); $stm->execute($alias) or panic_prepare($query,"email='$alias'"); $rv = $stm->rows; # Alias has vacation if ($rv == 1) { $realemail = $alias; } } # We have to look for alias domain (domain1 -> domain2) } else { my ($user, $domain) = split(/@/, $email); $logger->debug("Looking for alias domain for $domain / $email / $user"); $query = qq{SELECT target_domain FROM alias_domain WHERE alias_domain=?}; $stm = $dbh->prepare($query) or panic_prepare($query); $stm->execute($domain) or panic_execute($query,"alias_domain='$domain'"); $rv = $stm->rows; # The domain has a alias domain level alias if ($rv == 1) { my @row = $stm->fetchrow_array; my $alias_domain_dest = $row[0]; ($rv, $realemail) = find_real_address ("$user\@$alias_domain_dest"); # We still have to look for domain level aliases... } else { my ($user, $domain) = split(/@/, $email); $logger->debug("Looking for domain level aliases for $domain / $email / $user"); $query = qq{SELECT goto FROM alias WHERE address=?}; $stm = $dbh->prepare($query) or panic_prepare($query); $stm->execute("\@$domain") or panic_execute($query,"address='\@$domain'"); $rv = $stm->rows; # The receipient has a domain level alias if ($rv == 1) { my @row = $stm->fetchrow_array; my $wildcard_dest = $row[0]; my ($wilduser, $wilddomain) = split(/@/, $wildcard_dest); # Check domain alias if ($wilduser) { ($rv, $realemail) = find_real_address ($wildcard_dest); } else { ($rv, $realemail) = find_real_address ("$user\@$wilddomain"); } } else { $logger->debug("No domain level alias present for $domain / $email / $user"); } } } } return ($rv, $realemail); } # sends the vacation mail to the original sender. # sub send_vacation_email { my ($email, $orig_from, $orig_to, $orig_messageid, $test_mode) = @_; my $logger = get_logger(); $logger->debug("Asked to send vacation reply to $email thanks to $orig_messageid"); my $query = qq{SELECT subject,body FROM vacation WHERE email=?}; my $stm = $dbh->prepare($query) or panic_prepare($query); $stm->execute($email) or panic_execute($query,"email='$email'"); my $rv = $stm->rows; if ($rv == 1) { my @row = $stm->fetchrow_array; if (already_notified($email, $orig_from) == 1) { $logger->debug("Already notified $email, or some error prevented us from doing so"); return; } $logger->debug("Will send vacation response for $orig_messageid: FROM: $email (orig_to: $orig_to), TO: $orig_from; VACATION SUBJECT: $row[0] ; VACATION BODY: $row[1]"); my $subject = $row[0]; my $body = $row[1]; my $from = $email; my $to = $orig_from; my %smtp_connection; %smtp_connection = ( 'smtp' => $smtp_server, 'port' => $smtp_server_port, 'auth' => $smtp_auth, 'authid' => $smtp_authid, 'authpwd' => $smtp_authpwd, 'tls_allowed' => $smtp_tls_allowed, 'skip_bad_recipients' => 'true', 'encoding' => 'Base64', 'ctype' => 'text/plain; charset=UTF-8', 'headers' => 'Precedence: junk', 'headers' => 'X-Loop: Postfix Admin Virtual Vacation', ); my %mail; %mail = ( 'subject' => encode_mimewords($subject, 'Charset', 'UTF-8'), 'from' => $from, 'to' => $to, 'msg' => encode_base64($body) ); if($test_mode == 1) { $logger->info("** TEST MODE ** : Vacation response sent to $to from $from subject $subject (not) sent\n"); $logger->info(%mail); return 0; } $Mail::Sender::NO_X_MAILER = 1; my $sender = new Mail::Sender({%smtp_connection}); $sender->Open({%mail}); $sender->SendLineEnc($body); $sender->Close() or $logger->error("Failed to send vacation response: " . $sender->{'error_msg'}); $logger->debug("Vacation response sent to $to, from $from"); } } # Convert a (list of) email address(es) from RFC 822 style addressing to # RFC 821 style addressing. e.g. convert: # "John Jones" , "Jane Doe/Sales/ACME" # to: # jjones@acme.com, jdoe@acme.com sub strip_address { my ($arg) = @_; if(!$arg) { return ''; } my @ok; $logger = get_logger(); my @list; @list = $arg =~ m/([\w\.\-\+\'\=_\^\|\$\/\{\}~\?\*\\&\!`\%]+\@[\w\.\-]+\w+)/g; foreach(@list) { #$logger->debug("Checking: $_"); my $temp = Email::Valid->address( -address => $_, -mxcheck => 0); if($temp) { push(@ok, $temp); } else { $logger->debug("Email not valid : $Email::Valid::Details"); } } # remove duplicates my %seen = (); my @uniq; my $item; foreach $item (@ok) { push(@uniq, $item) unless $seen{$item}++ } my $result = lc(join(", ", @uniq)); #$logger->debug("Result: $result"); return $result; } sub panic_prepare { my ($arg) = @_; my $logger = get_logger(); $logger->error("Could not prepare sql statement: '$arg'"); exit(0); } sub panic_execute { my ($arg,$param) = @_; my $logger = get_logger(); $logger->error("Could not execute sql statement - '$arg' with parameters '$param'"); exit(0); } # Make sure the email wasn't sent by someone who could be a mailing list etc; if it was, # then we abort after appropriate logging. sub check_and_clean_from_address { my ($address) = @_; my $logger = get_logger(); if($address =~ /^(noreply|postmaster|mailer\-daemon|listserv|majordomo|owner\-|request\-|bounces\-)/i || $address =~ /\-(owner|request|bounces)\@/i ) { $logger->debug("sender $address contains $1 - will not send vacation message"); exit(0); } $address = strip_address($address); if($address eq "") { $logger->error("Address $address is not valid; exiting"); exit(0); } #$logger->debug("Address cleaned up to $address"); return $address; } ########################### main ################################# # Take headers apart $cc = ''; $replyto = ''; $logger->debug("Script argument SMTP recipient is : '$smtp_recipient' and smtp_sender : '$smtp_sender'"); while () { last if (/^$/); if (/^\s+(.*)/ and $lastheader) { $$lastheader .= " $1"; next; } elsif (/^from:\s*(.*)\n$/i) { $from = $1; $lastheader = \$from; } elsif (/^to:\s*(.*)\n$/i) { $to = $1; $lastheader = \$to; } elsif (/^cc:\s*(.*)\n$/i) { $cc = $1; $lastheader = \$cc; } elsif (/^Reply\-to:\s*(.*)\s*\n$/i) { $replyto = $1; $lastheader = \$replyto; } elsif (/^subject:\s*(.*)\n$/i) { $subject = $1; $lastheader = \$subject; } elsif (/^message\-id:\s*(.*)\s*\n$/i) { $messageid = $1; $lastheader = \$messageid; } elsif (/^x\-spam\-(flag|status):\s+yes/i) { $logger->debug("x-spam-$1: yes found; exiting"); exit (0); } elsif (/^x\-facebook\-notify:/i) { $logger->debug('Mail from facebook, ignoring'); exit(0); } elsif (/^precedence:\s+(bulk|list|junk)/i) { $logger->debug("precedence: $1 found; exiting"); exit (0); } elsif (/^x\-loop:\s+postfix\ admin\ virtual\ vacation/i) { $logger->debug("x-loop: postfix admin virtual vacation found; exiting"); exit (0); } elsif (/^Auto\-Submitted:\s*no/i) { next; } elsif (/^Auto\-Submitted:/i) { $logger->debug("Auto-Submitted: something found; exiting"); exit (0); } elsif (/^List\-(Id|Post):/i) { $logger->debug("List-$1: found; exiting"); exit (0); } elsif (/^(x\-(barracuda\-)?spam\-status):\s+(yes)/i) { $logger->debug("$1: $3 found; exiting"); exit (0); } elsif (/^(x\-dspam\-result):\s+(spam|bl[ao]cklisted)/i) { $logger->debug("$1: $2 found; exiting"); exit (0); } elsif (/^(x\-(anti|avas\-)?virus\-status):\s+(infected)/i) { $logger->debug("$1: $3 found; exiting"); exit (0); } elsif (/^(x\-(avas\-spam|spamtest|crm114|razor|pyzor)\-status):\s+(spam)/i) { $logger->debug("$1: $3 found; exiting"); exit (0); } elsif (/^(x\-osbf\-lua\-score):\s+[0-9\/\.\-\+]+\s+\[([-S])\]/i) { $logger->debug("$1: $2 found; exiting"); exit (0); } else {$lastheader = "" ; } } if($smtp_recipient =~ /\@$vacation_domain/) { # the regexp used here could probably be improved somewhat, for now hope that people won't use # as a valid mailbox character. my $tmp = $smtp_recipient; $tmp =~ s/\@$vacation_domain//; $tmp =~ s/#/\@/; $logger->debug("Converted autoreply mailbox back to normal style - from $smtp_recipient to $tmp"); $smtp_recipient = $tmp; undef $tmp; } # If either From: or To: are not set, exit if(!$from || !$to || !$messageid || !$smtp_sender || !$smtp_recipient) { $logger->info("One of from=$from, to=$to, messageid=$messageid, smtp sender=$smtp_sender, smtp recipient=$smtp_recipient empty"); exit(0); } $logger->debug("Email headers have to: '$to' and From: '$from'"); $to = strip_address($to); $cc = strip_address($cc); $from = check_and_clean_from_address($from); if($replyto ne "") { # if reply-to is invalid, or looks like a mailing list, then we probably don't want to send a reply. $replyto = check_and_clean_from_address($replyto); } $smtp_sender = check_and_clean_from_address($smtp_sender); $smtp_recipient = check_and_clean_from_address($smtp_recipient); if ($smtp_sender eq $smtp_recipient) { $logger->debug("smtp sender $smtp_sender and recipient $smtp_recipient are the same; aborting"); exit(0); } for (split(/,\s*/, lc($to)), split(/,\s*/, lc($cc))) { my $header_recipient = strip_address($_); if ($smtp_sender eq $header_recipient) { $logger->debug("sender header $smtp_sender contains recipient $header_recipient (mailing myself?)"); exit(0); } } my ($rv, $email) = find_real_address($smtp_recipient); if ($rv == 1) { $logger->debug("Attempting to send vacation response for: $messageid to: $smtp_sender, $smtp_recipient, $email (test_mode = $test_mode)"); send_vacation_email($email, $smtp_sender, $smtp_recipient, $messageid, $test_mode); } else { $logger->debug("SMTP recipient $smtp_recipient which resolves to $email does not have an active vacation (rv: $rv, email: $email)"); } 0; #/* vim: set expandtab softtabstop=3 tabstop=3 shiftwidth=3: */ postfixadmin-2.3.7/debian/0000775000175000017620000000000012301477467015514 5ustar davidpalepurplepostfixadmin-2.3.7/debian/apache.conf0000664000175000017620000000013611415441633017573 0ustar davidpalepurple# BEGIN FOR POSTFIXADMIN Alias /postfixadmin /usr/share/postfixadmin # END FOR POSTFIXADMIN postfixadmin-2.3.7/debian/postfixadmin.config0000664000175000017620000000050011201377624021373 0ustar davidpalepurple#!/bin/sh set -e . /usr/share/debconf/confmodule db_version 2.0 db_input high postfixadmin/reconfigure-webserver || true db_go || true if [ -f /usr/share/dbconfig-common/dpkg/config ]; then # we support mysql and pgsql dbc_dbtypes="mysql, pgsql" . /usr/share/dbconfig-common/dpkg/config dbc_go postfixadmin $@ fi postfixadmin-2.3.7/debian/TODO0000664000175000017620000000026711201377624016201 0ustar davidpalepurple * Do all necessary things automatically (maybe with dbconfig?) (database, setp password...) * DebTags * dbconfig: DOCUMENTS/SECURITY.txt * include postfix configuration templates postfixadmin-2.3.7/debian/compat0000664000175000017620000000000211161213262016672 0ustar davidpalepurple7 postfixadmin-2.3.7/debian/patches/0000775000175000017620000000000012301477467017143 5ustar davidpalepurplepostfixadmin-2.3.7/debian/patches/db_credentials0000664000175000017620000000440211704536777022036 0ustar davidpalepurpleDescription: This patch sets the dbconfig placeholders in config.inc.php. Forwarded: not-needed Author: Norman Messtorff Last-Update: 2011-12-18 Index: postfixadmin-2.3/config.inc.php =================================================================== --- postfixadmin-2.3.orig/config.inc.php 2012-01-14 12:42:16.000000000 +0100 +++ postfixadmin-2.3/config.inc.php 2012-01-14 12:56:28.000000000 +0100 @@ -16,6 +16,11 @@ * Contains configuration options. */ +// This loads the automatic generated DB credentials from /etc/postfixadmin/dbconfig.inc.php +require_once('dbconfig.inc.php'); +if (!isset($dbserver) || empty($dbserver)) + $dbserver='localhost'; + /***************************************************************** * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * You have to set $CONF['configured'] = true; before the @@ -23,7 +28,7 @@ * Doing this implies you have changed this file as required. * i.e. configuring database etc; specifying setup.php password etc. */ -$CONF['configured'] = false; +$CONF['configured'] = true; // In order to setup Postfixadmin, you MUST specify a hashed password here. // To create the hash, visit setup.php in a browser and type a password into the field, @@ -33,7 +38,7 @@ // Postfix Admin Path // Set the location of your Postfix Admin installation here. // YOU MUST ENTER THE COMPLETE URL e.g. http://domain.tld/postfixadmin -$CONF['postfix_admin_url'] = ''; +$CONF['postfix_admin_url'] = '/postfixadmin'; // shouldn't need changing. $CONF['postfix_admin_path'] = dirname(__FILE__); @@ -46,11 +51,11 @@ // mysql = MySQL 3.23 and 4.0, 4.1 or 5 // mysqli = MySQL 4.1+ // pgsql = PostgreSQL -$CONF['database_type'] = 'mysql'; -$CONF['database_host'] = 'localhost'; -$CONF['database_user'] = 'postfix'; -$CONF['database_password'] = 'postfixadmin'; -$CONF['database_name'] = 'postfix'; +$CONF['database_type'] = $dbtype; +$CONF['database_host'] = $dbserver; +$CONF['database_user'] = $dbuser; +$CONF['database_password'] = $dbpass; +$CONF['database_name'] = $dbname; // If you need to specify a different port for a MYSQL database connection, use e.g. // $CONF['database_host'] = '172.30.33.66:3308'; // If you need to specify a different port for POSTGRESQL database connection postfixadmin-2.3.7/debian/patches/series0000664000175000017620000000001711704536777020364 0ustar davidpalepurpledb_credentials postfixadmin-2.3.7/debian/postfixadmin.prerm0000664000175000017620000000103411212035612021244 0ustar davidpalepurple#!/bin/sh set -e . /usr/share/debconf/confmodule if [ -f /usr/share/dbconfig-common/dpkg/prerm ]; then . /usr/share/dbconfig-common/dpkg/prerm dbc_go postfixadmin $@ fi if [ -f /usr/share/debconf/confmodule ]; then . /usr/share/debconf/confmodule db_version 2.0 db_get postfixadmin/reconfigure-webserver servers="$RET" linkname="postfixadmin" if [ -e /usr/share/wwwconfig-common/confd-link.sh ]; then . /usr/share/wwwconfig-common/confd-link.sh else . /usr/share/postfixadmin/confd-link.sh fi fi #DEBHELPER# postfixadmin-2.3.7/debian/changelog0000664000175000017620000000111312301472405017345 0ustar davidpalepurplepostfixadmin (2.3.7-1) unstable; urgency=low * New upstream release (v2.3.7) -- David Goodwin (PalePurple) Thu, 20 Feb 2014 22:30:00 +0100 postfixadmin (2.3.6-1) unstable; urgency=low * New upstream release (v2.3.6) -- David Goodwin (PalePurple) Wed, 2 Jan 2013 21:20:00 +0100 postfixadmin (2.3.5-1) unstable; urgency=low * Initial Debian release (Closes: #247225) * Changed from normes to me, for signing/building purposes. -- David Goodwin (PalePurple) Sun, 15 Jan 2012 12:27:28 +0100 postfixadmin-2.3.7/debian/postfixadmin.install0000664000175000017620000000047711415441633021610 0ustar davidpalepurple*.php usr/share/postfixadmin admin usr/share/postfixadmin css usr/share/postfixadmin images usr/share/postfixadmin languages usr/share/postfixadmin model usr/share/postfixadmin templates usr/share/postfixadmin users usr/share/postfixadmin debian/apache.conf etc/postfixadmin debian/lighttpd.conf etc/postfixadmin postfixadmin-2.3.7/debian/po/0000775000175000017620000000000012301477467016132 5ustar davidpalepurplepostfixadmin-2.3.7/debian/po/POTFILES.in0000664000175000017620000000004411201377624017675 0ustar davidpalepurple[type: gettext/rfc822deb] templates postfixadmin-2.3.7/debian/po/templates.pot0000664000175000017620000000157011201377624020647 0ustar davidpalepurple# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: postfixadmin@packages.debian.org\n" "POT-Creation-Date: 2008-10-27 22:14+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #. Type: multiselect #. Description #: ../templates:1001 msgid "Web server to reconfigure automatically:" msgstr "" #. Type: multiselect #. Description #: ../templates:1001 msgid "" "Please choose the web server that should be automatically configured to run " "postfixadmin." msgstr "" postfixadmin-2.3.7/debian/templates0000664000175000017620000000041611201377624017426 0ustar davidpalepurpleTemplate: postfixadmin/reconfigure-webserver Type: multiselect Choices: apache2, apache, apache-ssl, apache-perl, lighttpd _Description: Web server to reconfigure automatically: Please choose the web server that should be automatically configured to run postfixadmin. postfixadmin-2.3.7/debian/confd-link.sh0000775000175000017620000000416411212035612020062 0ustar davidpalepurple#!/bin/sh # File: confd-link.sh # Changes: # 20081109 Norman Messtorff # Initial version. # # Needs: $servers - the servers to link configurations in. # $linkname - specify the link name # $linkdestination_apache - specify the link destination (Apache config) # $linkdestination_lighttpd - specify the link destination (lighttpd config) # Description: Linking configurations into Webservers conf.d # Sets: $status = {error, nothing, linked, removed} # $error = error message (if $status = error) status="nothing" error="" # # Checking needed settings... # if [ -z "$servers" ]; then status="error" error="No servers specified in confd-link.sh" elif [ -z "$linkname" ]; then status="error" error="No linkname specified in confd-link.sh" else # # The link removal part... # if [ "$1" = "remove" ] || [ "$1" = "purge" ]; then for A in $servers ; do A=${A%,} # # lighttpd has no conf.d # if [ "$A" = "lighttpd" ]; then linkpath="/etc/lighttpd/conf-available" else linkpath="/etc/$A/conf.d" fi # # Is it existing and a symbolic link or are we going to do some unwished things? # if [ -L $linkpath/$linkname ]; then if rm -f $linkpath/$linkname 2>&1 ; then status="removed" else status="error" error="ERROR! Couln't remove $linkpath/$linkname " fi else status="error" error="ERROR! $linkpath/$linkname is no symbolic link or doesn't exists." fi done else for A in $servers ; do A=${A%,} # # lighttpd has no conf.d # if [ "$A" = "lighttpd" ]; then linkpath="/etc/lighttpd/conf-available" linkdestination=$linkdestination_lighttpd else linkpath="/etc/$A/conf.d" linkdestination=$linkdestination_apache fi if [ -d $linkpath ]; then if ln -s $linkdestination $linkpath/$linkname >/dev/null 2>&1 ; then status="linked" else status="error" error="ERROR! 'ln -s' returned an error. Could not create link in $linkpath" fi else status="error" error="ERROR! $linkpath doesn't exists. Could not create link in $linkpath" fi done fi fi postfixadmin-2.3.7/debian/copyright0000664000175000017620000000241511201377624017441 0ustar davidpalepurpleThis package was debianized by David Goodwin on Sun, 04 Nov 2007 15:21:00 +0000. It was downloaded from subversion, via http://postfixadmin.sf.net Upstream Authors: The PostfixAdmin Development Team Copyright: Copyright (C) 2007 The Postfixadmin Project Team License: This package 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 2 of the License, or (at your option) any later version. This package 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 this package; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA On Debian GNU/Linux systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/GPL-2' The Debian packaging of Postfixadmin is licensed under the same terms as Postfixadmin itself. postfixadmin-2.3.7/debian/postfixadmin.examples0000664000175000017620000000077711415441633021763 0ustar davidpalepurpleVIRTUAL_VACATION ADDITIONS/change_password.tgz ADDITIONS/import_users_from_csv.py ADDITIONS/postfixadmin-domain-postdeletion.sh ADDITIONS/cleanupdirs.pl ADDITIONS/mailbox_remover.pl ADDITIONS/postfixadmin-mailbox-postcreation.sh ADDITIONS/virtualmaildel.php ADDITIONS/convert-passwd-to-postfixadmin.pl ADDITIONS/mkeveryone.pl ADDITIONS/postfixadmin-mailbox-postdeletion.sh ADDITIONS/delete-mailq-by-domain.pl ADDITIONS/pfa_maildir_cleanup.pl ADDITIONS/quota_usage.pl ADDITIONS/fetchmail.pl ADDITIONS/README.TXT postfixadmin-2.3.7/debian/postfixadmin.postrm0000664000175000017620000000162311704536777021477 0ustar davidpalepurple#!/bin/sh set -e if [ "$1" = "remove" ] || [ "$1" = "purge" ]; then if [ -f /usr/share/debconf/confmodule ]; then . /usr/share/debconf/confmodule db_version 2.0 # restart the webserver only if we know which one was configured. if db_get postfixadmin/reconfigure-webserver; then servers="$RET" restart=$servers linkname="postfixadmin" if [ -e /usr/share/wwwconfig-common/restart.sh ]; then . /usr/share/wwwconfig-common/restart.sh fi fi if [ -f /usr/share/dbconfig-common/dpkg/postrm ]; then . /usr/share/dbconfig-common/dpkg/postrm dbc_go postfixadmin $@ fi fi if [ "$1" = "purge" ]; then rm -f /etc/postfixadmin/dbconfig.inc.php if which ucf >/dev/null 2>&1; then ucf --purge /etc/postfixadmin/dbconfig.inc.php fi db_purge || true fi fi #DEBHELPER# exit 0 postfixadmin-2.3.7/debian/README.Debian0000664000175000017620000000235111212035612017534 0ustar davidpalepurplePostfixAdmin for Debian ======================= After installing the package, you should find that : http://youserver/postfixadmin/setup.php works. This should guide you through the appropriate process. You will need to create a database (either MySQL or PostgreSQL) and know the username and password for it. The Database does not need to be on the same server as the Postfixadmin install. Recommended and Suggested Packages ================================== - Postfix - MySQL or PostgreSQL - Courier or Dovecot Where to get help ================= The first stop would be the Postfixadmin Website, Forum or IRC channel. See : - http://postfixadmin.sf.net - #postfixadmin on irc.freenode.net How to build this package for Debian/lenny ========================================== If you want to build this package for Debian/lenny, you have to execute DIST="lenny" dpkg-buildpackage -rfakeroot This will include the confd-link.sh script into the package. That script is included in wwwconfig-common >0.2, but we have an older version in lenny at the moment. We (upstream and myself) want to provide also an lenny ready package, which will be available via sf.net. Just as an easy way for interested people which are running lenny. postfixadmin-2.3.7/debian/watch0000664000175000017620000000010011704536777016542 0ustar davidpalepurpleversion=3 http://sf.net/postfixadmin/postfixadmin_(.+)\.tar\.gz postfixadmin-2.3.7/debian/postfixadmin.links0000664000175000017620000000010611201377624021250 0ustar davidpalepurpleetc/postfixadmin/config.inc.php usr/share/postfixadmin/config.inc.php postfixadmin-2.3.7/debian/source/0000775000175000017620000000000012301477467017014 5ustar davidpalepurplepostfixadmin-2.3.7/debian/source/format0000664000175000017620000000001411704536777020230 0ustar davidpalepurple3.0 (quilt) postfixadmin-2.3.7/debian/README.source0000664000175000017620000000222611415441633017664 0ustar davidpalepurpleThis package is using the quilt framework. All patches are located in debian/patches. Adding a new patch: quilt new This will create a new file debian/patches/patch/date-patch_name. Please use the current date (e.g. 20100221 - YYYYMMDD) as prefix! Editing a file to include it into the patch: quilt edit This will open your $EDITOR. To write your changes into the new patchfile: quilt refresh. quilt push: Apply patch(es) from the series file. Without options, the next patch in the series file is applied. When a number is specified, apply the specified number of patches. When a patch name is specified, apply all patches up to and including the specified patch. Patch names may include the patches/ prefix, which means that filename completion can be used. quilt pop: Remove patch(es) from the stack of applied patches. Without options, the topmost patch is removed. When a number is specified, remove the specified number of patches. When a patch name is specified, remove patches until the specified patch end up on top of the stack. Patch names may include the patches/ prefix, which means that filename completion can be used. postfixadmin-2.3.7/debian/rules0000775000175000017620000000345411710102261016556 0ustar davidpalepurple#!/usr/bin/make -f # debian/rules makefile for postfixadmin # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 export PFADIR = $(shell pwd) export VERSION = $(shell grep -E "version = '.*';" functions.inc.php |sed -e "s/.version = '//" |sed -e "s/';.*//" |sed -e "s/ /-/g") export DEBVERSION = $(shell grep -E "postfixadmin .([0-9]+|\.)+" debian/changelog |head -1 |sed -e "s/postfixadmin .//" |sed -e "s/-.*//") include /usr/share/quilt/quilt.make build: build-arch build-indep build-arch: build-stamp build-indep: build-stamp build-stamp: $(QUILT_STAMPFN) dh_testdir #dh_testroot touch build-stamp # Create a needed tar.gz file to build a non-nativ .dpkg prep: rm -f ../postfixadmin_*orig.tar.gz cd ..; tar --exclude-vcs --exclude=*.svn* --exclude=postfixadmin/debian --exclude=postfixadmin/.pc -czf postfixadmin_${DEBVERSION}.orig.tar.gz postfixadmin-${DEBVERSION} # Call this target to build a shiny new .dpkg file. build-package: dh_testdir cd ${PFADIR}; dpkg-buildpackage -rfakeroot clean: unpatch dh_testdir #dh_testroot dh_clean debconf-updatepo install: build dh_testdir dh_testroot dh_prep dh_installdirs dh_install mv debian/postfixadmin/usr/share/postfixadmin/config.inc.php debian/postfixadmin/etc/postfixadmin/config.inc.php find debian/postfixadmin -name .svn | xargs -r rm -r cp debian/confd-link.sh debian/postfixadmin/usr/share/postfixadmin/ # Build architecture-independent files here. binary-indep: build install dh_testdir dh_testroot dh_installchangelogs dh_installdebconf dh_installdocs -X.svn dh_installexamples -X.svn dh_link dh_compress dh_fixperms dh_installdeb dh_gencontrol dh_md5sums dh_builddeb # Build architecture-dependent files here. binary-arch: binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install postfixadmin-2.3.7/debian/postfixadmin.dirs0000664000175000017620000000016111161213262021062 0ustar davidpalepurpleusr/share/postfixadmin usr/share/postfixadmin/css usr/share/doc/postfixadmin etc/postfixadmin etc/apache2/conf.d postfixadmin-2.3.7/debian/postfixadmin.postinst0000664000175000017620000000142411704536777022035 0ustar davidpalepurple#!/bin/bash set -e if [ "$1" = "configure" ]; then # configure DB stuff via dbconfig-common dbc_generate_include=php:/etc/postfixadmin/dbconfig.inc.php dbc_generate_include_args="-O root:www-data -m 640 -U" . /usr/share/debconf/confmodule . /usr/share/dbconfig-common/dpkg/postinst dbc_go postfixadmin $@ # configure webserver stuff db_get postfixadmin/reconfigure-webserver servers="$RET" restart="$servers" linkdestination_apache="../../postfixadmin/apache.conf" linkdestination_lighttpd="../../postfixadmin/lighttpd.conf" linkname="postfixadmin" if [ -e /usr/share/wwwconfig-common/confd-link.sh ]; then . /usr/share/wwwconfig-common/confd-link.sh else . /usr/share/postfixadmin/confd-link.sh fi . /usr/share/wwwconfig-common/restart.sh fi #DEBHELPER# exit 0 postfixadmin-2.3.7/debian/control0000664000175000017620000000226511704536777017132 0ustar davidpalepurpleSource: postfixadmin Section: admin Priority: optional Maintainer: Norman Messtorff Build-Depends: debhelper (>= 7), po-debconf, quilt (>= 0.46) Standards-Version: 3.9.2 Homepage: http://postfixadmin.sourceforge.net Package: postfixadmin Architecture: all Depends: debconf (>= 0.5), dbconfig-common, wwwconfig-common, apache2 | lighttpd | httpd, libapache2-mod-php5 | php5-cgi | php5, php5-imap, php5-mysql | php5-pgsql, mysql-client | postgresql-client, ${misc:Depends} Recommends: postfix-mysql | postfix-pgsql, mysql-server | postgresql-server | postgresql Suggests: squirrelmail-postfixadmin, dovecot-common | courier-authlib-mysql | courier-authlib-postgresql Description: Virtual mail hosting interface for Postfix Postfixadmin is a web interface to managing virtual users and domains for a Postfix mail transport agent. The web interface is written in PHP. It supports Virtual mailboxes, aliases, forwarders and vacation. . Allows administrators to delegate the handling of domains to the domain administrators. Allows users to login and change their own settings (e.g. forwarders, vacation, passwords etc). . Provides easy integration into dovecot, courier or cyrus. postfixadmin-2.3.7/debian/lighttpd.conf0000664000175000017620000000013211201377624020166 0ustar davidpalepurple# Alias for Postfixadmin alias.url += ( "/postfixadmin" => "/usr/share/postfixadmin", ) postfixadmin-2.3.7/debian/postfixadmin.docs0000775000175000017620000000001311704536777021076 0ustar davidpalepurpleDOCUMENTS postfixadmin-2.3.7/edit-domain.php0000664000175000017620000000674011151617107017171 0ustar davidpalepurple