summaryrefslogtreecommitdiff
path: root/program/lib/Net
diff options
context:
space:
mode:
Diffstat (limited to 'program/lib/Net')
-rw-r--r--program/lib/Net/IDNA2.php3402
-rw-r--r--program/lib/Net/IDNA2/Exception.php4
-rw-r--r--program/lib/Net/IDNA2/Exception/Nameprep.php6
-rw-r--r--program/lib/Net/LDAP3.php2618
-rw-r--r--program/lib/Net/LDAP3/Result.php152
-rw-r--r--program/lib/Net/SMTP.php1338
-rw-r--r--program/lib/Net/Sieve.php1274
-rw-r--r--program/lib/Net/Socket.php686
8 files changed, 0 insertions, 9480 deletions
diff --git a/program/lib/Net/IDNA2.php b/program/lib/Net/IDNA2.php
deleted file mode 100644
index 8c366fb8a..000000000
--- a/program/lib/Net/IDNA2.php
+++ /dev/null
@@ -1,3402 +0,0 @@
-<?php
-
-// {{{ license
-
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
-//
-// +----------------------------------------------------------------------+
-// | 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
-// | USA. |
-// +----------------------------------------------------------------------+
-//
-
-// }}}
-require_once 'Net/IDNA2/Exception.php';
-require_once 'Net/IDNA2/Exception/Nameprep.php';
-
-/**
- * Encode/decode Internationalized Domain Names.
- *
- * The class allows to convert internationalized domain names
- * (see RFC 3490 for details) as they can be used with various registries worldwide
- * to be translated between their original (localized) form and their encoded form
- * as it will be used in the DNS (Domain Name System).
- *
- * The class provides two public methods, encode() and decode(), which do exactly
- * what you would expect them to do. You are allowed to use complete domain names,
- * simple strings and complete email addresses as well. That means, that you might
- * use any of the following notations:
- *
- * - www.n�rgler.com
- * - xn--nrgler-wxa
- * - xn--brse-5qa.xn--knrz-1ra.info
- *
- * Unicode input might be given as either UTF-8 string, UCS-4 string or UCS-4
- * array. Unicode output is available in the same formats.
- * You can select your preferred format via {@link set_paramter()}.
- *
- * ACE input and output is always expected to be ASCII.
- *
- * @package Net
- * @author Markus Nix <mnix@docuverse.de>
- * @author Matthias Sommerfeld <mso@phlylabs.de>
- * @author Stefan Neufeind <pear.neufeind@speedpartner.de>
- * @version $Id: IDNA2.php 305344 2010-11-14 23:52:42Z neufeind $
- */
-class Net_IDNA2
-{
- // {{{ npdata
- /**
- * These Unicode codepoints are
- * mapped to nothing, See RFC3454 for details
- *
- * @static
- * @var array
- * @access private
- */
- private static $_np_map_nothing = array(
- 0xAD,
- 0x34F,
- 0x1806,
- 0x180B,
- 0x180C,
- 0x180D,
- 0x200B,
- 0x200C,
- 0x200D,
- 0x2060,
- 0xFE00,
- 0xFE01,
- 0xFE02,
- 0xFE03,
- 0xFE04,
- 0xFE05,
- 0xFE06,
- 0xFE07,
- 0xFE08,
- 0xFE09,
- 0xFE0A,
- 0xFE0B,
- 0xFE0C,
- 0xFE0D,
- 0xFE0E,
- 0xFE0F,
- 0xFEFF
- );
-
- /**
- * Prohibited codepints
- *
- * @static
- * @var array
- * @access private
- */
- private static $_general_prohibited = array(
- 0,
- 1,
- 2,
- 3,
- 4,
- 5,
- 6,
- 7,
- 8,
- 9,
- 0xA,
- 0xB,
- 0xC,
- 0xD,
- 0xE,
- 0xF,
- 0x10,
- 0x11,
- 0x12,
- 0x13,
- 0x14,
- 0x15,
- 0x16,
- 0x17,
- 0x18,
- 0x19,
- 0x1A,
- 0x1B,
- 0x1C,
- 0x1D,
- 0x1E,
- 0x1F,
- 0x20,
- 0x21,
- 0x22,
- 0x23,
- 0x24,
- 0x25,
- 0x26,
- 0x27,
- 0x28,
- 0x29,
- 0x2A,
- 0x2B,
- 0x2C,
- 0x2F,
- 0x3B,
- 0x3C,
- 0x3D,
- 0x3E,
- 0x3F,
- 0x40,
- 0x5B,
- 0x5C,
- 0x5D,
- 0x5E,
- 0x5F,
- 0x60,
- 0x7B,
- 0x7C,
- 0x7D,
- 0x7E,
- 0x7F,
- 0x3002
- );
-
- /**
- * Codepints prohibited by Nameprep
- * @static
- * @var array
- * @access private
- */
- private static $_np_prohibit = array(
- 0xA0,
- 0x1680,
- 0x2000,
- 0x2001,
- 0x2002,
- 0x2003,
- 0x2004,
- 0x2005,
- 0x2006,
- 0x2007,
- 0x2008,
- 0x2009,
- 0x200A,
- 0x200B,
- 0x202F,
- 0x205F,
- 0x3000,
- 0x6DD,
- 0x70F,
- 0x180E,
- 0x200C,
- 0x200D,
- 0x2028,
- 0x2029,
- 0xFEFF,
- 0xFFF9,
- 0xFFFA,
- 0xFFFB,
- 0xFFFC,
- 0xFFFE,
- 0xFFFF,
- 0x1FFFE,
- 0x1FFFF,
- 0x2FFFE,
- 0x2FFFF,
- 0x3FFFE,
- 0x3FFFF,
- 0x4FFFE,
- 0x4FFFF,
- 0x5FFFE,
- 0x5FFFF,
- 0x6FFFE,
- 0x6FFFF,
- 0x7FFFE,
- 0x7FFFF,
- 0x8FFFE,
- 0x8FFFF,
- 0x9FFFE,
- 0x9FFFF,
- 0xAFFFE,
- 0xAFFFF,
- 0xBFFFE,
- 0xBFFFF,
- 0xCFFFE,
- 0xCFFFF,
- 0xDFFFE,
- 0xDFFFF,
- 0xEFFFE,
- 0xEFFFF,
- 0xFFFFE,
- 0xFFFFF,
- 0x10FFFE,
- 0x10FFFF,
- 0xFFF9,
- 0xFFFA,
- 0xFFFB,
- 0xFFFC,
- 0xFFFD,
- 0x340,
- 0x341,
- 0x200E,
- 0x200F,
- 0x202A,
- 0x202B,
- 0x202C,
- 0x202D,
- 0x202E,
- 0x206A,
- 0x206B,
- 0x206C,
- 0x206D,
- 0x206E,
- 0x206F,
- 0xE0001
- );
-
- /**
- * Codepoint ranges prohibited by nameprep
- *
- * @static
- * @var array
- * @access private
- */
- private static $_np_prohibit_ranges = array(
- array(0x80, 0x9F ),
- array(0x2060, 0x206F ),
- array(0x1D173, 0x1D17A ),
- array(0xE000, 0xF8FF ),
- array(0xF0000, 0xFFFFD ),
- array(0x100000, 0x10FFFD),
- array(0xFDD0, 0xFDEF ),
- array(0xD800, 0xDFFF ),
- array(0x2FF0, 0x2FFB ),
- array(0xE0020, 0xE007F )
- );
-
- /**
- * Replacement mappings (casemapping, replacement sequences, ...)
- *
- * @static
- * @var array
- * @access private
- */
- private static $_np_replacemaps = array(
- 0x41 => array(0x61),
- 0x42 => array(0x62),
- 0x43 => array(0x63),
- 0x44 => array(0x64),
- 0x45 => array(0x65),
- 0x46 => array(0x66),
- 0x47 => array(0x67),
- 0x48 => array(0x68),
- 0x49 => array(0x69),
- 0x4A => array(0x6A),
- 0x4B => array(0x6B),
- 0x4C => array(0x6C),
- 0x4D => array(0x6D),
- 0x4E => array(0x6E),
- 0x4F => array(0x6F),
- 0x50 => array(0x70),
- 0x51 => array(0x71),
- 0x52 => array(0x72),
- 0x53 => array(0x73),
- 0x54 => array(0x74),
- 0x55 => array(0x75),
- 0x56 => array(0x76),
- 0x57 => array(0x77),
- 0x58 => array(0x78),
- 0x59 => array(0x79),
- 0x5A => array(0x7A),
- 0xB5 => array(0x3BC),
- 0xC0 => array(0xE0),
- 0xC1 => array(0xE1),
- 0xC2 => array(0xE2),
- 0xC3 => array(0xE3),
- 0xC4 => array(0xE4),
- 0xC5 => array(0xE5),
- 0xC6 => array(0xE6),
- 0xC7 => array(0xE7),
- 0xC8 => array(0xE8),
- 0xC9 => array(0xE9),
- 0xCA => array(0xEA),
- 0xCB => array(0xEB),
- 0xCC => array(0xEC),
- 0xCD => array(0xED),
- 0xCE => array(0xEE),
- 0xCF => array(0xEF),
- 0xD0 => array(0xF0),
- 0xD1 => array(0xF1),
- 0xD2 => array(0xF2),
- 0xD3 => array(0xF3),
- 0xD4 => array(0xF4),
- 0xD5 => array(0xF5),
- 0xD6 => array(0xF6),
- 0xD8 => array(0xF8),
- 0xD9 => array(0xF9),
- 0xDA => array(0xFA),
- 0xDB => array(0xFB),
- 0xDC => array(0xFC),
- 0xDD => array(0xFD),
- 0xDE => array(0xFE),
- 0xDF => array(0x73, 0x73),
- 0x100 => array(0x101),
- 0x102 => array(0x103),
- 0x104 => array(0x105),
- 0x106 => array(0x107),
- 0x108 => array(0x109),
- 0x10A => array(0x10B),
- 0x10C => array(0x10D),
- 0x10E => array(0x10F),
- 0x110 => array(0x111),
- 0x112 => array(0x113),
- 0x114 => array(0x115),
- 0x116 => array(0x117),
- 0x118 => array(0x119),
- 0x11A => array(0x11B),
- 0x11C => array(0x11D),
- 0x11E => array(0x11F),
- 0x120 => array(0x121),
- 0x122 => array(0x123),
- 0x124 => array(0x125),
- 0x126 => array(0x127),
- 0x128 => array(0x129),
- 0x12A => array(0x12B),
- 0x12C => array(0x12D),
- 0x12E => array(0x12F),
- 0x130 => array(0x69, 0x307),
- 0x132 => array(0x133),
- 0x134 => array(0x135),
- 0x136 => array(0x137),
- 0x139 => array(0x13A),
- 0x13B => array(0x13C),
- 0x13D => array(0x13E),
- 0x13F => array(0x140),
- 0x141 => array(0x142),
- 0x143 => array(0x144),
- 0x145 => array(0x146),
- 0x147 => array(0x148),
- 0x149 => array(0x2BC, 0x6E),
- 0x14A => array(0x14B),
- 0x14C => array(0x14D),
- 0x14E => array(0x14F),
- 0x150 => array(0x151),
- 0x152 => array(0x153),
- 0x154 => array(0x155),
- 0x156 => array(0x157),
- 0x158 => array(0x159),
- 0x15A => array(0x15B),
- 0x15C => array(0x15D),
- 0x15E => array(0x15F),
- 0x160 => array(0x161),
- 0x162 => array(0x163),
- 0x164 => array(0x165),
- 0x166 => array(0x167),
- 0x168 => array(0x169),
- 0x16A => array(0x16B),
- 0x16C => array(0x16D),
- 0x16E => array(0x16F),
- 0x170 => array(0x171),
- 0x172 => array(0x173),
- 0x174 => array(0x175),
- 0x176 => array(0x177),
- 0x178 => array(0xFF),
- 0x179 => array(0x17A),
- 0x17B => array(0x17C),
- 0x17D => array(0x17E),
- 0x17F => array(0x73),
- 0x181 => array(0x253),
- 0x182 => array(0x183),
- 0x184 => array(0x185),
- 0x186 => array(0x254),
- 0x187 => array(0x188),
- 0x189 => array(0x256),
- 0x18A => array(0x257),
- 0x18B => array(0x18C),
- 0x18E => array(0x1DD),
- 0x18F => array(0x259),
- 0x190 => array(0x25B),
- 0x191 => array(0x192),
- 0x193 => array(0x260),
- 0x194 => array(0x263),
- 0x196 => array(0x269),
- 0x197 => array(0x268),
- 0x198 => array(0x199),
- 0x19C => array(0x26F),
- 0x19D => array(0x272),
- 0x19F => array(0x275),
- 0x1A0 => array(0x1A1),
- 0x1A2 => array(0x1A3),
- 0x1A4 => array(0x1A5),
- 0x1A6 => array(0x280),
- 0x1A7 => array(0x1A8),
- 0x1A9 => array(0x283),
- 0x1AC => array(0x1AD),
- 0x1AE => array(0x288),
- 0x1AF => array(0x1B0),
- 0x1B1 => array(0x28A),
- 0x1B2 => array(0x28B),
- 0x1B3 => array(0x1B4),
- 0x1B5 => array(0x1B6),
- 0x1B7 => array(0x292),
- 0x1B8 => array(0x1B9),
- 0x1BC => array(0x1BD),
- 0x1C4 => array(0x1C6),
- 0x1C5 => array(0x1C6),
- 0x1C7 => array(0x1C9),
- 0x1C8 => array(0x1C9),
- 0x1CA => array(0x1CC),
- 0x1CB => array(0x1CC),
- 0x1CD => array(0x1CE),
- 0x1CF => array(0x1D0),
- 0x1D1 => array(0x1D2),
- 0x1D3 => array(0x1D4),
- 0x1D5 => array(0x1D6),
- 0x1D7 => array(0x1D8),
- 0x1D9 => array(0x1DA),
- 0x1DB => array(0x1DC),
- 0x1DE => array(0x1DF),
- 0x1E0 => array(0x1E1),
- 0x1E2 => array(0x1E3),
- 0x1E4 => array(0x1E5),
- 0x1E6 => array(0x1E7),
- 0x1E8 => array(0x1E9),
- 0x1EA => array(0x1EB),
- 0x1EC => array(0x1ED),
- 0x1EE => array(0x1EF),
- 0x1F0 => array(0x6A, 0x30C),
- 0x1F1 => array(0x1F3),
- 0x1F2 => array(0x1F3),
- 0x1F4 => array(0x1F5),
- 0x1F6 => array(0x195),
- 0x1F7 => array(0x1BF),
- 0x1F8 => array(0x1F9),
- 0x1FA => array(0x1FB),
- 0x1FC => array(0x1FD),
- 0x1FE => array(0x1FF),
- 0x200 => array(0x201),
- 0x202 => array(0x203),
- 0x204 => array(0x205),
- 0x206 => array(0x207),
- 0x208 => array(0x209),
- 0x20A => array(0x20B),
- 0x20C => array(0x20D),
- 0x20E => array(0x20F),
- 0x210 => array(0x211),
- 0x212 => array(0x213),
- 0x214 => array(0x215),
- 0x216 => array(0x217),
- 0x218 => array(0x219),
- 0x21A => array(0x21B),
- 0x21C => array(0x21D),
- 0x21E => array(0x21F),
- 0x220 => array(0x19E),
- 0x222 => array(0x223),
- 0x224 => array(0x225),
- 0x226 => array(0x227),
- 0x228 => array(0x229),
- 0x22A => array(0x22B),
- 0x22C => array(0x22D),
- 0x22E => array(0x22F),
- 0x230 => array(0x231),
- 0x232 => array(0x233),
- 0x345 => array(0x3B9),
- 0x37A => array(0x20, 0x3B9),
- 0x386 => array(0x3AC),
- 0x388 => array(0x3AD),
- 0x389 => array(0x3AE),
- 0x38A => array(0x3AF),
- 0x38C => array(0x3CC),
- 0x38E => array(0x3CD),
- 0x38F => array(0x3CE),
- 0x390 => array(0x3B9, 0x308, 0x301),
- 0x391 => array(0x3B1),
- 0x392 => array(0x3B2),
- 0x393 => array(0x3B3),
- 0x394 => array(0x3B4),
- 0x395 => array(0x3B5),
- 0x396 => array(0x3B6),
- 0x397 => array(0x3B7),
- 0x398 => array(0x3B8),
- 0x399 => array(0x3B9),
- 0x39A => array(0x3BA),
- 0x39B => array(0x3BB),
- 0x39C => array(0x3BC),
- 0x39D => array(0x3BD),
- 0x39E => array(0x3BE),
- 0x39F => array(0x3BF),
- 0x3A0 => array(0x3C0),
- 0x3A1 => array(0x3C1),
- 0x3A3 => array(0x3C3),
- 0x3A4 => array(0x3C4),
- 0x3A5 => array(0x3C5),
- 0x3A6 => array(0x3C6),
- 0x3A7 => array(0x3C7),
- 0x3A8 => array(0x3C8),
- 0x3A9 => array(0x3C9),
- 0x3AA => array(0x3CA),
- 0x3AB => array(0x3CB),
- 0x3B0 => array(0x3C5, 0x308, 0x301),
- 0x3C2 => array(0x3C3),
- 0x3D0 => array(0x3B2),
- 0x3D1 => array(0x3B8),
- 0x3D2 => array(0x3C5),
- 0x3D3 => array(0x3CD),
- 0x3D4 => array(0x3CB),
- 0x3D5 => array(0x3C6),
- 0x3D6 => array(0x3C0),
- 0x3D8 => array(0x3D9),
- 0x3DA => array(0x3DB),
- 0x3DC => array(0x3DD),
- 0x3DE => array(0x3DF),
- 0x3E0 => array(0x3E1),
- 0x3E2 => array(0x3E3),
- 0x3E4 => array(0x3E5),
- 0x3E6 => array(0x3E7),
- 0x3E8 => array(0x3E9),
- 0x3EA => array(0x3EB),
- 0x3EC => array(0x3ED),
- 0x3EE => array(0x3EF),
- 0x3F0 => array(0x3BA),
- 0x3F1 => array(0x3C1),
- 0x3F2 => array(0x3C3),
- 0x3F4 => array(0x3B8),
- 0x3F5 => array(0x3B5),
- 0x400 => array(0x450),
- 0x401 => array(0x451),
- 0x402 => array(0x452),
- 0x403 => array(0x453),
- 0x404 => array(0x454),
- 0x405 => array(0x455),
- 0x406 => array(0x456),
- 0x407 => array(0x457),
- 0x408 => array(0x458),
- 0x409 => array(0x459),
- 0x40A => array(0x45A),
- 0x40B => array(0x45B),
- 0x40C => array(0x45C),
- 0x40D => array(0x45D),
- 0x40E => array(0x45E),
- 0x40F => array(0x45F),
- 0x410 => array(0x430),
- 0x411 => array(0x431),
- 0x412 => array(0x432),
- 0x413 => array(0x433),
- 0x414 => array(0x434),
- 0x415 => array(0x435),
- 0x416 => array(0x436),
- 0x417 => array(0x437),
- 0x418 => array(0x438),
- 0x419 => array(0x439),
- 0x41A => array(0x43A),
- 0x41B => array(0x43B),
- 0x41C => array(0x43C),
- 0x41D => array(0x43D),
- 0x41E => array(0x43E),
- 0x41F => array(0x43F),
- 0x420 => array(0x440),
- 0x421 => array(0x441),
- 0x422 => array(0x442),
- 0x423 => array(0x443),
- 0x424 => array(0x444),
- 0x425 => array(0x445),
- 0x426 => array(0x446),
- 0x427 => array(0x447),
- 0x428 => array(0x448),
- 0x429 => array(0x449),
- 0x42A => array(0x44A),
- 0x42B => array(0x44B),
- 0x42C => array(0x44C),
- 0x42D => array(0x44D),
- 0x42E => array(0x44E),
- 0x42F => array(0x44F),
- 0x460 => array(0x461),
- 0x462 => array(0x463),
- 0x464 => array(0x465),
- 0x466 => array(0x467),
- 0x468 => array(0x469),
- 0x46A => array(0x46B),
- 0x46C => array(0x46D),
- 0x46E => array(0x46F),
- 0x470 => array(0x471),
- 0x472 => array(0x473),
- 0x474 => array(0x475),
- 0x476 => array(0x477),
- 0x478 => array(0x479),
- 0x47A => array(0x47B),
- 0x47C => array(0x47D),
- 0x47E => array(0x47F),
- 0x480 => array(0x481),
- 0x48A => array(0x48B),
- 0x48C => array(0x48D),
- 0x48E => array(0x48F),
- 0x490 => array(0x491),
- 0x492 => array(0x493),
- 0x494 => array(0x495),
- 0x496 => array(0x497),
- 0x498 => array(0x499),
- 0x49A => array(0x49B),
- 0x49C => array(0x49D),
- 0x49E => array(0x49F),
- 0x4A0 => array(0x4A1),
- 0x4A2 => array(0x4A3),
- 0x4A4 => array(0x4A5),
- 0x4A6 => array(0x4A7),
- 0x4A8 => array(0x4A9),
- 0x4AA => array(0x4AB),
- 0x4AC => array(0x4AD),
- 0x4AE => array(0x4AF),
- 0x4B0 => array(0x4B1),
- 0x4B2 => array(0x4B3),
- 0x4B4 => array(0x4B5),
- 0x4B6 => array(0x4B7),
- 0x4B8 => array(0x4B9),
- 0x4BA => array(0x4BB),
- 0x4BC => array(0x4BD),
- 0x4BE => array(0x4BF),
- 0x4C1 => array(0x4C2),
- 0x4C3 => array(0x4C4),
- 0x4C5 => array(0x4C6),
- 0x4C7 => array(0x4C8),
- 0x4C9 => array(0x4CA),
- 0x4CB => array(0x4CC),
- 0x4CD => array(0x4CE),
- 0x4D0 => array(0x4D1),
- 0x4D2 => array(0x4D3),
- 0x4D4 => array(0x4D5),
- 0x4D6 => array(0x4D7),
- 0x4D8 => array(0x4D9),
- 0x4DA => array(0x4DB),
- 0x4DC => array(0x4DD),
- 0x4DE => array(0x4DF),
- 0x4E0 => array(0x4E1),
- 0x4E2 => array(0x4E3),
- 0x4E4 => array(0x4E5),
- 0x4E6 => array(0x4E7),
- 0x4E8 => array(0x4E9),
- 0x4EA => array(0x4EB),
- 0x4EC => array(0x4ED),
- 0x4EE => array(0x4EF),
- 0x4F0 => array(0x4F1),
- 0x4F2 => array(0x4F3),
- 0x4F4 => array(0x4F5),
- 0x4F8 => array(0x4F9),
- 0x500 => array(0x501),
- 0x502 => array(0x503),
- 0x504 => array(0x505),
- 0x506 => array(0x507),
- 0x508 => array(0x509),
- 0x50A => array(0x50B),
- 0x50C => array(0x50D),
- 0x50E => array(0x50F),
- 0x531 => array(0x561),
- 0x532 => array(0x562),
- 0x533 => array(0x563),
- 0x534 => array(0x564),
- 0x535 => array(0x565),
- 0x536 => array(0x566),
- 0x537 => array(0x567),
- 0x538 => array(0x568),
- 0x539 => array(0x569),
- 0x53A => array(0x56A),
- 0x53B => array(0x56B),
- 0x53C => array(0x56C),
- 0x53D => array(0x56D),
- 0x53E => array(0x56E),
- 0x53F => array(0x56F),
- 0x540 => array(0x570),
- 0x541 => array(0x571),
- 0x542 => array(0x572),
- 0x543 => array(0x573),
- 0x544 => array(0x574),
- 0x545 => array(0x575),
- 0x546 => array(0x576),
- 0x547 => array(0x577),
- 0x548 => array(0x578),
- 0x549 => array(0x579),
- 0x54A => array(0x57A),
- 0x54B => array(0x57B),
- 0x54C => array(0x57C),
- 0x54D => array(0x57D),
- 0x54E => array(0x57E),
- 0x54F => array(0x57F),
- 0x550 => array(0x580),
- 0x551 => array(0x581),
- 0x552 => array(0x582),
- 0x553 => array(0x583),
- 0x554 => array(0x584),
- 0x555 => array(0x585),
- 0x556 => array(0x586),
- 0x587 => array(0x565, 0x582),
- 0x1E00 => array(0x1E01),
- 0x1E02 => array(0x1E03),
- 0x1E04 => array(0x1E05),
- 0x1E06 => array(0x1E07),
- 0x1E08 => array(0x1E09),
- 0x1E0A => array(0x1E0B),
- 0x1E0C => array(0x1E0D),
- 0x1E0E => array(0x1E0F),
- 0x1E10 => array(0x1E11),
- 0x1E12 => array(0x1E13),
- 0x1E14 => array(0x1E15),
- 0x1E16 => array(0x1E17),
- 0x1E18 => array(0x1E19),
- 0x1E1A => array(0x1E1B),
- 0x1E1C => array(0x1E1D),
- 0x1E1E => array(0x1E1F),
- 0x1E20 => array(0x1E21),
- 0x1E22 => array(0x1E23),
- 0x1E24 => array(0x1E25),
- 0x1E26 => array(0x1E27),
- 0x1E28 => array(0x1E29),
- 0x1E2A => array(0x1E2B),
- 0x1E2C => array(0x1E2D),
- 0x1E2E => array(0x1E2F),
- 0x1E30 => array(0x1E31),
- 0x1E32 => array(0x1E33),
- 0x1E34 => array(0x1E35),
- 0x1E36 => array(0x1E37),
- 0x1E38 => array(0x1E39),
- 0x1E3A => array(0x1E3B),
- 0x1E3C => array(0x1E3D),
- 0x1E3E => array(0x1E3F),
- 0x1E40 => array(0x1E41),
- 0x1E42 => array(0x1E43),
- 0x1E44 => array(0x1E45),
- 0x1E46 => array(0x1E47),
- 0x1E48 => array(0x1E49),
- 0x1E4A => array(0x1E4B),
- 0x1E4C => array(0x1E4D),
- 0x1E4E => array(0x1E4F),
- 0x1E50 => array(0x1E51),
- 0x1E52 => array(0x1E53),
- 0x1E54 => array(0x1E55),
- 0x1E56 => array(0x1E57),
- 0x1E58 => array(0x1E59),
- 0x1E5A => array(0x1E5B),
- 0x1E5C => array(0x1E5D),
- 0x1E5E => array(0x1E5F),
- 0x1E60 => array(0x1E61),
- 0x1E62 => array(0x1E63),
- 0x1E64 => array(0x1E65),
- 0x1E66 => array(0x1E67),
- 0x1E68 => array(0x1E69),
- 0x1E6A => array(0x1E6B),
- 0x1E6C => array(0x1E6D),
- 0x1E6E => array(0x1E6F),
- 0x1E70 => array(0x1E71),
- 0x1E72 => array(0x1E73),
- 0x1E74 => array(0x1E75),
- 0x1E76 => array(0x1E77),
- 0x1E78 => array(0x1E79),
- 0x1E7A => array(0x1E7B),
- 0x1E7C => array(0x1E7D),
- 0x1E7E => array(0x1E7F),
- 0x1E80 => array(0x1E81),
- 0x1E82 => array(0x1E83),
- 0x1E84 => array(0x1E85),
- 0x1E86 => array(0x1E87),
- 0x1E88 => array(0x1E89),
- 0x1E8A => array(0x1E8B),
- 0x1E8C => array(0x1E8D),
- 0x1E8E => array(0x1E8F),
- 0x1E90 => array(0x1E91),
- 0x1E92 => array(0x1E93),
- 0x1E94 => array(0x1E95),
- 0x1E96 => array(0x68, 0x331),
- 0x1E97 => array(0x74, 0x308),
- 0x1E98 => array(0x77, 0x30A),
- 0x1E99 => array(0x79, 0x30A),
- 0x1E9A => array(0x61, 0x2BE),
- 0x1E9B => array(0x1E61),
- 0x1EA0 => array(0x1EA1),
- 0x1EA2 => array(0x1EA3),
- 0x1EA4 => array(0x1EA5),
- 0x1EA6 => array(0x1EA7),
- 0x1EA8 => array(0x1EA9),
- 0x1EAA => array(0x1EAB),
- 0x1EAC => array(0x1EAD),
- 0x1EAE => array(0x1EAF),
- 0x1EB0 => array(0x1EB1),
- 0x1EB2 => array(0x1EB3),
- 0x1EB4 => array(0x1EB5),
- 0x1EB6 => array(0x1EB7),
- 0x1EB8 => array(0x1EB9),
- 0x1EBA => array(0x1EBB),
- 0x1EBC => array(0x1EBD),
- 0x1EBE => array(0x1EBF),
- 0x1EC0 => array(0x1EC1),
- 0x1EC2 => array(0x1EC3),
- 0x1EC4 => array(0x1EC5),
- 0x1EC6 => array(0x1EC7),
- 0x1EC8 => array(0x1EC9),
- 0x1ECA => array(0x1ECB),
- 0x1ECC => array(0x1ECD),
- 0x1ECE => array(0x1ECF),
- 0x1ED0 => array(0x1ED1),
- 0x1ED2 => array(0x1ED3),
- 0x1ED4 => array(0x1ED5),
- 0x1ED6 => array(0x1ED7),
- 0x1ED8 => array(0x1ED9),
- 0x1EDA => array(0x1EDB),
- 0x1EDC => array(0x1EDD),
- 0x1EDE => array(0x1EDF),
- 0x1EE0 => array(0x1EE1),
- 0x1EE2 => array(0x1EE3),
- 0x1EE4 => array(0x1EE5),
- 0x1EE6 => array(0x1EE7),
- 0x1EE8 => array(0x1EE9),
- 0x1EEA => array(0x1EEB),
- 0x1EEC => array(0x1EED),
- 0x1EEE => array(0x1EEF),
- 0x1EF0 => array(0x1EF1),
- 0x1EF2 => array(0x1EF3),
- 0x1EF4 => array(0x1EF5),
- 0x1EF6 => array(0x1EF7),
- 0x1EF8 => array(0x1EF9),
- 0x1F08 => array(0x1F00),
- 0x1F09 => array(0x1F01),
- 0x1F0A => array(0x1F02),
- 0x1F0B => array(0x1F03),
- 0x1F0C => array(0x1F04),
- 0x1F0D => array(0x1F05),
- 0x1F0E => array(0x1F06),
- 0x1F0F => array(0x1F07),
- 0x1F18 => array(0x1F10),
- 0x1F19 => array(0x1F11),
- 0x1F1A => array(0x1F12),
- 0x1F1B => array(0x1F13),
- 0x1F1C => array(0x1F14),
- 0x1F1D => array(0x1F15),
- 0x1F28 => array(0x1F20),
- 0x1F29 => array(0x1F21),
- 0x1F2A => array(0x1F22),
- 0x1F2B => array(0x1F23),
- 0x1F2C => array(0x1F24),
- 0x1F2D => array(0x1F25),
- 0x1F2E => array(0x1F26),
- 0x1F2F => array(0x1F27),
- 0x1F38 => array(0x1F30),
- 0x1F39 => array(0x1F31),
- 0x1F3A => array(0x1F32),
- 0x1F3B => array(0x1F33),
- 0x1F3C => array(0x1F34),
- 0x1F3D => array(0x1F35),
- 0x1F3E => array(0x1F36),
- 0x1F3F => array(0x1F37),
- 0x1F48 => array(0x1F40),
- 0x1F49 => array(0x1F41),
- 0x1F4A => array(0x1F42),
- 0x1F4B => array(0x1F43),
- 0x1F4C => array(0x1F44),
- 0x1F4D => array(0x1F45),
- 0x1F50 => array(0x3C5, 0x313),
- 0x1F52 => array(0x3C5, 0x313, 0x300),
- 0x1F54 => array(0x3C5, 0x313, 0x301),
- 0x1F56 => array(0x3C5, 0x313, 0x342),
- 0x1F59 => array(0x1F51),
- 0x1F5B => array(0x1F53),
- 0x1F5D => array(0x1F55),
- 0x1F5F => array(0x1F57),
- 0x1F68 => array(0x1F60),
- 0x1F69 => array(0x1F61),
- 0x1F6A => array(0x1F62),
- 0x1F6B => array(0x1F63),
- 0x1F6C => array(0x1F64),
- 0x1F6D => array(0x1F65),
- 0x1F6E => array(0x1F66),
- 0x1F6F => array(0x1F67),
- 0x1F80 => array(0x1F00, 0x3B9),
- 0x1F81 => array(0x1F01, 0x3B9),
- 0x1F82 => array(0x1F02, 0x3B9),
- 0x1F83 => array(0x1F03, 0x3B9),
- 0x1F84 => array(0x1F04, 0x3B9),
- 0x1F85 => array(0x1F05, 0x3B9),
- 0x1F86 => array(0x1F06, 0x3B9),
- 0x1F87 => array(0x1F07, 0x3B9),
- 0x1F88 => array(0x1F00, 0x3B9),
- 0x1F89 => array(0x1F01, 0x3B9),
- 0x1F8A => array(0x1F02, 0x3B9),
- 0x1F8B => array(0x1F03, 0x3B9),
- 0x1F8C => array(0x1F04, 0x3B9),
- 0x1F8D => array(0x1F05, 0x3B9),
- 0x1F8E => array(0x1F06, 0x3B9),
- 0x1F8F => array(0x1F07, 0x3B9),
- 0x1F90 => array(0x1F20, 0x3B9),
- 0x1F91 => array(0x1F21, 0x3B9),
- 0x1F92 => array(0x1F22, 0x3B9),
- 0x1F93 => array(0x1F23, 0x3B9),
- 0x1F94 => array(0x1F24, 0x3B9),
- 0x1F95 => array(0x1F25, 0x3B9),
- 0x1F96 => array(0x1F26, 0x3B9),
- 0x1F97 => array(0x1F27, 0x3B9),
- 0x1F98 => array(0x1F20, 0x3B9),
- 0x1F99 => array(0x1F21, 0x3B9),
- 0x1F9A => array(0x1F22, 0x3B9),
- 0x1F9B => array(0x1F23, 0x3B9),
- 0x1F9C => array(0x1F24, 0x3B9),
- 0x1F9D => array(0x1F25, 0x3B9),
- 0x1F9E => array(0x1F26, 0x3B9),
- 0x1F9F => array(0x1F27, 0x3B9),
- 0x1FA0 => array(0x1F60, 0x3B9),
- 0x1FA1 => array(0x1F61, 0x3B9),
- 0x1FA2 => array(0x1F62, 0x3B9),
- 0x1FA3 => array(0x1F63, 0x3B9),
- 0x1FA4 => array(0x1F64, 0x3B9),
- 0x1FA5 => array(0x1F65, 0x3B9),
- 0x1FA6 => array(0x1F66, 0x3B9),
- 0x1FA7 => array(0x1F67, 0x3B9),
- 0x1FA8 => array(0x1F60, 0x3B9),
- 0x1FA9 => array(0x1F61, 0x3B9),
- 0x1FAA => array(0x1F62, 0x3B9),
- 0x1FAB => array(0x1F63, 0x3B9),
- 0x1FAC => array(0x1F64, 0x3B9),
- 0x1FAD => array(0x1F65, 0x3B9),
- 0x1FAE => array(0x1F66, 0x3B9),
- 0x1FAF => array(0x1F67, 0x3B9),
- 0x1FB2 => array(0x1F70, 0x3B9),
- 0x1FB3 => array(0x3B1, 0x3B9),
- 0x1FB4 => array(0x3AC, 0x3B9),
- 0x1FB6 => array(0x3B1, 0x342),
- 0x1FB7 => array(0x3B1, 0x342, 0x3B9),
- 0x1FB8 => array(0x1FB0),
- 0x1FB9 => array(0x1FB1),
- 0x1FBA => array(0x1F70),
- 0x1FBB => array(0x1F71),
- 0x1FBC => array(0x3B1, 0x3B9),
- 0x1FBE => array(0x3B9),
- 0x1FC2 => array(0x1F74, 0x3B9),
- 0x1FC3 => array(0x3B7, 0x3B9),
- 0x1FC4 => array(0x3AE, 0x3B9),
- 0x1FC6 => array(0x3B7, 0x342),
- 0x1FC7 => array(0x3B7, 0x342, 0x3B9),
- 0x1FC8 => array(0x1F72),
- 0x1FC9 => array(0x1F73),
- 0x1FCA => array(0x1F74),
- 0x1FCB => array(0x1F75),
- 0x1FCC => array(0x3B7, 0x3B9),
- 0x1FD2 => array(0x3B9, 0x308, 0x300),
- 0x1FD3 => array(0x3B9, 0x308, 0x301),
- 0x1FD6 => array(0x3B9, 0x342),
- 0x1FD7 => array(0x3B9, 0x308, 0x342),
- 0x1FD8 => array(0x1FD0),
- 0x1FD9 => array(0x1FD1),
- 0x1FDA => array(0x1F76),
- 0x1FDB => array(0x1F77),
- 0x1FE2 => array(0x3C5, 0x308, 0x300),
- 0x1FE3 => array(0x3C5, 0x308, 0x301),
- 0x1FE4 => array(0x3C1, 0x313),
- 0x1FE6 => array(0x3C5, 0x342),
- 0x1FE7 => array(0x3C5, 0x308, 0x342),
- 0x1FE8 => array(0x1FE0),
- 0x1FE9 => array(0x1FE1),
- 0x1FEA => array(0x1F7A),
- 0x1FEB => array(0x1F7B),
- 0x1FEC => array(0x1FE5),
- 0x1FF2 => array(0x1F7C, 0x3B9),
- 0x1FF3 => array(0x3C9, 0x3B9),
- 0x1FF4 => array(0x3CE, 0x3B9),
- 0x1FF6 => array(0x3C9, 0x342),
- 0x1FF7 => array(0x3C9, 0x342, 0x3B9),
- 0x1FF8 => array(0x1F78),
- 0x1FF9 => array(0x1F79),
- 0x1FFA => array(0x1F7C),
- 0x1FFB => array(0x1F7D),
- 0x1FFC => array(0x3C9, 0x3B9),
- 0x20A8 => array(0x72, 0x73),
- 0x2102 => array(0x63),
- 0x2103 => array(0xB0, 0x63),
- 0x2107 => array(0x25B),
- 0x2109 => array(0xB0, 0x66),
- 0x210B => array(0x68),
- 0x210C => array(0x68),
- 0x210D => array(0x68),
- 0x2110 => array(0x69),
- 0x2111 => array(0x69),
- 0x2112 => array(0x6C),
- 0x2115 => array(0x6E),
- 0x2116 => array(0x6E, 0x6F),
- 0x2119 => array(0x70),
- 0x211A => array(0x71),
- 0x211B => array(0x72),
- 0x211C => array(0x72),
- 0x211D => array(0x72),
- 0x2120 => array(0x73, 0x6D),
- 0x2121 => array(0x74, 0x65, 0x6C),
- 0x2122 => array(0x74, 0x6D),
- 0x2124 => array(0x7A),
- 0x2126 => array(0x3C9),
- 0x2128 => array(0x7A),
- 0x212A => array(0x6B),
- 0x212B => array(0xE5),
- 0x212C => array(0x62),
- 0x212D => array(0x63),
- 0x2130 => array(0x65),
- 0x2131 => array(0x66),
- 0x2133 => array(0x6D),
- 0x213E => array(0x3B3),
- 0x213F => array(0x3C0),
- 0x2145 => array(0x64),
- 0x2160 => array(0x2170),
- 0x2161 => array(0x2171),
- 0x2162 => array(0x2172),
- 0x2163 => array(0x2173),
- 0x2164 => array(0x2174),
- 0x2165 => array(0x2175),
- 0x2166 => array(0x2176),
- 0x2167 => array(0x2177),
- 0x2168 => array(0x2178),
- 0x2169 => array(0x2179),
- 0x216A => array(0x217A),
- 0x216B => array(0x217B),
- 0x216C => array(0x217C),
- 0x216D => array(0x217D),
- 0x216E => array(0x217E),
- 0x216F => array(0x217F),
- 0x24B6 => array(0x24D0),
- 0x24B7 => array(0x24D1),
- 0x24B8 => array(0x24D2),
- 0x24B9 => array(0x24D3),
- 0x24BA => array(0x24D4),
- 0x24BB => array(0x24D5),
- 0x24BC => array(0x24D6),
- 0x24BD => array(0x24D7),
- 0x24BE => array(0x24D8),
- 0x24BF => array(0x24D9),
- 0x24C0 => array(0x24DA),
- 0x24C1 => array(0x24DB),
- 0x24C2 => array(0x24DC),
- 0x24C3 => array(0x24DD),
- 0x24C4 => array(0x24DE),
- 0x24C5 => array(0x24DF),
- 0x24C6 => array(0x24E0),
- 0x24C7 => array(0x24E1),
- 0x24C8 => array(0x24E2),
- 0x24C9 => array(0x24E3),
- 0x24CA => array(0x24E4),
- 0x24CB => array(0x24E5),
- 0x24CC => array(0x24E6),
- 0x24CD => array(0x24E7),
- 0x24CE => array(0x24E8),
- 0x24CF => array(0x24E9),
- 0x3371 => array(0x68, 0x70, 0x61),
- 0x3373 => array(0x61, 0x75),
- 0x3375 => array(0x6F, 0x76),
- 0x3380 => array(0x70, 0x61),
- 0x3381 => array(0x6E, 0x61),
- 0x3382 => array(0x3BC, 0x61),
- 0x3383 => array(0x6D, 0x61),
- 0x3384 => array(0x6B, 0x61),
- 0x3385 => array(0x6B, 0x62),
- 0x3386 => array(0x6D, 0x62),
- 0x3387 => array(0x67, 0x62),
- 0x338A => array(0x70, 0x66),
- 0x338B => array(0x6E, 0x66),
- 0x338C => array(0x3BC, 0x66),
- 0x3390 => array(0x68, 0x7A),
- 0x3391 => array(0x6B, 0x68, 0x7A),
- 0x3392 => array(0x6D, 0x68, 0x7A),
- 0x3393 => array(0x67, 0x68, 0x7A),
- 0x3394 => array(0x74, 0x68, 0x7A),
- 0x33A9 => array(0x70, 0x61),
- 0x33AA => array(0x6B, 0x70, 0x61),
- 0x33AB => array(0x6D, 0x70, 0x61),
- 0x33AC => array(0x67, 0x70, 0x61),
- 0x33B4 => array(0x70, 0x76),
- 0x33B5 => array(0x6E, 0x76),
- 0x33B6 => array(0x3BC, 0x76),
- 0x33B7 => array(0x6D, 0x76),
- 0x33B8 => array(0x6B, 0x76),
- 0x33B9 => array(0x6D, 0x76),
- 0x33BA => array(0x70, 0x77),
- 0x33BB => array(0x6E, 0x77),
- 0x33BC => array(0x3BC, 0x77),
- 0x33BD => array(0x6D, 0x77),
- 0x33BE => array(0x6B, 0x77),
- 0x33BF => array(0x6D, 0x77),
- 0x33C0 => array(0x6B, 0x3C9),
- 0x33C1 => array(0x6D, 0x3C9),
- /* 0x33C2 => array(0x61, 0x2E, 0x6D, 0x2E), */
- 0x33C3 => array(0x62, 0x71),
- 0x33C6 => array(0x63, 0x2215, 0x6B, 0x67),
- 0x33C7 => array(0x63, 0x6F, 0x2E),
- 0x33C8 => array(0x64, 0x62),
- 0x33C9 => array(0x67, 0x79),
- 0x33CB => array(0x68, 0x70),
- 0x33CD => array(0x6B, 0x6B),
- 0x33CE => array(0x6B, 0x6D),
- 0x33D7 => array(0x70, 0x68),
- 0x33D9 => array(0x70, 0x70, 0x6D),
- 0x33DA => array(0x70, 0x72),
- 0x33DC => array(0x73, 0x76),
- 0x33DD => array(0x77, 0x62),
- 0xFB00 => array(0x66, 0x66),
- 0xFB01 => array(0x66, 0x69),
- 0xFB02 => array(0x66, 0x6C),
- 0xFB03 => array(0x66, 0x66, 0x69),
- 0xFB04 => array(0x66, 0x66, 0x6C),
- 0xFB05 => array(0x73, 0x74),
- 0xFB06 => array(0x73, 0x74),
- 0xFB13 => array(0x574, 0x576),
- 0xFB14 => array(0x574, 0x565),
- 0xFB15 => array(0x574, 0x56B),
- 0xFB16 => array(0x57E, 0x576),
- 0xFB17 => array(0x574, 0x56D),
- 0xFF21 => array(0xFF41),
- 0xFF22 => array(0xFF42),
- 0xFF23 => array(0xFF43),
- 0xFF24 => array(0xFF44),
- 0xFF25 => array(0xFF45),
- 0xFF26 => array(0xFF46),
- 0xFF27 => array(0xFF47),
- 0xFF28 => array(0xFF48),
- 0xFF29 => array(0xFF49),
- 0xFF2A => array(0xFF4A),
- 0xFF2B => array(0xFF4B),
- 0xFF2C => array(0xFF4C),
- 0xFF2D => array(0xFF4D),
- 0xFF2E => array(0xFF4E),
- 0xFF2F => array(0xFF4F),
- 0xFF30 => array(0xFF50),
- 0xFF31 => array(0xFF51),
- 0xFF32 => array(0xFF52),
- 0xFF33 => array(0xFF53),
- 0xFF34 => array(0xFF54),
- 0xFF35 => array(0xFF55),
- 0xFF36 => array(0xFF56),
- 0xFF37 => array(0xFF57),
- 0xFF38 => array(0xFF58),
- 0xFF39 => array(0xFF59),
- 0xFF3A => array(0xFF5A),
- 0x10400 => array(0x10428),
- 0x10401 => array(0x10429),
- 0x10402 => array(0x1042A),
- 0x10403 => array(0x1042B),
- 0x10404 => array(0x1042C),
- 0x10405 => array(0x1042D),
- 0x10406 => array(0x1042E),
- 0x10407 => array(0x1042F),
- 0x10408 => array(0x10430),
- 0x10409 => array(0x10431),
- 0x1040A => array(0x10432),
- 0x1040B => array(0x10433),
- 0x1040C => array(0x10434),
- 0x1040D => array(0x10435),
- 0x1040E => array(0x10436),
- 0x1040F => array(0x10437),
- 0x10410 => array(0x10438),
- 0x10411 => array(0x10439),
- 0x10412 => array(0x1043A),
- 0x10413 => array(0x1043B),
- 0x10414 => array(0x1043C),
- 0x10415 => array(0x1043D),
- 0x10416 => array(0x1043E),
- 0x10417 => array(0x1043F),
- 0x10418 => array(0x10440),
- 0x10419 => array(0x10441),
- 0x1041A => array(0x10442),
- 0x1041B => array(0x10443),
- 0x1041C => array(0x10444),
- 0x1041D => array(0x10445),
- 0x1041E => array(0x10446),
- 0x1041F => array(0x10447),
- 0x10420 => array(0x10448),
- 0x10421 => array(0x10449),
- 0x10422 => array(0x1044A),
- 0x10423 => array(0x1044B),
- 0x10424 => array(0x1044C),
- 0x10425 => array(0x1044D),
- 0x1D400 => array(0x61),
- 0x1D401 => array(0x62),
- 0x1D402 => array(0x63),
- 0x1D403 => array(0x64),
- 0x1D404 => array(0x65),
- 0x1D405 => array(0x66),
- 0x1D406 => array(0x67),
- 0x1D407 => array(0x68),
- 0x1D408 => array(0x69),
- 0x1D409 => array(0x6A),
- 0x1D40A => array(0x6B),
- 0x1D40B => array(0x6C),
- 0x1D40C => array(0x6D),
- 0x1D40D => array(0x6E),
- 0x1D40E => array(0x6F),
- 0x1D40F => array(0x70),
- 0x1D410 => array(0x71),
- 0x1D411 => array(0x72),
- 0x1D412 => array(0x73),
- 0x1D413 => array(0x74),
- 0x1D414 => array(0x75),
- 0x1D415 => array(0x76),
- 0x1D416 => array(0x77),
- 0x1D417 => array(0x78),
- 0x1D418 => array(0x79),
- 0x1D419 => array(0x7A),
- 0x1D434 => array(0x61),
- 0x1D435 => array(0x62),
- 0x1D436 => array(0x63),
- 0x1D437 => array(0x64),
- 0x1D438 => array(0x65),
- 0x1D439 => array(0x66),
- 0x1D43A => array(0x67),
- 0x1D43B => array(0x68),
- 0x1D43C => array(0x69),
- 0x1D43D => array(0x6A),
- 0x1D43E => array(0x6B),
- 0x1D43F => array(0x6C),
- 0x1D440 => array(0x6D),
- 0x1D441 => array(0x6E),
- 0x1D442 => array(0x6F),
- 0x1D443 => array(0x70),
- 0x1D444 => array(0x71),
- 0x1D445 => array(0x72),
- 0x1D446 => array(0x73),
- 0x1D447 => array(0x74),
- 0x1D448 => array(0x75),
- 0x1D449 => array(0x76),
- 0x1D44A => array(0x77),
- 0x1D44B => array(0x78),
- 0x1D44C => array(0x79),
- 0x1D44D => array(0x7A),
- 0x1D468 => array(0x61),
- 0x1D469 => array(0x62),
- 0x1D46A => array(0x63),
- 0x1D46B => array(0x64),
- 0x1D46C => array(0x65),
- 0x1D46D => array(0x66),
- 0x1D46E => array(0x67),
- 0x1D46F => array(0x68),
- 0x1D470 => array(0x69),
- 0x1D471 => array(0x6A),
- 0x1D472 => array(0x6B),
- 0x1D473 => array(0x6C),
- 0x1D474 => array(0x6D),
- 0x1D475 => array(0x6E),
- 0x1D476 => array(0x6F),
- 0x1D477 => array(0x70),
- 0x1D478 => array(0x71),
- 0x1D479 => array(0x72),
- 0x1D47A => array(0x73),
- 0x1D47B => array(0x74),
- 0x1D47C => array(0x75),
- 0x1D47D => array(0x76),
- 0x1D47E => array(0x77),
- 0x1D47F => array(0x78),
- 0x1D480 => array(0x79),
- 0x1D481 => array(0x7A),
- 0x1D49C => array(0x61),
- 0x1D49E => array(0x63),
- 0x1D49F => array(0x64),
- 0x1D4A2 => array(0x67),
- 0x1D4A5 => array(0x6A),
- 0x1D4A6 => array(0x6B),
- 0x1D4A9 => array(0x6E),
- 0x1D4AA => array(0x6F),
- 0x1D4AB => array(0x70),
- 0x1D4AC => array(0x71),
- 0x1D4AE => array(0x73),
- 0x1D4AF => array(0x74),
- 0x1D4B0 => array(0x75),
- 0x1D4B1 => array(0x76),
- 0x1D4B2 => array(0x77),
- 0x1D4B3 => array(0x78),
- 0x1D4B4 => array(0x79),
- 0x1D4B5 => array(0x7A),
- 0x1D4D0 => array(0x61),
- 0x1D4D1 => array(0x62),
- 0x1D4D2 => array(0x63),
- 0x1D4D3 => array(0x64),
- 0x1D4D4 => array(0x65),
- 0x1D4D5 => array(0x66),
- 0x1D4D6 => array(0x67),
- 0x1D4D7 => array(0x68),
- 0x1D4D8 => array(0x69),
- 0x1D4D9 => array(0x6A),
- 0x1D4DA => array(0x6B),
- 0x1D4DB => array(0x6C),
- 0x1D4DC => array(0x6D),
- 0x1D4DD => array(0x6E),
- 0x1D4DE => array(0x6F),
- 0x1D4DF => array(0x70),
- 0x1D4E0 => array(0x71),
- 0x1D4E1 => array(0x72),
- 0x1D4E2 => array(0x73),
- 0x1D4E3 => array(0x74),
- 0x1D4E4 => array(0x75),
- 0x1D4E5 => array(0x76),
- 0x1D4E6 => array(0x77),
- 0x1D4E7 => array(0x78),
- 0x1D4E8 => array(0x79),
- 0x1D4E9 => array(0x7A),
- 0x1D504 => array(0x61),
- 0x1D505 => array(0x62),
- 0x1D507 => array(0x64),
- 0x1D508 => array(0x65),
- 0x1D509 => array(0x66),
- 0x1D50A => array(0x67),
- 0x1D50D => array(0x6A),
- 0x1D50E => array(0x6B),
- 0x1D50F => array(0x6C),
- 0x1D510 => array(0x6D),
- 0x1D511 => array(0x6E),
- 0x1D512 => array(0x6F),
- 0x1D513 => array(0x70),
- 0x1D514 => array(0x71),
- 0x1D516 => array(0x73),
- 0x1D517 => array(0x74),
- 0x1D518 => array(0x75),
- 0x1D519 => array(0x76),
- 0x1D51A => array(0x77),
- 0x1D51B => array(0x78),
- 0x1D51C => array(0x79),
- 0x1D538 => array(0x61),
- 0x1D539 => array(0x62),
- 0x1D53B => array(0x64),
- 0x1D53C => array(0x65),
- 0x1D53D => array(0x66),
- 0x1D53E => array(0x67),
- 0x1D540 => array(0x69),
- 0x1D541 => array(0x6A),
- 0x1D542 => array(0x6B),
- 0x1D543 => array(0x6C),
- 0x1D544 => array(0x6D),
- 0x1D546 => array(0x6F),
- 0x1D54A => array(0x73),
- 0x1D54B => array(0x74),
- 0x1D54C => array(0x75),
- 0x1D54D => array(0x76),
- 0x1D54E => array(0x77),
- 0x1D54F => array(0x78),
- 0x1D550 => array(0x79),
- 0x1D56C => array(0x61),
- 0x1D56D => array(0x62),
- 0x1D56E => array(0x63),
- 0x1D56F => array(0x64),
- 0x1D570 => array(0x65),
- 0x1D571 => array(0x66),
- 0x1D572 => array(0x67),
- 0x1D573 => array(0x68),
- 0x1D574 => array(0x69),
- 0x1D575 => array(0x6A),
- 0x1D576 => array(0x6B),
- 0x1D577 => array(0x6C),
- 0x1D578 => array(0x6D),
- 0x1D579 => array(0x6E),
- 0x1D57A => array(0x6F),
- 0x1D57B => array(0x70),
- 0x1D57C => array(0x71),
- 0x1D57D => array(0x72),
- 0x1D57E => array(0x73),
- 0x1D57F => array(0x74),
- 0x1D580 => array(0x75),
- 0x1D581 => array(0x76),
- 0x1D582 => array(0x77),
- 0x1D583 => array(0x78),
- 0x1D584 => array(0x79),
- 0x1D585 => array(0x7A),
- 0x1D5A0 => array(0x61),
- 0x1D5A1 => array(0x62),
- 0x1D5A2 => array(0x63),
- 0x1D5A3 => array(0x64),
- 0x1D5A4 => array(0x65),
- 0x1D5A5 => array(0x66),
- 0x1D5A6 => array(0x67),
- 0x1D5A7 => array(0x68),
- 0x1D5A8 => array(0x69),
- 0x1D5A9 => array(0x6A),
- 0x1D5AA => array(0x6B),
- 0x1D5AB => array(0x6C),
- 0x1D5AC => array(0x6D),
- 0x1D5AD => array(0x6E),
- 0x1D5AE => array(0x6F),
- 0x1D5AF => array(0x70),
- 0x1D5B0 => array(0x71),
- 0x1D5B1 => array(0x72),
- 0x1D5B2 => array(0x73),
- 0x1D5B3 => array(0x74),
- 0x1D5B4 => array(0x75),
- 0x1D5B5 => array(0x76),
- 0x1D5B6 => array(0x77),
- 0x1D5B7 => array(0x78),
- 0x1D5B8 => array(0x79),
- 0x1D5B9 => array(0x7A),
- 0x1D5D4 => array(0x61),
- 0x1D5D5 => array(0x62),
- 0x1D5D6 => array(0x63),
- 0x1D5D7 => array(0x64),
- 0x1D5D8 => array(0x65),
- 0x1D5D9 => array(0x66),
- 0x1D5DA => array(0x67),
- 0x1D5DB => array(0x68),
- 0x1D5DC => array(0x69),
- 0x1D5DD => array(0x6A),
- 0x1D5DE => array(0x6B),
- 0x1D5DF => array(0x6C),
- 0x1D5E0 => array(0x6D),
- 0x1D5E1 => array(0x6E),
- 0x1D5E2 => array(0x6F),
- 0x1D5E3 => array(0x70),
- 0x1D5E4 => array(0x71),
- 0x1D5E5 => array(0x72),
- 0x1D5E6 => array(0x73),
- 0x1D5E7 => array(0x74),
- 0x1D5E8 => array(0x75),
- 0x1D5E9 => array(0x76),
- 0x1D5EA => array(0x77),
- 0x1D5EB => array(0x78),
- 0x1D5EC => array(0x79),
- 0x1D5ED => array(0x7A),
- 0x1D608 => array(0x61),
- 0x1D609 => array(0x62),
- 0x1D60A => array(0x63),
- 0x1D60B => array(0x64),
- 0x1D60C => array(0x65),
- 0x1D60D => array(0x66),
- 0x1D60E => array(0x67),
- 0x1D60F => array(0x68),
- 0x1D610 => array(0x69),
- 0x1D611 => array(0x6A),
- 0x1D612 => array(0x6B),
- 0x1D613 => array(0x6C),
- 0x1D614 => array(0x6D),
- 0x1D615 => array(0x6E),
- 0x1D616 => array(0x6F),
- 0x1D617 => array(0x70),
- 0x1D618 => array(0x71),
- 0x1D619 => array(0x72),
- 0x1D61A => array(0x73),
- 0x1D61B => array(0x74),
- 0x1D61C => array(0x75),
- 0x1D61D => array(0x76),
- 0x1D61E => array(0x77),
- 0x1D61F => array(0x78),
- 0x1D620 => array(0x79),
- 0x1D621 => array(0x7A),
- 0x1D63C => array(0x61),
- 0x1D63D => array(0x62),
- 0x1D63E => array(0x63),
- 0x1D63F => array(0x64),
- 0x1D640 => array(0x65),
- 0x1D641 => array(0x66),
- 0x1D642 => array(0x67),
- 0x1D643 => array(0x68),
- 0x1D644 => array(0x69),
- 0x1D645 => array(0x6A),
- 0x1D646 => array(0x6B),
- 0x1D647 => array(0x6C),
- 0x1D648 => array(0x6D),
- 0x1D649 => array(0x6E),
- 0x1D64A => array(0x6F),
- 0x1D64B => array(0x70),
- 0x1D64C => array(0x71),
- 0x1D64D => array(0x72),
- 0x1D64E => array(0x73),
- 0x1D64F => array(0x74),
- 0x1D650 => array(0x75),
- 0x1D651 => array(0x76),
- 0x1D652 => array(0x77),
- 0x1D653 => array(0x78),
- 0x1D654 => array(0x79),
- 0x1D655 => array(0x7A),
- 0x1D670 => array(0x61),
- 0x1D671 => array(0x62),
- 0x1D672 => array(0x63),
- 0x1D673 => array(0x64),
- 0x1D674 => array(0x65),
- 0x1D675 => array(0x66),
- 0x1D676 => array(0x67),
- 0x1D677 => array(0x68),
- 0x1D678 => array(0x69),
- 0x1D679 => array(0x6A),
- 0x1D67A => array(0x6B),
- 0x1D67B => array(0x6C),
- 0x1D67C => array(0x6D),
- 0x1D67D => array(0x6E),
- 0x1D67E => array(0x6F),
- 0x1D67F => array(0x70),
- 0x1D680 => array(0x71),
- 0x1D681 => array(0x72),
- 0x1D682 => array(0x73),
- 0x1D683 => array(0x74),
- 0x1D684 => array(0x75),
- 0x1D685 => array(0x76),
- 0x1D686 => array(0x77),
- 0x1D687 => array(0x78),
- 0x1D688 => array(0x79),
- 0x1D689 => array(0x7A),
- 0x1D6A8 => array(0x3B1),
- 0x1D6A9 => array(0x3B2),
- 0x1D6AA => array(0x3B3),
- 0x1D6AB => array(0x3B4),
- 0x1D6AC => array(0x3B5),
- 0x1D6AD => array(0x3B6),
- 0x1D6AE => array(0x3B7),
- 0x1D6AF => array(0x3B8),
- 0x1D6B0 => array(0x3B9),
- 0x1D6B1 => array(0x3BA),
- 0x1D6B2 => array(0x3BB),
- 0x1D6B3 => array(0x3BC),
- 0x1D6B4 => array(0x3BD),
- 0x1D6B5 => array(0x3BE),
- 0x1D6B6 => array(0x3BF),
- 0x1D6B7 => array(0x3C0),
- 0x1D6B8 => array(0x3C1),
- 0x1D6B9 => array(0x3B8),
- 0x1D6BA => array(0x3C3),
- 0x1D6BB => array(0x3C4),
- 0x1D6BC => array(0x3C5),
- 0x1D6BD => array(0x3C6),
- 0x1D6BE => array(0x3C7),
- 0x1D6BF => array(0x3C8),
- 0x1D6C0 => array(0x3C9),
- 0x1D6D3 => array(0x3C3),
- 0x1D6E2 => array(0x3B1),
- 0x1D6E3 => array(0x3B2),
- 0x1D6E4 => array(0x3B3),
- 0x1D6E5 => array(0x3B4),
- 0x1D6E6 => array(0x3B5),
- 0x1D6E7 => array(0x3B6),
- 0x1D6E8 => array(0x3B7),
- 0x1D6E9 => array(0x3B8),
- 0x1D6EA => array(0x3B9),
- 0x1D6EB => array(0x3BA),
- 0x1D6EC => array(0x3BB),
- 0x1D6ED => array(0x3BC),
- 0x1D6EE => array(0x3BD),
- 0x1D6EF => array(0x3BE),
- 0x1D6F0 => array(0x3BF),
- 0x1D6F1 => array(0x3C0),
- 0x1D6F2 => array(0x3C1),
- 0x1D6F3 => array(0x3B8),
- 0x1D6F4 => array(0x3C3),
- 0x1D6F5 => array(0x3C4),
- 0x1D6F6 => array(0x3C5),
- 0x1D6F7 => array(0x3C6),
- 0x1D6F8 => array(0x3C7),
- 0x1D6F9 => array(0x3C8),
- 0x1D6FA => array(0x3C9),
- 0x1D70D => array(0x3C3),
- 0x1D71C => array(0x3B1),
- 0x1D71D => array(0x3B2),
- 0x1D71E => array(0x3B3),
- 0x1D71F => array(0x3B4),
- 0x1D720 => array(0x3B5),
- 0x1D721 => array(0x3B6),
- 0x1D722 => array(0x3B7),
- 0x1D723 => array(0x3B8),
- 0x1D724 => array(0x3B9),
- 0x1D725 => array(0x3BA),
- 0x1D726 => array(0x3BB),
- 0x1D727 => array(0x3BC),
- 0x1D728 => array(0x3BD),
- 0x1D729 => array(0x3BE),
- 0x1D72A => array(0x3BF),
- 0x1D72B => array(0x3C0),
- 0x1D72C => array(0x3C1),
- 0x1D72D => array(0x3B8),
- 0x1D72E => array(0x3C3),
- 0x1D72F => array(0x3C4),
- 0x1D730 => array(0x3C5),
- 0x1D731 => array(0x3C6),
- 0x1D732 => array(0x3C7),
- 0x1D733 => array(0x3C8),
- 0x1D734 => array(0x3C9),
- 0x1D747 => array(0x3C3),
- 0x1D756 => array(0x3B1),
- 0x1D757 => array(0x3B2),
- 0x1D758 => array(0x3B3),
- 0x1D759 => array(0x3B4),
- 0x1D75A => array(0x3B5),
- 0x1D75B => array(0x3B6),
- 0x1D75C => array(0x3B7),
- 0x1D75D => array(0x3B8),
- 0x1D75E => array(0x3B9),
- 0x1D75F => array(0x3BA),
- 0x1D760 => array(0x3BB),
- 0x1D761 => array(0x3BC),
- 0x1D762 => array(0x3BD),
- 0x1D763 => array(0x3BE),
- 0x1D764 => array(0x3BF),
- 0x1D765 => array(0x3C0),
- 0x1D766 => array(0x3C1),
- 0x1D767 => array(0x3B8),
- 0x1D768 => array(0x3C3),
- 0x1D769 => array(0x3C4),
- 0x1D76A => array(0x3C5),
- 0x1D76B => array(0x3C6),
- 0x1D76C => array(0x3C7),
- 0x1D76D => array(0x3C8),
- 0x1D76E => array(0x3C9),
- 0x1D781 => array(0x3C3),
- 0x1D790 => array(0x3B1),
- 0x1D791 => array(0x3B2),
- 0x1D792 => array(0x3B3),
- 0x1D793 => array(0x3B4),
- 0x1D794 => array(0x3B5),
- 0x1D795 => array(0x3B6),
- 0x1D796 => array(0x3B7),
- 0x1D797 => array(0x3B8),
- 0x1D798 => array(0x3B9),
- 0x1D799 => array(0x3BA),
- 0x1D79A => array(0x3BB),
- 0x1D79B => array(0x3BC),
- 0x1D79C => array(0x3BD),
- 0x1D79D => array(0x3BE),
- 0x1D79E => array(0x3BF),
- 0x1D79F => array(0x3C0),
- 0x1D7A0 => array(0x3C1),
- 0x1D7A1 => array(0x3B8),
- 0x1D7A2 => array(0x3C3),
- 0x1D7A3 => array(0x3C4),
- 0x1D7A4 => array(0x3C5),
- 0x1D7A5 => array(0x3C6),
- 0x1D7A6 => array(0x3C7),
- 0x1D7A7 => array(0x3C8),
- 0x1D7A8 => array(0x3C9),
- 0x1D7BB => array(0x3C3),
- 0x3F9 => array(0x3C3),
- 0x1D2C => array(0x61),
- 0x1D2D => array(0xE6),
- 0x1D2E => array(0x62),
- 0x1D30 => array(0x64),
- 0x1D31 => array(0x65),
- 0x1D32 => array(0x1DD),
- 0x1D33 => array(0x67),
- 0x1D34 => array(0x68),
- 0x1D35 => array(0x69),
- 0x1D36 => array(0x6A),
- 0x1D37 => array(0x6B),
- 0x1D38 => array(0x6C),
- 0x1D39 => array(0x6D),
- 0x1D3A => array(0x6E),
- 0x1D3C => array(0x6F),
- 0x1D3D => array(0x223),
- 0x1D3E => array(0x70),
- 0x1D3F => array(0x72),
- 0x1D40 => array(0x74),
- 0x1D41 => array(0x75),
- 0x1D42 => array(0x77),
- 0x213B => array(0x66, 0x61, 0x78),
- 0x3250 => array(0x70, 0x74, 0x65),
- 0x32CC => array(0x68, 0x67),
- 0x32CE => array(0x65, 0x76),
- 0x32CF => array(0x6C, 0x74, 0x64),
- 0x337A => array(0x69, 0x75),
- 0x33DE => array(0x76, 0x2215, 0x6D),
- 0x33DF => array(0x61, 0x2215, 0x6D)
- );
-
- /**
- * Normalization Combining Classes; Code Points not listed
- * got Combining Class 0.
- *
- * @static
- * @var array
- * @access private
- */
- private static $_np_norm_combcls = array(
- 0x334 => 1,
- 0x335 => 1,
- 0x336 => 1,
- 0x337 => 1,
- 0x338 => 1,
- 0x93C => 7,
- 0x9BC => 7,
- 0xA3C => 7,
- 0xABC => 7,
- 0xB3C => 7,
- 0xCBC => 7,
- 0x1037 => 7,
- 0x3099 => 8,
- 0x309A => 8,
- 0x94D => 9,
- 0x9CD => 9,
- 0xA4D => 9,
- 0xACD => 9,
- 0xB4D => 9,
- 0xBCD => 9,
- 0xC4D => 9,
- 0xCCD => 9,
- 0xD4D => 9,
- 0xDCA => 9,
- 0xE3A => 9,
- 0xF84 => 9,
- 0x1039 => 9,
- 0x1714 => 9,
- 0x1734 => 9,
- 0x17D2 => 9,
- 0x5B0 => 10,
- 0x5B1 => 11,
- 0x5B2 => 12,
- 0x5B3 => 13,
- 0x5B4 => 14,
- 0x5B5 => 15,
- 0x5B6 => 16,
- 0x5B7 => 17,
- 0x5B8 => 18,
- 0x5B9 => 19,
- 0x5BB => 20,
- 0x5Bc => 21,
- 0x5BD => 22,
- 0x5BF => 23,
- 0x5C1 => 24,
- 0x5C2 => 25,
- 0xFB1E => 26,
- 0x64B => 27,
- 0x64C => 28,
- 0x64D => 29,
- 0x64E => 30,
- 0x64F => 31,
- 0x650 => 32,
- 0x651 => 33,
- 0x652 => 34,
- 0x670 => 35,
- 0x711 => 36,
- 0xC55 => 84,
- 0xC56 => 91,
- 0xE38 => 103,
- 0xE39 => 103,
- 0xE48 => 107,
- 0xE49 => 107,
- 0xE4A => 107,
- 0xE4B => 107,
- 0xEB8 => 118,
- 0xEB9 => 118,
- 0xEC8 => 122,
- 0xEC9 => 122,
- 0xECA => 122,
- 0xECB => 122,
- 0xF71 => 129,
- 0xF72 => 130,
- 0xF7A => 130,
- 0xF7B => 130,
- 0xF7C => 130,
- 0xF7D => 130,
- 0xF80 => 130,
- 0xF74 => 132,
- 0x321 => 202,
- 0x322 => 202,
- 0x327 => 202,
- 0x328 => 202,
- 0x31B => 216,
- 0xF39 => 216,
- 0x1D165 => 216,
- 0x1D166 => 216,
- 0x1D16E => 216,
- 0x1D16F => 216,
- 0x1D170 => 216,
- 0x1D171 => 216,
- 0x1D172 => 216,
- 0x302A => 218,
- 0x316 => 220,
- 0x317 => 220,
- 0x318 => 220,
- 0x319 => 220,
- 0x31C => 220,
- 0x31D => 220,
- 0x31E => 220,
- 0x31F => 220,
- 0x320 => 220,
- 0x323 => 220,
- 0x324 => 220,
- 0x325 => 220,
- 0x326 => 220,
- 0x329 => 220,
- 0x32A => 220,
- 0x32B => 220,
- 0x32C => 220,
- 0x32D => 220,
- 0x32E => 220,
- 0x32F => 220,
- 0x330 => 220,
- 0x331 => 220,
- 0x332 => 220,
- 0x333 => 220,
- 0x339 => 220,
- 0x33A => 220,
- 0x33B => 220,
- 0x33C => 220,
- 0x347 => 220,
- 0x348 => 220,
- 0x349 => 220,
- 0x34D => 220,
- 0x34E => 220,
- 0x353 => 220,
- 0x354 => 220,
- 0x355 => 220,
- 0x356 => 220,
- 0x591 => 220,
- 0x596 => 220,
- 0x59B => 220,
- 0x5A3 => 220,
- 0x5A4 => 220,
- 0x5A5 => 220,
- 0x5A6 => 220,
- 0x5A7 => 220,
- 0x5AA => 220,
- 0x655 => 220,
- 0x656 => 220,
- 0x6E3 => 220,
- 0x6EA => 220,
- 0x6ED => 220,
- 0x731 => 220,
- 0x734 => 220,
- 0x737 => 220,
- 0x738 => 220,
- 0x739 => 220,
- 0x73B => 220,
- 0x73C => 220,
- 0x73E => 220,
- 0x742 => 220,
- 0x744 => 220,
- 0x746 => 220,
- 0x748 => 220,
- 0x952 => 220,
- 0xF18 => 220,
- 0xF19 => 220,
- 0xF35 => 220,
- 0xF37 => 220,
- 0xFC6 => 220,
- 0x193B => 220,
- 0x20E8 => 220,
- 0x1D17B => 220,
- 0x1D17C => 220,
- 0x1D17D => 220,
- 0x1D17E => 220,
- 0x1D17F => 220,
- 0x1D180 => 220,
- 0x1D181 => 220,
- 0x1D182 => 220,
- 0x1D18A => 220,
- 0x1D18B => 220,
- 0x59A => 222,
- 0x5AD => 222,
- 0x1929 => 222,
- 0x302D => 222,
- 0x302E => 224,
- 0x302F => 224,
- 0x1D16D => 226,
- 0x5AE => 228,
- 0x18A9 => 228,
- 0x302B => 228,
- 0x300 => 230,
- 0x301 => 230,
- 0x302 => 230,
- 0x303 => 230,
- 0x304 => 230,
- 0x305 => 230,
- 0x306 => 230,
- 0x307 => 230,
- 0x308 => 230,
- 0x309 => 230,
- 0x30A => 230,
- 0x30B => 230,
- 0x30C => 230,
- 0x30D => 230,
- 0x30E => 230,
- 0x30F => 230,
- 0x310 => 230,
- 0x311 => 230,
- 0x312 => 230,
- 0x313 => 230,
- 0x314 => 230,
- 0x33D => 230,
- 0x33E => 230,
- 0x33F => 230,
- 0x340 => 230,
- 0x341 => 230,
- 0x342 => 230,
- 0x343 => 230,
- 0x344 => 230,
- 0x346 => 230,
- 0x34A => 230,
- 0x34B => 230,
- 0x34C => 230,
- 0x350 => 230,
- 0x351 => 230,
- 0x352 => 230,
- 0x357 => 230,
- 0x363 => 230,
- 0x364 => 230,
- 0x365 => 230,
- 0x366 => 230,
- 0x367 => 230,
- 0x368 => 230,
- 0x369 => 230,
- 0x36A => 230,
- 0x36B => 230,
- 0x36C => 230,
- 0x36D => 230,
- 0x36E => 230,
- 0x36F => 230,
- 0x483 => 230,
- 0x484 => 230,
- 0x485 => 230,
- 0x486 => 230,
- 0x592 => 230,
- 0x593 => 230,
- 0x594 => 230,
- 0x595 => 230,
- 0x597 => 230,
- 0x598 => 230,
- 0x599 => 230,
- 0x59C => 230,
- 0x59D => 230,
- 0x59E => 230,
- 0x59F => 230,
- 0x5A0 => 230,
- 0x5A1 => 230,
- 0x5A8 => 230,
- 0x5A9 => 230,
- 0x5AB => 230,
- 0x5AC => 230,
- 0x5AF => 230,
- 0x5C4 => 230,
- 0x610 => 230,
- 0x611 => 230,
- 0x612 => 230,
- 0x613 => 230,
- 0x614 => 230,
- 0x615 => 230,
- 0x653 => 230,
- 0x654 => 230,
- 0x657 => 230,
- 0x658 => 230,
- 0x6D6 => 230,
- 0x6D7 => 230,
- 0x6D8 => 230,
- 0x6D9 => 230,
- 0x6DA => 230,
- 0x6DB => 230,
- 0x6DC => 230,
- 0x6DF => 230,
- 0x6E0 => 230,
- 0x6E1 => 230,
- 0x6E2 => 230,
- 0x6E4 => 230,
- 0x6E7 => 230,
- 0x6E8 => 230,
- 0x6EB => 230,
- 0x6EC => 230,
- 0x730 => 230,
- 0x732 => 230,
- 0x733 => 230,
- 0x735 => 230,
- 0x736 => 230,
- 0x73A => 230,
- 0x73D => 230,
- 0x73F => 230,
- 0x740 => 230,
- 0x741 => 230,
- 0x743 => 230,
- 0x745 => 230,
- 0x747 => 230,
- 0x749 => 230,
- 0x74A => 230,
- 0x951 => 230,
- 0x953 => 230,
- 0x954 => 230,
- 0xF82 => 230,
- 0xF83 => 230,
- 0xF86 => 230,
- 0xF87 => 230,
- 0x170D => 230,
- 0x193A => 230,
- 0x20D0 => 230,
- 0x20D1 => 230,
- 0x20D4 => 230,
- 0x20D5 => 230,
- 0x20D6 => 230,
- 0x20D7 => 230,
- 0x20DB => 230,
- 0x20DC => 230,
- 0x20E1 => 230,
- 0x20E7 => 230,
- 0x20E9 => 230,
- 0xFE20 => 230,
- 0xFE21 => 230,
- 0xFE22 => 230,
- 0xFE23 => 230,
- 0x1D185 => 230,
- 0x1D186 => 230,
- 0x1D187 => 230,
- 0x1D189 => 230,
- 0x1D188 => 230,
- 0x1D1AA => 230,
- 0x1D1AB => 230,
- 0x1D1AC => 230,
- 0x1D1AD => 230,
- 0x315 => 232,
- 0x31A => 232,
- 0x302C => 232,
- 0x35F => 233,
- 0x362 => 233,
- 0x35D => 234,
- 0x35E => 234,
- 0x360 => 234,
- 0x361 => 234,
- 0x345 => 240
- );
- // }}}
-
- // {{{ properties
- /**
- * @var string
- * @access private
- */
- private $_punycode_prefix = 'xn--';
-
- /**
- * @access private
- */
- private $_invalid_ucs = 0x80000000;
-
- /**
- * @access private
- */
- private $_max_ucs = 0x10FFFF;
-
- /**
- * @var int
- * @access private
- */
- private $_base = 36;
-
- /**
- * @var int
- * @access private
- */
- private $_tmin = 1;
-
- /**
- * @var int
- * @access private
- */
- private $_tmax = 26;
-
- /**
- * @var int
- * @access private
- */
- private $_skew = 38;
-
- /**
- * @var int
- * @access private
- */
- private $_damp = 700;
-
- /**
- * @var int
- * @access private
- */
- private $_initial_bias = 72;
-
- /**
- * @var int
- * @access private
- */
- private $_initial_n = 0x80;
-
- /**
- * @var int
- * @access private
- */
- private $_slast;
-
- /**
- * @access private
- */
- private $_sbase = 0xAC00;
-
- /**
- * @access private
- */
- private $_lbase = 0x1100;
-
- /**
- * @access private
- */
- private $_vbase = 0x1161;
-
- /**
- * @access private
- */
- private $_tbase = 0x11a7;
-
- /**
- * @var int
- * @access private
- */
- private $_lcount = 19;
-
- /**
- * @var int
- * @access private
- */
- private $_vcount = 21;
-
- /**
- * @var int
- * @access private
- */
- private $_tcount = 28;
-
- /**
- * vcount * tcount
- *
- * @var int
- * @access private
- */
- private $_ncount = 588;
-
- /**
- * lcount * tcount * vcount
- *
- * @var int
- * @access private
- */
- private $_scount = 11172;
-
- /**
- * Default encoding for encode()'s input and decode()'s output is UTF-8;
- * Other possible encodings are ucs4_string and ucs4_array
- * See {@link setParams()} for how to select these
- *
- * @var bool
- * @access private
- */
- private $_api_encoding = 'utf8';
-
- /**
- * Overlong UTF-8 encodings are forbidden
- *
- * @var bool
- * @access private
- */
- private $_allow_overlong = false;
-
- /**
- * Behave strict or not
- *
- * @var bool
- * @access private
- */
- private $_strict_mode = false;
-
- /**
- * IDNA-version to use
- *
- * Values are "2003" and "2008".
- * Defaults to "2003", since that was the original version and for
- * compatibility with previous versions of this library.
- * If you need to encode "new" characters like the German "Eszett",
- * please switch to 2008 first before encoding.
- *
- * @var bool
- * @access private
- */
- private $_version = '2003';
-
- /**
- * Cached value indicating whether or not mbstring function overloading is
- * on for strlen
- *
- * This is cached for optimal performance.
- *
- * @var boolean
- * @see Net_IDNA2::_byteLength()
- */
- private static $_mb_string_overload = null;
- // }}}
-
-
- // {{{ constructor
- /**
- * Constructor
- *
- * @param array $options Options to initialise the object with
- *
- * @access public
- * @see setParams()
- */
- public function __construct($options = null)
- {
- $this->_slast = $this->_sbase + $this->_lcount * $this->_vcount * $this->_tcount;
-
- if (is_array($options)) {
- $this->setParams($options);
- }
-
- // populate mbstring overloading cache if not set
- if (self::$_mb_string_overload === null) {
- self::$_mb_string_overload = (extension_loaded('mbstring')
- && (ini_get('mbstring.func_overload') & 0x02) === 0x02);
- }
- }
- // }}}
-
-
- /**
- * Sets a new option value. Available options and values:
- *
- * [utf8 - Use either UTF-8 or ISO-8859-1 as input (true for UTF-8, false
- * otherwise); The output is always UTF-8]
- * [overlong - Unicode does not allow unnecessarily long encodings of chars,
- * to allow this, set this parameter to true, else to false;
- * default is false.]
- * [strict - true: strict mode, good for registration purposes - Causes errors
- * on failures; false: loose mode, ideal for "wildlife" applications
- * by silently ignoring errors and returning the original input instead]
- *
- * @param mixed $option Parameter to set (string: single parameter; array of Parameter => Value pairs)
- * @param string $value Value to use (if parameter 1 is a string)
- *
- * @return boolean true on success, false otherwise
- * @access public
- */
- public function setParams($option, $value = false)
- {
- if (!is_array($option)) {
- $option = array($option => $value);
- }
-
- foreach ($option as $k => $v) {
- switch ($k) {
- case 'encoding':
- switch ($v) {
- case 'utf8':
- case 'ucs4_string':
- case 'ucs4_array':
- $this->_api_encoding = $v;
- break;
-
- default:
- throw new InvalidArgumentException('Set Parameter: Unknown parameter '.$v.' for option '.$k);
- }
-
- break;
-
- case 'overlong':
- $this->_allow_overlong = ($v) ? true : false;
- break;
-
- case 'strict':
- $this->_strict_mode = ($v) ? true : false;
- break;
-
- case 'version':
- if (in_array($v, array('2003', '2008'))) {
- $this->_version = $v;
- } else {
- throw new InvalidArgumentException('Set Parameter: Invalid parameter '.$v.' for option '.$k);
- }
- break;
-
- default:
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Encode a given UTF-8 domain name.
- *
- * @param string $decoded Domain name (UTF-8 or UCS-4)
- * @param string $one_time_encoding Desired input encoding, see {@link set_parameter}
- * If not given will use default-encoding
- *
- * @return string Encoded Domain name (ACE string)
- * @return mixed processed string
- * @throws Exception
- * @access public
- */
- public function encode($decoded, $one_time_encoding = false)
- {
- // Forcing conversion of input to UCS4 array
- // If one time encoding is given, use this, else the objects property
- switch (($one_time_encoding) ? $one_time_encoding : $this->_api_encoding) {
- case 'utf8':
- $decoded = $this->_utf8_to_ucs4($decoded);
- break;
- case 'ucs4_string':
- $decoded = $this->_ucs4_string_to_ucs4($decoded);
- case 'ucs4_array': // No break; before this line. Catch case, but do nothing
- break;
- default:
- throw new InvalidArgumentException('Unsupported input format');
- }
-
- // No input, no output, what else did you expect?
- if (empty($decoded)) return '';
-
- // Anchors for iteration
- $last_begin = 0;
- // Output string
- $output = '';
-
- foreach ($decoded as $k => $v) {
- // Make sure to use just the plain dot
- switch($v) {
- case 0x3002:
- case 0xFF0E:
- case 0xFF61:
- $decoded[$k] = 0x2E;
- // It's right, no break here
- // The codepoints above have to be converted to dots anyway
-
- // Stumbling across an anchoring character
- case 0x2E:
- case 0x2F:
- case 0x3A:
- case 0x3F:
- case 0x40:
- // Neither email addresses nor URLs allowed in strict mode
- if ($this->_strict_mode) {
- throw new InvalidArgumentException('Neither email addresses nor URLs are allowed in strict mode.');
- }
- // Skip first char
- if ($k) {
- $encoded = '';
- $encoded = $this->_encode(array_slice($decoded, $last_begin, (($k)-$last_begin)));
- if ($encoded) {
- $output .= $encoded;
- } else {
- $output .= $this->_ucs4_to_utf8(array_slice($decoded, $last_begin, (($k)-$last_begin)));
- }
- $output .= chr($decoded[$k]);
- }
- $last_begin = $k + 1;
- }
- }
- // Catch the rest of the string
- if ($last_begin) {
- $inp_len = sizeof($decoded);
- $encoded = '';
- $encoded = $this->_encode(array_slice($decoded, $last_begin, (($inp_len)-$last_begin)));
- if ($encoded) {
- $output .= $encoded;
- } else {
- $output .= $this->_ucs4_to_utf8(array_slice($decoded, $last_begin, (($inp_len)-$last_begin)));
- }
- return $output;
- }
-
- if ($output = $this->_encode($decoded)) {
- return $output;
- }
-
- return $this->_ucs4_to_utf8($decoded);
- }
-
- /**
- * Decode a given ACE domain name.
- *
- * @param string $input Domain name (ACE string)
- * @param string $one_time_encoding Desired output encoding, see {@link set_parameter}
- *
- * @return string Decoded Domain name (UTF-8 or UCS-4)
- * @throws Exception
- * @access public
- */
- public function decode($input, $one_time_encoding = false)
- {
- // Optionally set
- if ($one_time_encoding) {
- switch ($one_time_encoding) {
- case 'utf8':
- case 'ucs4_string':
- case 'ucs4_array':
- break;
- default:
- throw new InvalidArgumentException('Unknown encoding '.$one_time_encoding);
- }
- }
- // Make sure to drop any newline characters around
- $input = trim($input);
-
- // Negotiate input and try to determine, wether it is a plain string,
- // an email address or something like a complete URL
- if (strpos($input, '@')) { // Maybe it is an email address
- // No no in strict mode
- if ($this->_strict_mode) {
- throw new InvalidArgumentException('Only simple domain name parts can be handled in strict mode');
- }
- list($email_pref, $input) = explode('@', $input, 2);
- $arr = explode('.', $input);
- foreach ($arr as $k => $v) {
- $conv = $this->_decode($v);
- if ($conv) $arr[$k] = $conv;
- }
- $return = $email_pref . '@' . join('.', $arr);
- } elseif (preg_match('![:\./]!', $input)) { // Or a complete domain name (with or without paths / parameters)
- // No no in strict mode
- if ($this->_strict_mode) {
- throw new InvalidArgumentException('Only simple domain name parts can be handled in strict mode');
- }
-
- $parsed = parse_url($input);
- if (isset($parsed['host'])) {
- $arr = explode('.', $parsed['host']);
- foreach ($arr as $k => $v) {
- $conv = $this->_decode($v);
- if ($conv) $arr[$k] = $conv;
- }
- $parsed['host'] = join('.', $arr);
- if (isset($parsed['scheme'])) {
- $parsed['scheme'] .= (strtolower($parsed['scheme']) == 'mailto') ? ':' : '://';
- }
- $return = $this->_unparse_url($parsed);
- } else { // parse_url seems to have failed, try without it
- $arr = explode('.', $input);
- foreach ($arr as $k => $v) {
- $conv = $this->_decode($v);
- if ($conv) $arr[$k] = $conv;
- }
- $return = join('.', $arr);
- }
- } else { // Otherwise we consider it being a pure domain name string
- $return = $this->_decode($input);
- }
- // The output is UTF-8 by default, other output formats need conversion here
- // If one time encoding is given, use this, else the objects property
- switch (($one_time_encoding) ? $one_time_encoding : $this->_api_encoding) {
- case 'utf8':
- return $return;
- break;
- case 'ucs4_string':
- return $this->_ucs4_to_ucs4_string($this->_utf8_to_ucs4($return));
- break;
- case 'ucs4_array':
- return $this->_utf8_to_ucs4($return);
- break;
- default:
- throw new InvalidArgumentException('Unsupported output format');
- }
- }
-
-
- // {{{ private
- /**
- * Opposite function to parse_url()
- *
- * Inspired by code from comments of php.net-documentation for parse_url()
- *
- * @param array $parts_arr parts (strings) as returned by parse_url()
- *
- * @return string
- * @access private
- */
- private function _unparse_url($parts_arr)
- {
- if (!empty($parts_arr['scheme'])) {
- $ret_url = $parts_arr['scheme'];
- }
- if (!empty($parts_arr['user'])) {
- $ret_url .= $parts_arr['user'];
- if (!empty($parts_arr['pass'])) {
- $ret_url .= ':' . $parts_arr['pass'];
- }
- $ret_url .= '@';
- }
- $ret_url .= $parts_arr['host'];
- if (!empty($parts_arr['port'])) {
- $ret_url .= ':' . $parts_arr['port'];
- }
- $ret_url .= $parts_arr['path'];
- if (!empty($parts_arr['query'])) {
- $ret_url .= '?' . $parts_arr['query'];
- }
- if (!empty($parts_arr['fragment'])) {
- $ret_url .= '#' . $parts_arr['fragment'];
- }
- return $ret_url;
- }
-
- /**
- * The actual encoding algorithm.
- *
- * @param string $decoded Decoded string which should be encoded
- *
- * @return string Encoded string
- * @throws Exception
- * @access private
- */
- private function _encode($decoded)
- {
- // We cannot encode a domain name containing the Punycode prefix
- $extract = self::_byteLength($this->_punycode_prefix);
- $check_pref = $this->_utf8_to_ucs4($this->_punycode_prefix);
- $check_deco = array_slice($decoded, 0, $extract);
-
- if ($check_pref == $check_deco) {
- throw new InvalidArgumentException('This is already a punycode string');
- }
-
- // We will not try to encode strings consisting of basic code points only
- $encodable = false;
- foreach ($decoded as $k => $v) {
- if ($v > 0x7a) {
- $encodable = true;
- break;
- }
- }
- if (!$encodable) {
- if ($this->_strict_mode) {
- throw new InvalidArgumentException('The given string does not contain encodable chars');
- }
-
- return false;
- }
-
- // Do NAMEPREP
- $decoded = $this->_nameprep($decoded);
-
- $deco_len = count($decoded);
-
- // Empty array
- if (!$deco_len) {
- return false;
- }
-
- // How many chars have been consumed
- $codecount = 0;
-
- // Start with the prefix; copy it to output
- $encoded = $this->_punycode_prefix;
-
- $encoded = '';
- // Copy all basic code points to output
- for ($i = 0; $i < $deco_len; ++$i) {
- $test = $decoded[$i];
- // Will match [0-9a-zA-Z-]
- if ((0x2F < $test && $test < 0x40)
- || (0x40 < $test && $test < 0x5B)
- || (0x60 < $test && $test <= 0x7B)
- || (0x2D == $test)
- ) {
- $encoded .= chr($decoded[$i]);
- $codecount++;
- }
- }
-
- // All codepoints were basic ones
- if ($codecount == $deco_len) {
- return $encoded;
- }
-
- // Start with the prefix; copy it to output
- $encoded = $this->_punycode_prefix . $encoded;
-
- // If we have basic code points in output, add an hyphen to the end
- if ($codecount) {
- $encoded .= '-';
- }
-
- // Now find and encode all non-basic code points
- $is_first = true;
- $cur_code = $this->_initial_n;
- $bias = $this->_initial_bias;
- $delta = 0;
-
- while ($codecount < $deco_len) {
- // Find the smallest code point >= the current code point and
- // remember the last ouccrence of it in the input
- for ($i = 0, $next_code = $this->_max_ucs; $i < $deco_len; $i++) {
- if ($decoded[$i] >= $cur_code && $decoded[$i] <= $next_code) {
- $next_code = $decoded[$i];
- }
- }
-
- $delta += ($next_code - $cur_code) * ($codecount + 1);
- $cur_code = $next_code;
-
- // Scan input again and encode all characters whose code point is $cur_code
- for ($i = 0; $i < $deco_len; $i++) {
- if ($decoded[$i] < $cur_code) {
- $delta++;
- } else if ($decoded[$i] == $cur_code) {
- for ($q = $delta, $k = $this->_base; 1; $k += $this->_base) {
- $t = ($k <= $bias)?
- $this->_tmin :
- (($k >= $bias + $this->_tmax)? $this->_tmax : $k - $bias);
-
- if ($q < $t) {
- break;
- }
-
- $encoded .= $this->_encodeDigit(ceil($t + (($q - $t) % ($this->_base - $t))));
- $q = ($q - $t) / ($this->_base - $t);
- }
-
- $encoded .= $this->_encodeDigit($q);
- $bias = $this->_adapt($delta, $codecount + 1, $is_first);
- $codecount++;
- $delta = 0;
- $is_first = false;
- }
- }
-
- $delta++;
- $cur_code++;
- }
-
- return $encoded;
- }
-
- /**
- * The actual decoding algorithm.
- *
- * @param string $encoded Encoded string which should be decoded
- *
- * @return string Decoded string
- * @throws Exception
- * @access private
- */
- private function _decode($encoded)
- {
- // We do need to find the Punycode prefix
- if (!preg_match('!^' . preg_quote($this->_punycode_prefix, '!') . '!', $encoded)) {
- return false;
- }
-
- $encode_test = preg_replace('!^' . preg_quote($this->_punycode_prefix, '!') . '!', '', $encoded);
-
- // If nothing left after removing the prefix, it is hopeless
- if (!$encode_test) {
- return false;
- }
-
- // Find last occurence of the delimiter
- $delim_pos = strrpos($encoded, '-');
-
- if ($delim_pos > self::_byteLength($this->_punycode_prefix)) {
- for ($k = self::_byteLength($this->_punycode_prefix); $k < $delim_pos; ++$k) {
- $decoded[] = ord($encoded{$k});
- }
- } else {
- $decoded = array();
- }
-
- $deco_len = count($decoded);
- $enco_len = self::_byteLength($encoded);
-
- // Wandering through the strings; init
- $is_first = true;
- $bias = $this->_initial_bias;
- $idx = 0;
- $char = $this->_initial_n;
-
- for ($enco_idx = ($delim_pos)? ($delim_pos + 1) : 0; $enco_idx < $enco_len; ++$deco_len) {
- for ($old_idx = $idx, $w = 1, $k = $this->_base; 1 ; $k += $this->_base) {
- $digit = $this->_decodeDigit($encoded{$enco_idx++});
- $idx += $digit * $w;
-
- $t = ($k <= $bias) ?
- $this->_tmin :
- (($k >= $bias + $this->_tmax)? $this->_tmax : ($k - $bias));
-
- if ($digit < $t) {
- break;
- }
-
- $w = (int)($w * ($this->_base - $t));
- }
-
- $bias = $this->_adapt($idx - $old_idx, $deco_len + 1, $is_first);
- $is_first = false;
- $char += (int) ($idx / ($deco_len + 1));
- $idx %= ($deco_len + 1);
-
- if ($deco_len > 0) {
- // Make room for the decoded char
- for ($i = $deco_len; $i > $idx; $i--) {
- $decoded[$i] = $decoded[($i - 1)];
- }
- }
-
- $decoded[$idx++] = $char;
- }
-
- return $this->_ucs4_to_utf8($decoded);
- }
-
- /**
- * Adapt the bias according to the current code point and position.
- *
- * @param int $delta ...
- * @param int $npoints ...
- * @param boolean $is_first ...
- *
- * @return int
- * @access private
- */
- private function _adapt($delta, $npoints, $is_first)
- {
- $delta = (int) ($is_first ? ($delta / $this->_damp) : ($delta / 2));
- $delta += (int) ($delta / $npoints);
-
- for ($k = 0; $delta > (($this->_base - $this->_tmin) * $this->_tmax) / 2; $k += $this->_base) {
- $delta = (int) ($delta / ($this->_base - $this->_tmin));
- }
-
- return (int) ($k + ($this->_base - $this->_tmin + 1) * $delta / ($delta + $this->_skew));
- }
-
- /**
- * Encoding a certain digit.
- *
- * @param int $d One digit to encode
- *
- * @return char Encoded digit
- * @access private
- */
- private function _encodeDigit($d)
- {
- return chr($d + 22 + 75 * ($d < 26));
- }
-
- /**
- * Decode a certain digit.
- *
- * @param char $cp One digit (character) to decode
- *
- * @return int Decoded digit
- * @access private
- */
- private function _decodeDigit($cp)
- {
- $cp = ord($cp);
- return ($cp - 48 < 10)? $cp - 22 : (($cp - 65 < 26)? $cp - 65 : (($cp - 97 < 26)? $cp - 97 : $this->_base));
- }
-
- /**
- * Do Nameprep according to RFC3491 and RFC3454.
- *
- * @param array $input Unicode Characters
- *
- * @return string Unicode Characters, Nameprep'd
- * @throws Exception
- * @access private
- */
- private function _nameprep($input)
- {
- $output = array();
-
- // Walking through the input array, performing the required steps on each of
- // the input chars and putting the result into the output array
- // While mapping required chars we apply the cannonical ordering
-
- foreach ($input as $v) {
- // Map to nothing == skip that code point
- if (in_array($v, self::$_np_map_nothing)) {
- continue;
- }
-
- // Try to find prohibited input
- if (in_array($v, self::$_np_prohibit) || in_array($v, self::$_general_prohibited)) {
- throw new Net_IDNA2_Exception_Nameprep('Prohibited input U+' . sprintf('%08X', $v));
- }
-
- foreach (self::$_np_prohibit_ranges as $range) {
- if ($range[0] <= $v && $v <= $range[1]) {
- throw new Net_IDNA2_Exception_Nameprep('Prohibited input U+' . sprintf('%08X', $v));
- }
- }
-
- // Hangul syllable decomposition
- if (0xAC00 <= $v && $v <= 0xD7AF) {
- foreach ($this->_hangulDecompose($v) as $out) {
- $output[] = $out;
- }
- } else if (($this->_version == '2003') && isset(self::$_np_replacemaps[$v])) {
- // There's a decomposition mapping for that code point
- // Decompositions only in version 2003 (original) of IDNA
- foreach ($this->_applyCannonicalOrdering(self::$_np_replacemaps[$v]) as $out) {
- $output[] = $out;
- }
- } else {
- $output[] = $v;
- }
- }
-
- // Combine code points
-
- $last_class = 0;
- $last_starter = 0;
- $out_len = count($output);
-
- for ($i = 0; $i < $out_len; ++$i) {
- $class = $this->_getCombiningClass($output[$i]);
-
- if ((!$last_class || $last_class != $class) && $class) {
- // Try to match
- $seq_len = $i - $last_starter;
- $out = $this->_combine(array_slice($output, $last_starter, $seq_len));
-
- // On match: Replace the last starter with the composed character and remove
- // the now redundant non-starter(s)
- if ($out) {
- $output[$last_starter] = $out;
-
- if (count($out) != $seq_len) {
- for ($j = $i + 1; $j < $out_len; ++$j) {
- $output[$j - 1] = $output[$j];
- }
-
- unset($output[$out_len]);
- }
-
- // Rewind the for loop by one, since there can be more possible compositions
- $i--;
- $out_len--;
- $last_class = ($i == $last_starter)? 0 : $this->_getCombiningClass($output[$i - 1]);
-
- continue;
- }
- }
-
- // The current class is 0
- if (!$class) {
- $last_starter = $i;
- }
-
- $last_class = $class;
- }
-
- return $output;
- }
-
- /**
- * Decomposes a Hangul syllable
- * (see http://www.unicode.org/unicode/reports/tr15/#Hangul).
- *
- * @param integer $char 32bit UCS4 code point
- *
- * @return array Either Hangul Syllable decomposed or original 32bit
- * value as one value array
- * @access private
- */
- private function _hangulDecompose($char)
- {
- $sindex = $char - $this->_sbase;
-
- if ($sindex < 0 || $sindex >= $this->_scount) {
- return array($char);
- }
-
- $result = array();
- $T = $this->_tbase + $sindex % $this->_tcount;
- $result[] = (int)($this->_lbase + $sindex / $this->_ncount);
- $result[] = (int)($this->_vbase + ($sindex % $this->_ncount) / $this->_tcount);
-
- if ($T != $this->_tbase) {
- $result[] = $T;
- }
-
- return $result;
- }
-
- /**
- * Ccomposes a Hangul syllable
- * (see http://www.unicode.org/unicode/reports/tr15/#Hangul).
- *
- * @param array $input Decomposed UCS4 sequence
- *
- * @return array UCS4 sequence with syllables composed
- * @access private
- */
- private function _hangulCompose($input)
- {
- $inp_len = count($input);
-
- if (!$inp_len) {
- return array();
- }
-
- $result = array();
- $last = $input[0];
- $result[] = $last; // copy first char from input to output
-
- for ($i = 1; $i < $inp_len; ++$i) {
- $char = $input[$i];
-
- // Find out, wether two current characters from L and V
- $lindex = $last - $this->_lbase;
-
- if (0 <= $lindex && $lindex < $this->_lcount) {
- $vindex = $char - $this->_vbase;
-
- if (0 <= $vindex && $vindex < $this->_vcount) {
- // create syllable of form LV
- $last = ($this->_sbase + ($lindex * $this->_vcount + $vindex) * $this->_tcount);
- $out_off = count($result) - 1;
- $result[$out_off] = $last; // reset last
-
- // discard char
- continue;
- }
- }
-
- // Find out, wether two current characters are LV and T
- $sindex = $last - $this->_sbase;
-
- if (0 <= $sindex && $sindex < $this->_scount && ($sindex % $this->_tcount) == 0) {
- $tindex = $char - $this->_tbase;
-
- if (0 <= $tindex && $tindex <= $this->_tcount) {
- // create syllable of form LVT
- $last += $tindex;
- $out_off = count($result) - 1;
- $result[$out_off] = $last; // reset last
-
- // discard char
- continue;
- }
- }
-
- // if neither case was true, just add the character
- $last = $char;
- $result[] = $char;
- }
-
- return $result;
- }
-
- /**
- * Returns the combining class of a certain wide char.
- *
- * @param integer $char Wide char to check (32bit integer)
- *
- * @return integer Combining class if found, else 0
- * @access private
- */
- private function _getCombiningClass($char)
- {
- return isset(self::$_np_norm_combcls[$char])? self::$_np_norm_combcls[$char] : 0;
- }
-
- /**
- * Apllies the cannonical ordering of a decomposed UCS4 sequence.
- *
- * @param array $input Decomposed UCS4 sequence
- *
- * @return array Ordered USC4 sequence
- * @access private
- */
- private function _applyCannonicalOrdering($input)
- {
- $swap = true;
- $size = count($input);
-
- while ($swap) {
- $swap = false;
- $last = $this->_getCombiningClass($input[0]);
-
- for ($i = 0; $i < $size - 1; ++$i) {
- $next = $this->_getCombiningClass($input[$i + 1]);
-
- if ($next != 0 && $last > $next) {
- // Move item leftward until it fits
- for ($j = $i + 1; $j > 0; --$j) {
- if ($this->_getCombiningClass($input[$j - 1]) <= $next) {
- break;
- }
-
- $t = $input[$j];
- $input[$j] = $input[$j - 1];
- $input[$j - 1] = $t;
- $swap = 1;
- }
-
- // Reentering the loop looking at the old character again
- $next = $last;
- }
-
- $last = $next;
- }
- }
-
- return $input;
- }
-
- /**
- * Do composition of a sequence of starter and non-starter.
- *
- * @param array $input UCS4 Decomposed sequence
- *
- * @return array Ordered USC4 sequence
- * @access private
- */
- private function _combine($input)
- {
- $inp_len = count($input);
-
- // Is it a Hangul syllable?
- if (1 != $inp_len) {
- $hangul = $this->_hangulCompose($input);
-
- // This place is probably wrong
- if (count($hangul) != $inp_len) {
- return $hangul;
- }
- }
-
- foreach (self::$_np_replacemaps as $np_src => $np_target) {
- if ($np_target[0] != $input[0]) {
- continue;
- }
-
- if (count($np_target) != $inp_len) {
- continue;
- }
-
- $hit = false;
-
- foreach ($input as $k2 => $v2) {
- if ($v2 == $np_target[$k2]) {
- $hit = true;
- } else {
- $hit = false;
- break;
- }
- }
-
- if ($hit) {
- return $np_src;
- }
- }
-
- return false;
- }
-
- /**
- * This converts an UTF-8 encoded string to its UCS-4 (array) representation
- * By talking about UCS-4 we mean arrays of 32bit integers representing
- * each of the "chars". This is due to PHP not being able to handle strings with
- * bit depth different from 8. This applies to the reverse method _ucs4_to_utf8(), too.
- * The following UTF-8 encodings are supported:
- *
- * bytes bits representation
- * 1 7 0xxxxxxx
- * 2 11 110xxxxx 10xxxxxx
- * 3 16 1110xxxx 10xxxxxx 10xxxxxx
- * 4 21 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- * 5 26 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
- * 6 31 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
- *
- * Each x represents a bit that can be used to store character data.
- *
- * @param string $input utf8-encoded string
- *
- * @return array ucs4-encoded array
- * @throws Exception
- * @access private
- */
- private function _utf8_to_ucs4($input)
- {
- $output = array();
- $out_len = 0;
- $inp_len = self::_byteLength($input, '8bit');
- $mode = 'next';
- $test = 'none';
- for ($k = 0; $k < $inp_len; ++$k) {
- $v = ord($input{$k}); // Extract byte from input string
-
- if ($v < 128) { // We found an ASCII char - put into stirng as is
- $output[$out_len] = $v;
- ++$out_len;
- if ('add' == $mode) {
- throw new UnexpectedValueException('Conversion from UTF-8 to UCS-4 failed: malformed input at byte '.$k);
- }
- continue;
- }
- if ('next' == $mode) { // Try to find the next start byte; determine the width of the Unicode char
- $start_byte = $v;
- $mode = 'add';
- $test = 'range';
- if ($v >> 5 == 6) { // &110xxxxx 10xxxxx
- $next_byte = 0; // Tells, how many times subsequent bitmasks must rotate 6bits to the left
- $v = ($v - 192) << 6;
- } elseif ($v >> 4 == 14) { // &1110xxxx 10xxxxxx 10xxxxxx
- $next_byte = 1;
- $v = ($v - 224) << 12;
- } elseif ($v >> 3 == 30) { // &11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- $next_byte = 2;
- $v = ($v - 240) << 18;
- } elseif ($v >> 2 == 62) { // &111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
- $next_byte = 3;
- $v = ($v - 248) << 24;
- } elseif ($v >> 1 == 126) { // &1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
- $next_byte = 4;
- $v = ($v - 252) << 30;
- } else {
- throw new UnexpectedValueException('This might be UTF-8, but I don\'t understand it at byte '.$k);
- }
- if ('add' == $mode) {
- $output[$out_len] = (int) $v;
- ++$out_len;
- continue;
- }
- }
- if ('add' == $mode) {
- if (!$this->_allow_overlong && $test == 'range') {
- $test = 'none';
- if (($v < 0xA0 && $start_byte == 0xE0) || ($v < 0x90 && $start_byte == 0xF0) || ($v > 0x8F && $start_byte == 0xF4)) {
- throw new OutOfRangeException('Bogus UTF-8 character detected (out of legal range) at byte '.$k);
- }
- }
- if ($v >> 6 == 2) { // Bit mask must be 10xxxxxx
- $v = ($v - 128) << ($next_byte * 6);
- $output[($out_len - 1)] += $v;
- --$next_byte;
- } else {
- throw new UnexpectedValueException('Conversion from UTF-8 to UCS-4 failed: malformed input at byte '.$k);
- }
- if ($next_byte < 0) {
- $mode = 'next';
- }
- }
- } // for
- return $output;
- }
-
- /**
- * Convert UCS-4 array into UTF-8 string
- *
- * @param array $input ucs4-encoded array
- *
- * @return string utf8-encoded string
- * @throws Exception
- * @access private
- */
- private function _ucs4_to_utf8($input)
- {
- $output = '';
-
- foreach ($input as $v) {
- // $v = ord($v);
-
- if ($v < 128) {
- // 7bit are transferred literally
- $output .= chr($v);
- } else if ($v < 1 << 11) {
- // 2 bytes
- $output .= chr(192 + ($v >> 6))
- . chr(128 + ($v & 63));
- } else if ($v < 1 << 16) {
- // 3 bytes
- $output .= chr(224 + ($v >> 12))
- . chr(128 + (($v >> 6) & 63))
- . chr(128 + ($v & 63));
- } else if ($v < 1 << 21) {
- // 4 bytes
- $output .= chr(240 + ($v >> 18))
- . chr(128 + (($v >> 12) & 63))
- . chr(128 + (($v >> 6) & 63))
- . chr(128 + ($v & 63));
- } else if ($v < 1 << 26) {
- // 5 bytes
- $output .= chr(248 + ($v >> 24))
- . chr(128 + (($v >> 18) & 63))
- . chr(128 + (($v >> 12) & 63))
- . chr(128 + (($v >> 6) & 63))
- . chr(128 + ($v & 63));
- } else if ($v < 1 << 31) {
- // 6 bytes
- $output .= chr(252 + ($v >> 30))
- . chr(128 + (($v >> 24) & 63))
- . chr(128 + (($v >> 18) & 63))
- . chr(128 + (($v >> 12) & 63))
- . chr(128 + (($v >> 6) & 63))
- . chr(128 + ($v & 63));
- } else {
- throw new UnexpectedValueException('Conversion from UCS-4 to UTF-8 failed: malformed input');
- }
- }
-
- return $output;
- }
-
- /**
- * Convert UCS-4 array into UCS-4 string
- *
- * @param array $input ucs4-encoded array
- *
- * @return string ucs4-encoded string
- * @throws Exception
- * @access private
- */
- private function _ucs4_to_ucs4_string($input)
- {
- $output = '';
- // Take array values and split output to 4 bytes per value
- // The bit mask is 255, which reads &11111111
- foreach ($input as $v) {
- $output .= ($v & (255 << 24) >> 24) . ($v & (255 << 16) >> 16) . ($v & (255 << 8) >> 8) . ($v & 255);
- }
- return $output;
- }
-
- /**
- * Convert UCS-4 string into UCS-4 array
- *
- * @param string $input ucs4-encoded string
- *
- * @return array ucs4-encoded array
- * @throws InvalidArgumentException
- * @access private
- */
- private function _ucs4_string_to_ucs4($input)
- {
- $output = array();
-
- $inp_len = self::_byteLength($input);
- // Input length must be dividable by 4
- if ($inp_len % 4) {
- throw new InvalidArgumentException('Input UCS4 string is broken');
- }
-
- // Empty input - return empty output
- if (!$inp_len) {
- return $output;
- }
-
- for ($i = 0, $out_len = -1; $i < $inp_len; ++$i) {
- // Increment output position every 4 input bytes
- if (!$i % 4) {
- $out_len++;
- $output[$out_len] = 0;
- }
- $output[$out_len] += ord($input{$i}) << (8 * (3 - ($i % 4) ) );
- }
- return $output;
- }
-
- /**
- * Echo hex representation of UCS4 sequence.
- *
- * @param array $input UCS4 sequence
- * @param boolean $include_bit Include bitmask in output
- *
- * @return void
- * @static
- * @access private
- */
- private static function _showHex($input, $include_bit = false)
- {
- foreach ($input as $k => $v) {
- echo '[', $k, '] => ', sprintf('%X', $v);
-
- if ($include_bit) {
- echo ' (', Net_IDNA2::_showBitmask($v), ')';
- }
-
- echo "\n";
- }
- }
-
- /**
- * Gives you a bit representation of given Byte (8 bits), Word (16 bits) or DWord (32 bits)
- * Output width is automagically determined
- *
- * @param int $octet ...
- *
- * @return string Bitmask-representation
- * @static
- * @access private
- */
- private static function _showBitmask($octet)
- {
- if ($octet >= (1 << 16)) {
- $w = 31;
- } else if ($octet >= (1 << 8)) {
- $w = 15;
- } else {
- $w = 7;
- }
-
- $return = '';
-
- for ($i = $w; $i > -1; $i--) {
- $return .= ($octet & (1 << $i))? '1' : '0';
- }
-
- return $return;
- }
-
- /**
- * Gets the length of a string in bytes even if mbstring function
- * overloading is turned on
- *
- * @param string $string the string for which to get the length.
- *
- * @return integer the length of the string in bytes.
- *
- * @see Net_IDNA2::$_mb_string_overload
- */
- private static function _byteLength($string)
- {
- if (self::$_mb_string_overload) {
- return mb_strlen($string, '8bit');
- }
- return strlen((binary)$string);
- }
-
- // }}}}
-
- // {{{ factory
- /**
- * Attempts to return a concrete IDNA instance for either php4 or php5.
- *
- * @param array $params Set of paramaters
- *
- * @return Net_IDNA2
- * @access public
- */
- function getInstance($params = array())
- {
- return new Net_IDNA2($params);
- }
- // }}}
-
- // {{{ singleton
- /**
- * Attempts to return a concrete IDNA instance for either php4 or php5,
- * only creating a new instance if no IDNA instance with the same
- * parameters currently exists.
- *
- * @param array $params Set of paramaters
- *
- * @return object Net_IDNA2
- * @access public
- */
- function singleton($params = array())
- {
- static $instances;
- if (!isset($instances)) {
- $instances = array();
- }
-
- $signature = serialize($params);
- if (!isset($instances[$signature])) {
- $instances[$signature] = Net_IDNA2::getInstance($params);
- }
-
- return $instances[$signature];
- }
- // }}}
-}
-
-?>
diff --git a/program/lib/Net/IDNA2/Exception.php b/program/lib/Net/IDNA2/Exception.php
deleted file mode 100644
index 72cb1ae75..000000000
--- a/program/lib/Net/IDNA2/Exception.php
+++ /dev/null
@@ -1,4 +0,0 @@
-<?php
-class Net_IDNA2_Exception extends Exception
-{
-}
diff --git a/program/lib/Net/IDNA2/Exception/Nameprep.php b/program/lib/Net/IDNA2/Exception/Nameprep.php
deleted file mode 100644
index 44cbd6bb9..000000000
--- a/program/lib/Net/IDNA2/Exception/Nameprep.php
+++ /dev/null
@@ -1,6 +0,0 @@
-<?php
-require_once 'Net/IDNA2/Exception.php';
-
-class Net_IDNA2_Exception_Nameprep extends Net_IDNA2_Exception
-{
-}
diff --git a/program/lib/Net/LDAP3.php b/program/lib/Net/LDAP3.php
deleted file mode 100644
index 3202f5aaf..000000000
--- a/program/lib/Net/LDAP3.php
+++ /dev/null
@@ -1,2618 +0,0 @@
-<?php
-/*
- +-----------------------------------------------------------------------+
- | Net/LDAP3.php |
- | |
- | Based on code created by the Roundcube Webmail team. |
- | |
- | Copyright (C) 2006-2014, The Roundcube Dev Team |
- | Copyright (C) 2012-2014, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Provide advanced functionality for accessing LDAP directories |
- | |
- +-----------------------------------------------------------------------+
- | Authors: Thomas Bruederli <roundcube@gmail.com> |
- | Aleksander Machniak <machniak@kolabsys.com> |
- | Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> |
- +-----------------------------------------------------------------------+
-*/
-
-require_once __DIR__ . '/LDAP3/Result.php';
-
-/**
- * Model class to access a LDAP directories
- *
- * @package Net_LDAP3
- */
-class Net_LDAP3
-{
- public $conn;
- public $vlv_active = false;
-
- private $attribute_level_rights_map = array(
- "r" => "read",
- "s" => "search",
- "w" => "write",
- "o" => "delete",
- "c" => "compare",
- "W" => "write",
- "O" => "delete"
- );
-
- private $entry_level_rights_map = array(
- "a" => "add",
- "d" => "delete",
- "n" => "modrdn",
- "v" => "read"
- );
-
- /*
- * Manipulate configuration through the config_set and config_get methods.
- * Available options:
- * 'debug' => false,
- * 'hosts' => array(),
- * 'port' => 389,
- * 'use_tls' => false,
- * 'ldap_version' => 3, // using LDAPv3
- * 'auth_method' => '', // SASL authentication method (for proxy auth), e.g. DIGEST-MD5
- * 'numsub_filter' => '(objectClass=organizationalUnit)', // with VLV, we also use numSubOrdinates to query the total number of records. Set this filter to get all numSubOrdinates attributes for counting
- * 'referrals' => false, // Sets the LDAP_OPT_REFERRALS option. Mostly used in multi-domain Active Directory setups
- * 'network_timeout' => 10, // The timeout (in seconds) for connect + bind arrempts. This is only supported in PHP >= 5.3.0 with OpenLDAP 2.x
- * 'sizelimit' => 0, // Enables you to limit the count of entries fetched. Setting this to 0 means no limit.
- * 'timelimit' => 0, // Sets the number of seconds how long is spend on the search. Setting this to 0 means no limit.
- * 'vlv' => false, // force VLV off
- * 'config_root_dn' => 'cn=config', // Root DN to read config (e.g. vlv indexes) from
- * 'service_bind_dn' => 'uid=kolab-service,ou=Special Users,dc=example,dc=org',
- * 'service_bind_pw' => 'Welcome2KolabSystems',
- * 'root_dn' => 'dc=example,dc=org',
- */
- protected $config = array(
- 'sizelimit' => 0,
- 'timelimit' => 0,
- );
-
- protected $debug_level = false;
- protected $list_page = 1;
- protected $page_size = 10;
- protected $cache;
-
- // Use public method config_set('log_hook', $callback) to have $callback be
- // call_user_func'ed instead of the local log functions.
- protected $_log_hook;
-
- // Use public method config_set('config_get_hook', $callback) to have
- // $callback be call_user_func'ed instead of the local config_get function.
- protected $_config_get_hook;
-
- // Use public method config_set('config_set_hook', $callback) to have
- // $callback be call_user_func'ed instead of the local config_set function.
- protected $_config_set_hook;
-
- // Not Yet Implemented
- // Intended to allow hooking in for the purpose of caching.
- protected $_result_hook;
-
- // Runtime. These are not the variables you're looking for.
- protected $_current_bind_dn;
- protected $_current_bind_pw;
- protected $_current_host;
- protected $_supported_control = array();
- protected $_vlv_indexes_and_searches;
-
- /**
- * Constructor
- *
- * @param array $config Configuration parameters that have not already
- * been initialized. For configuration parameters
- * that have in fact been set, use the config_set()
- * method after initialization.
- */
- public function __construct($config = array())
- {
- if (!empty($config) && is_array($config)) {
- foreach ($config as $key => $value) {
- if (empty($this->config[$key])) {
- $setter = 'config_set_' . $key;
- if (method_exists($this, $setter)) {
- $this->$setter($value);
- }
- else if (isset($this->$key)) {
- $this->$key = $value;
- }
- else {
- $this->config[$key] = $value;
- }
- }
- }
- }
- }
-
- /**
- * Add multiple entries to the directory information tree in one go.
- */
- public function add_entries($entries, $attributes = array())
- {
- // If $entries is an associative array, it's keys are DNs and its
- // values are the attributes for that DN.
- //
- // If $entries is a non-associative array, the attributes are expected
- // to be positional in $attributes.
-
- $result_set = array();
-
- if (array_keys($entries) == range(0, count($entries) - 1)) {
- // $entries is sequential
- if (count($entries) !== count($attributes)) {
- $this->_error("Wrong entry/attribute count in " . __FUNCTION__);
- return false;
- }
-
- for ($i = 0; $i < count($entries); $i++) {
- $result_set[$i] = $this->add_entry($entries[$i], $attributes[$i]);
- }
- }
- else {
- // $entries is associative
- foreach ($entries as $entry_dn => $entry_attributes) {
- if (array_keys($attributes) !== range(0, count($attributes)-1)) {
- // $attributes is associative as well, let's merge these
- //
- // $entry_attributes takes precedence, so is in the second
- // position in array_merge()
- $entry_attributes = array_merge($attributes, $entry_attributes);
- }
-
- $result_set[$entry_dn] = $this->add_entry($entry_dn, $entry_attributes);
- }
- }
-
- return $result_set;
- }
-
- /**
- * Add an entry to the directory information tree.
- */
- public function add_entry($entry_dn, $attributes)
- {
- // TODO:
- // - Get entry rdn attribute value from entry_dn and see if it exists in
- // attributes -> issue warning if so (but not block the operation).
- $this->_debug("Entry DN", $entry_dn);
- $this->_debug("Attributes", $attributes);
-
- foreach ($attributes as $attr_name => $attr_value) {
- if (empty($attr_value)) {
- unset($attributes[$attr_name]);
- }
- }
-
- $this->_debug("C: Add $entry_dn: " . json_encode($attributes));
-
- if (($add_result = ldap_add($this->conn, $entry_dn, $attributes)) == false) {
- $this->_debug("S: " . ldap_error($this->conn));
- $this->_debug("S: Adding entry $entry_dn failed. " . ldap_error($this->conn));
-
- return false;
- }
-
- $this->_debug("LDAP: S: OK");
-
- return true;
- }
-
- /**
- * Add replication agreements and initialize the consumer(s) for
- * $domain_root_dn.
- *
- * Searches the configured replicas for any of the current domain/config
- * databases, and uses this information to configure the additional
- * replication for the (new) domain database (at $domain_root_dn).
- *
- * Very specific to Netscape-based directory servers, and currently also
- * very specific to multi-master replication.
- */
- public function add_replication_agreements($domain_root_dn)
- {
- $replica_hosts = $this->list_replicas();
-
- if (empty($replica_hosts)) {
- return;
- }
-
- $result = $this->search($this->config_get('config_root_dn'), "(&(objectclass=nsDS5Replica)(nsDS5ReplicaType=3))", "sub");
-
- if (!$result) {
- $this->_debug("No replication configuration found.");
- return;
- }
-
- // Preserve the number of replicated databases we have, because the replication ID
- // can be calculated from the number of databases replicated, and the number of
- // servers.
- $num_replica_dbs = $result->count();
- $replicas = $result->entries(true);
- $max_replica_agreements = 0;
-
- foreach ($replicas as $replica_dn => $replica_attrs) {
- $result = $this->search($replica_dn, "(objectclass=nsDS5ReplicationAgreement)", "sub");
- if ($result) {
- if ($max_replica_agreements < $result->count()) {
- $max_replica_agreements = $result->count();
- $max_replica_agreements_dn = $replica_dn;
- }
- }
- }
-
- $max_repl_id = $num_replica_dbs * count($replica_hosts);
-
- $this->_debug("The current maximum replication ID is $max_repl_id");
- $this->_debug("The current maximum number of replication agreements for any database is $max_replica_agreements (for $max_replica_agreements_dn)");
- $this->_debug("With " . count($replica_hosts) . " replicas, the next is " . ($max_repl_id + 1) . " and the last one is " . ($max_repl_id + count($replica_hosts)));
-
- // Then add the replication agreements
- foreach ($replica_hosts as $num => $replica_host) {
- $ldap = new Net_LDAP3($this->config);
- $ldap->config_set('hosts', array($replica_host));
- $ldap->connect();
- $ldap->bind($this->_current_bind_dn, $this->_current_bind_pw);
-
- $replica_attrs = array(
- 'cn' => 'replica',
- 'objectclass' => array(
- 'top',
- 'nsds5replica',
- 'extensibleobject',
- ),
- 'nsDS5ReplicaBindDN' => $ldap->get_entry_attribute($replica_dn, "nsDS5ReplicaBindDN"),
- 'nsDS5ReplicaId' => ($max_repl_id + $num + 1),
- 'nsDS5ReplicaRoot' => $domain_root_dn,
- 'nsDS5ReplicaType' => $ldap->get_entry_attribute($replica_dn, "nsDS5ReplicaType"),
- 'nsds5ReplicaPurgeDelay' => $ldap->get_entry_attribute($replica_dn, "nsds5ReplicaPurgeDelay"),
- 'nsDS5Flags' => $ldap->get_entry_attribute($replica_dn, "nsDS5Flags")
- );
-
- $new_replica_dn = 'cn=replica,cn="' . $domain_root_dn . '",cn=mapping tree,cn=config';
-
- $this->_debug("Adding $new_replica_dn to $replica_host with attributes: " . var_export($replica_attrs, true));
-
- $result = $ldap->add_entry($new_replica_dn, $replica_attrs);
-
- if (!$result) {
- $this->_error("Could not add replication configuration to database for $domain_root_dn on $replica_host");
- continue;
- }
-
- $result = $ldap->search($replica_dn, "(objectclass=nsDS5ReplicationAgreement)", "sub");
-
- if (!$result) {
- $this->_error("Host $replica_host does not have any replication agreements");
- continue;
- }
-
- $entries = $result->entries(true);
- $replica_agreement_tpl_dn = key($entries);
-
- $this->_debug("Using " . var_export($replica_agreement_tpl_dn, true) . " as the template for new replication agreements");
-
- foreach ($replica_hosts as $replicate_to_host) {
- // Skip the current server
- if ($replicate_to_host == $replica_host) {
- continue;
- }
-
- $this->_debug("Adding a replication agreement for $domain_root_dn to $replicate_to_host on " . $replica_host);
-
- $attrs = array(
- 'objectclass',
- 'nsDS5ReplicaBindDN',
- 'nsDS5ReplicaCredentials',
- 'nsDS5ReplicaTransportInfo',
- 'nsDS5ReplicaBindMethod',
- 'nsDS5ReplicaHost',
- 'nsDS5ReplicaPort'
- );
-
- $replica_agreement_attrs = $ldap->get_entry_attributes($replica_agreement_tpl_dn, $attrs);
- $replica_agreement_attrs['cn'] = array_shift(explode('.', $replicate_to_host)) . str_replace(array('dc=',','), array('_',''), $domain_root_dn);
- $replica_agreement_attrs['nsDS5ReplicaRoot'] = $domain_root_dn;
- $replica_agreement_dn = "cn=" . $replica_agreement_attrs['cn'] . "," . $new_replica_dn;
-
- $this->_debug("Adding $replica_agreement_dn to $replica_host with attributes: " . var_export($replica_agreement_attrs, true));
-
- $result = $ldap->add_entry($replica_agreement_dn, $replica_agreement_attrs);
-
- if (!$result) {
- $this->_error("Failed adding $replica_agreement_dn");
- }
- }
- }
-
- $server_id = implode('', array_diff($replica_hosts, $this->_server_id_not));
-
- $this->_debug("About to trigger consumer initialization for replicas on current 'parent': $server_id");
-
- $result = $this->search($this->config_get('config_root_dn'), "(&(objectclass=nsDS5ReplicationAgreement)(nsds5replicaroot=$domain_root_dn))", "sub");
-
- if ($result) {
- foreach ($result->entries(true) as $agreement_dn => $agreement_attrs) {
- $this->modify_entry_attributes(
- $agreement_dn,
- array(
- 'replace' => array(
- 'nsds5BeginReplicaRefresh' => 'start',
- ),
- )
- );
- }
- }
- }
-
- public function attribute_details($attributes = array())
- {
- $schema = $this->init_schema();
-
- if (!$schema) {
- return array();
- }
-
- $attribs = $schema->getAll('attributes');
-
- $attributes_details = array();
-
- foreach ($attributes as $attribute) {
- if (array_key_exists($attribute, $attribs)) {
- $attrib_details = $attribs[$attribute];
-
- if (!empty($attrib_details['sup'])) {
- foreach ($attrib_details['sup'] as $super_attrib) {
- $_attrib_details = $attribs[$super_attrib];
- if (is_array($_attrib_details)) {
- $attrib_details = array_merge($_attrib_details, $attrib_details);
- }
- }
- }
- }
- else if (array_key_exists(strtolower($attribute), $attribs)) {
- $attrib_details = $attribs[strtolower($attribute)];
-
- if (!empty($attrib_details['sup'])) {
- foreach ($attrib_details['sup'] as $super_attrib) {
- $_attrib_details = $attribs[$super_attrib];
- if (is_array($_attrib_details)) {
- $attrib_details = array_merge($_attrib_details, $attrib_details);
- }
- }
- }
- }
- else {
- $this->_warning("LDAP: No schema details exist for attribute $attribute (which is strange)");
- }
-
- // The relevant parts only, please
- $attributes_details[$attribute] = array(
- 'type' => !empty($attrib_details['single-value']) ? 'text' : 'list',
- 'description' => $attrib_details['desc'],
- 'syntax' => $attrib_details['syntax'],
- 'max-length' => $attrib_details['max-length'] ?: false,
- );
- }
-
- return $attributes_details;
- }
-
- public function attributes_allowed($objectclasses = array())
- {
- $this->_debug("Listing allowed_attributes for objectclasses", $objectclasses);
-
- if (!is_array($objectclasses) || empty($objectclasses)) {
- return false;
- }
-
- $schema = $this->init_schema();
- if (!$schema) {
- return false;
- }
-
- $may = array();
- $must = array();
- $superclasses = array();
-
- foreach ($objectclasses as $objectclass) {
- $superclass = $schema->superclass($objectclass);
- if (!empty($superclass)) {
- $superclasses = array_merge($superclass, $superclasses);
- }
-
- $_may = $schema->may($objectclass);
- $_must = $schema->must($objectclass);
-
- if (is_array($_may)) {
- $may = array_merge($may, $_may);
- }
- if (is_array($_must)) {
- $must = array_merge($must, $_must);
- }
- }
-
- $may = array_unique($may);
- $must = array_unique($must);
- $superclasses = array_unique($superclasses);
-
- return array('may' => $may, 'must' => $must, 'super' => $superclasses);
- }
-
- public function classes_allowed()
- {
- $schema = $this->init_schema();
- if (!$schema) {
- return false;
- }
-
- $list = $schema->getAll('objectclasses');
- $classes = array();
-
- foreach ($list as $class) {
- $classes[] = $class['name'];
- }
-
- return $classes;
- }
-
- /**
- * Bind connection with DN and password
- *
- * @param string $dn Bind DN
- * @param string $pass Bind password
- *
- * @return boolean True on success, False on error
- */
- public function bind($bind_dn, $bind_pw)
- {
- if (!$this->conn) {
- return false;
- }
-
- if ($bind_dn == $this->_current_bind_dn) {
- return true;
- }
-
- $this->_debug("C: Bind [dn: $bind_dn]");
-
- if (@ldap_bind($this->conn, $bind_dn, $bind_pw)) {
- $this->_debug("S: OK");
- $this->_current_bind_dn = $bind_dn;
- $this->_current_bind_pw = $bind_pw;
-
- return true;
- }
-
- $this->_debug("S: ".ldap_error($this->conn));
- $this->_error("Bind failed for dn=$bind_dn: ".ldap_error($this->conn));
-
- return false;
- }
-
- /**
- * Close connection to LDAP server
- */
- public function close()
- {
- if ($this->conn) {
- $this->_debug("C: Close");
- ldap_unbind($this->conn);
-
- $this->_current_bind_dn = null;
- $this->_current_bind_pw = null;
- $this->conn = null;
- }
- }
-
- /**
- * Get the value of a configuration item.
- *
- * @param string $key Configuration key
- * @param mixed $default Default value to return
- */
- public function config_get($key, $default = null)
- {
- if (!empty($this->_config_get_hook)) {
- return call_user_func_array($this->_config_get_hook, array($key, $value));
- }
- else if (method_exists($this, "config_get_{$key}")) {
- return call_user_func(array($this, "config_get_$key"), $value);
- }
- else if (!isset($this->config[$key])) {
- return $default;
- }
- else {
- return $this->config[$key];
- }
- }
-
- /**
- * Set a configuration item to value.
- *
- * @param string $key Configuration key
- * @param mixed $value Configuration value
- */
- public function config_set($key, $value = null)
- {
- if (is_array($key)) {
- foreach ($key as $k => $v) {
- $this->config_set($k, $v);
- }
- return;
- }
-
- if (!empty($this->_config_set_hook)) {
- call_user_func($this->_config_set_hook, array($key, $value));
- }
- else if (method_exists($this, "config_set_{$key}")) {
- call_user_func_array(array($this, "config_set_$key"), array($value));
- }
- else if (isset($this->$key)) {
- $this->$key = $value;
- }
- else {
- // 'host' option is deprecated
- if ($key == 'host') {
- $this->config['hosts'] = (array) $value;
- }
- else {
- $this->config[$key] = $value;
- }
- }
- }
-
- /**
- * Establish a connection to the LDAP server
- */
- public function connect($host = null)
- {
- if (!function_exists('ldap_connect')) {
- $this->_error("No ldap support in this PHP installation");
- return false;
- }
-
- if (is_resource($this->conn)) {
- $this->_debug("Connection already exists");
- return true;
- }
-
- $hosts = !empty($host) ? $host : $this->config_get('hosts', array());
- $port = $this->config_get('port', 389);
-
- foreach ((array) $hosts as $host) {
- $this->_debug("C: Connect [$host:$port]");
-
- if ($lc = @ldap_connect($host, $port)) {
- if ($this->config_get('use_tls', false) === true) {
- if (!ldap_start_tls($lc)) {
- $this->_debug("S: Could not start TLS. " . ldap_error($lc));
- continue;
- }
- }
-
- $this->_debug("S: OK");
-
- $ldap_version = $this->config_get('ldap_version', 3);
- $timeout = $this->config_get('network_timeout');
- $referrals = $this->config_get('referrals');
-
- ldap_set_option($lc, LDAP_OPT_PROTOCOL_VERSION, $ldap_version);
-
- if ($timeout) {
- ldap_set_option($lc, LDAP_OPT_NETWORK_TIMEOUT, $timeout);
- }
-
- if ($referrals !== null) {
- ldap_set_option($lc, LDAP_OPT_REFERRALS, (bool) $referrals);
- }
-
- $this->_current_host = $host;
- $this->conn = $lc;
-
- break;
- }
-
- $this->_debug("S: NOT OK");
- }
-
- if (!is_resource($this->conn)) {
- $this->_error("Could not connect to LDAP");
- return false;
- }
-
- return true;
- }
-
- /**
- * Shortcut to ldap_delete()
- */
- public function delete_entry($entry_dn)
- {
- $this->_debug("LDAP: C: Delete $entry_dn");
-
- if (ldap_delete($this->conn, $entry_dn) === false) {
- $this->_debug("LDAP: S: " . ldap_error($this->conn));
- return false;
- }
-
- $this->_debug("LDAP: S: OK");
-
- return true;
- }
-
- /**
- * Deletes specified entry and all entries in the tree
- */
- public function delete_entry_recursive($entry_dn)
- {
- // searching for sub entries, but not scope sub, just one level
- $result = $this->search($entry_dn, '(objectclass=*)', 'one');
-
- if ($result) {
- $entries = $result->entries(true);
-
- foreach (array_keys($entries) as $sub_dn) {
- if (!$this->delete_entry_recursive($sub_dn)) {
- return false;
- }
- }
- }
-
- if (!$this->delete_entry($entry_dn)) {
- return false;
- }
-
- return true;
- }
-
- public function effective_rights($subject)
- {
- $effective_rights_control_oid = "1.3.6.1.4.1.42.2.27.9.5.2";
-
- $supported_controls = $this->supported_controls();
-
- if (!in_array($effective_rights_control_oid, $supported_controls)) {
- $this->_debug("LDAP: No getEffectiveRights control in supportedControls");
- return false;
- }
-
- $attributes = array(
- 'attributeLevelRights' => array(),
- 'entryLevelRights' => array(),
- );
-
- $output = array();
- $entry_dn = $this->entry_dn($subject);
-
- if (!$entry_dn) {
- $entry_dn = $this->config_get($subject . "_base_dn");
- }
- if (!$entry_dn) {
- $entry_dn = $this->config_get("base_dn");
- }
- if (!$entry_dn) {
- $entry_dn = $this->config_get("root_dn");
- }
-
- $this->_debug("effective_rights for subject $subject resolves to entry dn $entry_dn");
-
- $moz_ldapsearch = "/usr/lib64/mozldap/ldapsearch";
- if (!is_file($moz_ldapsearch)) {
- $moz_ldapsearch = "/usr/lib/mozldap/ldapsearch";
- }
- if (!is_file($moz_ldapsearch)) {
- $moz_ldapsearch = null;
- }
-
- if (empty($moz_ldapsearch)) {
- $this->_error("Mozilla LDAP C SDK binary ldapsearch not found, cannot get effective rights on subject $subject");
- return null;
- }
-
- $command = array(
- $moz_ldapsearch,
- '-x',
- '-h',
- $this->_ldap_server,
- '-p',
- $this->_ldap_port,
- '-b',
- escapeshellarg($entry_dn),
- '-D',
- escapeshellarg($this->_current_bind_dn),
- '-w',
- escapeshellarg($this->_current_bind_pw),
- '-J',
- escapeshellarg(implode(':', array(
- $effective_rights_control_oid, // OID
- 'true', // Criticality
- 'dn:' . $this->_current_bind_dn // User DN
- ))),
- '-s',
- 'base',
- '"(objectclass=*)"',
- '"*"',
- );
-
- $command = implode(' ', $command);
-
- $this->_debug("LDAP: Executing command: $command");
-
- exec($command, $output, $return_code);
-
- $this->_debug("LDAP: Command output:" . var_export($output, true));
- $this->_debug("Return code: " . $return_code);
-
- if ($return_code) {
- $this->_error("Command $moz_ldapsearch returned error code: $return_code");
- return null;
- }
-
- $lines = array();
- foreach ($output as $line_num => $line) {
- if (substr($line, 0, 1) == " ") {
- $lines[count($lines)-1] .= trim($line);
- }
- else {
- $lines[] = trim($line);
- }
- }
-
- foreach ($lines as $line) {
- $line_components = explode(':', $line);
- $attribute_name = array_shift($line_components);
- $attribute_value = trim(implode(':', $line_components));
-
- switch ($attribute_name) {
- case "attributeLevelRights":
- $attributes[$attribute_name] = $this->parse_attribute_level_rights($attribute_value);
- break;
- case "dn":
- $attributes[$attribute_name] = $attribute_value;
- break;
- case "entryLevelRights":
- $attributes[$attribute_name] = $this->parse_entry_level_rights($attribute_value);
- break;
-
- default:
- break;
- }
- }
-
- return $attributes;
- }
-
- /**
- * Resolve entry data to entry DN
- *
- * @param string $subject Entry string (e.g. entry DN or unique attribute value)
- * @param array $attributes Additional attributes
- * @param string $base_dn Optional base DN
- *
- * @return string Entry DN string
- */
- public function entry_dn($subject, $attributes = array(), $base_dn = null)
- {
- $this->_debug("entry_dn on subject $subject");
- $is_dn = ldap_explode_dn($subject, 1);
-
- if (is_array($is_dn) && array_key_exists("count", $is_dn) && $is_dn["count"] > 0) {
- $this->_debug("$subject is a dn");
- return $subject;
- }
-
- $this->_debug("$subject is not a dn");
-
- if (strlen($subject) < 32 || preg_match('/[^a-fA-F0-9-]/', $subject)) {
- $this->_debug("$subject is not a unique identifier");
- return;
- }
-
- $unique_attr = $this->config_get('unique_attribute', 'nsuniqueid');
-
- $this->_debug("Using unique_attribute " . var_export($unique_attr, true) . " at " . __FILE__ . ":" . __LINE__);
-
- $attributes = array_merge(array($unique_attr => $subject), (array)$attributes);
- $subject = $this->entry_find_by_attribute($attributes, $base_dn);
-
- if (!empty($subject)) {
- return key($subject);
- }
- }
-
- public function entry_find_by_attribute($attributes, $base_dn = null)
- {
- $this->_debug("Net_LDAP3::entry_find_by_attribute(\$attributes, \$base_dn) called with base_dn", $base_dn, "and attributes", $attributes);
-
- if (empty($attributes) || !is_array($attributes)) {
- return false;
- }
-
- if (empty($attributes[key($attributes)])) {
- return false;
- }
-
- $filter = count($attributes) ? "(&" : "";
-
- foreach ($attributes as $key => $value) {
- $filter .= "(" . $key . "=" . $value . ")";
- }
-
- $filter .= count($attributes) ? ")" : "";
-
- if (empty($base_dn)) {
- $base_dn = $this->config_get('root_dn');
- $this->_debug("Using base_dn from domain " . $this->domain . ": " . $base_dn);
- }
-
- $result = $this->search($base_dn, $filter, 'sub', array_keys($attributes));
-
- if ($result && $result->count() > 0) {
- $this->_debug("Results found: " . implode(', ', array_keys($result->entries(true))));
- return $result->entries(true);
- }
- else {
- $this->_debug("No result");
- return false;
- }
- }
-
- public function find_user_groups($member_dn)
- {
- $groups = array();
- $root_dn = $this->config_get('root_dn');
-
- // TODO: Do not query for both, it's either one or the other
- $entries = $this->search($root_dn, "(|" .
- "(&(objectclass=groupofnames)(member=$member_dn))" .
- "(&(objectclass=groupofuniquenames)(uniquemember=$member_dn))" .
- ")"
- );
-
- if ($entries) {
- $groups = array_keys($entries->entries(true));
- }
-
- return $groups;
- }
-
- public function get_entry_attribute($subject_dn, $attribute)
- {
- $entry = $this->get_entry_attributes($subject_dn, (array)$attribute);
-
- return $entry[strtolower($attribute)];
- }
-
- public function get_entry_attributes($subject_dn, $attributes)
- {
- // @TODO: use get_entry?
- $result = $this->search($subject_dn, '(objectclass=*)', 'base', $attributes);
-
- if (!$result) {
- return array();
- }
-
- $entries = $result->entries(true);
- $entry_dn = key($entries);
- $entry = $entries[$entry_dn];
-
- return $entry;
- }
-
- /**
- * Get a specific LDAP entry, identified by its DN
- *
- * @param string $dn Record identifier
- * @param array $attributes Attributes to return
- *
- * @return array Hash array
- */
- public function get_entry($dn, $attributes = array())
- {
- $rec = null;
-
- if ($this->conn && $dn) {
- $this->_debug("C: Read [dn: $dn] [(objectclass=*)]");
-
- if ($ldap_result = @ldap_read($this->conn, $dn, '(objectclass=*)', $attributes)) {
- $this->_debug("S: OK");
-
- if ($entry = ldap_first_entry($this->conn, $ldap_result)) {
- $rec = ldap_get_attributes($this->conn, $entry);
- }
- }
- else {
- $this->_debug("S: ".ldap_error($this->conn));
- }
-
- if (!empty($rec)) {
- $rec['dn'] = $dn; // Add in the dn for the entry.
- }
- }
-
- return $rec;
- }
-
- public function list_replicas()
- {
- $this->_debug("Finding replicas for this server.");
-
- // Search any host that is a replica for the current host
- $replica_hosts = $this->config_get('replica_hosts', array());
- $root_dn = $this->config_get('config_root_dn');
-
- if (!empty($replica_hosts)) {
- return $replica_hosts;
- }
-
- $ldap = new Net_LDAP3($this->config);
- $ldap->connect();
- $ldap->bind($this->_current_bind_dn, $this->_current_bind_pw);
-
- $result = $ldap->search($root_dn, '(objectclass=nsds5replicationagreement)', 'sub', array('nsds5replicahost'));
-
- if (!$result) {
- $this->_debug("No replicas configured");
- return $replica_hosts;
- }
-
- $this->_debug("Replication agreements found: " . var_export($result->entries(true), true));
-
- foreach ($result->entries(true) as $dn => $attrs) {
- if (!in_array($attrs['nsds5replicahost'], $replica_hosts)) {
- $replica_hosts[] = $attrs['nsds5replicahost'];
- }
- }
-
- // $replica_hosts now holds the IDs of servers we are currently NOT
- // connected to. We might need this later in order to set
- $this->_server_id_not = $replica_hosts;
-
- $this->_debug("So far, we have the following replicas: " . var_export($replica_hosts, true));
-
- $ldap->close();
-
- foreach ($replica_hosts as $replica_host) {
- $ldap->config_set('hosts', array($replica_host));
- $ldap->connect();
- $ldap->bind($this->_current_bind_dn, $this->_current_bind_pw);
-
- $result = $ldap->search($root_dn, '(objectclass=nsds5replicationagreement)', 'sub', array('nsds5replicahost'));
- if (!$result) {
- $this->_debug("No replicas configured");
- }
-
- foreach ($result->entries(true) as $dn => $attrs) {
- if (!in_array($attrs['nsds5replicahost'], $replica_hosts)) {
- $replica_hosts[] = $attrs['nsds5replicahost'];
- }
- }
-
- $ldap->close();
- }
-
- $this->config_set('replica_hosts', $replica_hosts);
-
- return $replica_hosts;
- }
-
- public function login($username, $password, $domain = null)
- {
- $this->_debug("Net_LDAP3::login(\$username = '" . $username . "', \$password = '****', \$domain = '" . $domain . "')");
-
- $_bind_dn = $this->config_get('service_bind_dn');
- $_bind_pw = $this->config_get('service_bind_pw');
-
- if (empty($_bind_dn)) {
- $this->_debug("No valid service bind dn found.");
- return null;
- }
-
- if (empty($_bind_pw)) {
- $this->_debug("No valid service bind password found.");
- return null;
- }
-
- $bound = $this->bind($_bind_dn, $_bind_pw);
-
- if (!$bound) {
- $this->_debug("Could not bind with service bind credentials.");
- return null;
- }
-
- $entry_dn = $this->entry_dn($username);
-
- if (!empty($entry_dn)) {
- $bound = $this->bind($entry_dn, $password);
-
- if (!$bound) {
- $this->_error("Could not bind with " . $entry_dn);
- return null;
- }
-
- return $entry_dn;
- }
-
- $base_dn = $this->config_get('root_dn');
-
- if (empty($base_dn)) {
- $this->_debug("Could not get a valid base dn to search.");
- return null;
- }
-
- $localpart = $username;
-
- if (empty($domain) ) {
- if (count(explode('@', $username)) > 1) {
- $_parts = explode('@', $username);
- $localpart = $_parts[0];
- $domain = $_parts[1];
- }
- else {
- $localpart = $username;
- $domain = '';
- }
- }
-
- $realm = $domain;
- $filter = $this->config_get("login_filter", null);
-
- if (empty($filter)) {
- $filter = $this->config_get("filter", null);
- }
- if (empty($filter)) {
- $filter = "(&(|(mail=%s)(mail=%U@%d)(alias=%s)(alias=%U@%d)(uid=%s))(objectclass=inetorgperson))";
- }
-
- $this->_debug("Net::LDAP3::login() original filter: " . $filter);
-
- $replace_patterns = array(
- '/%s/' => $username,
- '/%d/' => $domain,
- '/%U/' => $localpart,
- '/%r/' => $realm
- );
-
- $filter = preg_replace(array_keys($replace_patterns), array_values($replace_patterns), $filter);
-
- $this->_debug("Net::LDAP3::login() actual filter: " . $filter);
-
- $result = $this->search($base_dn, $filter, 'sub');
-
- if (!$result) {
- $this->_debug("Could not search $base_dn with $filter");
- return null;
- }
-
- if ($result->count() > 1) {
- $this->_debug("Multiple entries found.");
- return null;
- }
- else if ($result->count() < 1) {
- $this->_debug("No entries found.");
- return null;
- }
-
- $entries = $result->entries();
- $entry = self::normalize_result($entries);
- $entry_dn = key($entry);
-
- $bound = $this->bind($entry_dn, $password);
-
- if (!$bound) {
- $this->_debug("Could not bind with " . $entry_dn);
- return null;
- }
-
- return $entry_dn;
- }
-
- public function list_group_members($dn, $entry = null, $recurse = true)
- {
- $this->_debug("Called list_group_members(" . $dn . ")");
-
- if (is_array($entry) && in_array('objectclass', $entry)) {
- if (!in_array(array('groupofnames', 'groupofuniquenames', 'groupofurls'), $entry['objectclass'])) {
- $this->_debug("Called list_group_members on a non-group!");
- return array();
- }
- }
- else {
- $entry = $this->get_entry($dn, array('member', 'uniquemember', 'memberurl', 'objectclass'));
-
- if (!$entry) {
- return array();
- }
- }
-
- $group_members = array();
-
- foreach ((array)$entry['objectclass'] as $objectclass) {
- switch (strtolower($objectclass)) {
- case "groupofnames":
- case "kolabgroupofnames":
- $group_members = array_merge($group_members, $this->list_group_member($dn, $entry['member'], $recurse));
- break;
- case "groupofuniquenames":
- case "kolabgroupofuniquenames":
- $group_members = array_merge($group_members, $this->list_group_uniquemember($dn, $entry['uniquemember'], $recurse));
- break;
- case "groupofurls":
- $group_members = array_merge($group_members, $this->list_group_memberurl($dn, $entry['memberurl'], $recurse));
- break;
- }
- }
-
- return array_values(array_filter($group_members));
- }
-
- public function modify_entry($subject_dn, $old_attrs, $new_attrs)
- {
- $this->_debug("OLD ATTRIBUTES", $old_attrs);
- $this->_debug("NEW ATTRIBUTES", $new_attrs);
-
- // TODO: Get $rdn_attr - we have type_id in $new_attrs
- $dn_components = ldap_explode_dn($subject_dn, 0);
- $rdn_components = explode('=', $dn_components[0]);
- $rdn_attr = $rdn_components[0];
-
- $this->_debug("Net_LDAP3::modify_entry() using rdn attribute: " . $rdn_attr);
-
- $mod_array = array(
- 'add' => array(), // For use with ldap_mod_add()
- 'del' => array(), // For use with ldap_mod_del()
- 'replace' => array(), // For use with ldap_mod_replace()
- 'rename' => array(), // For use with ldap_rename()
- );
-
- // This is me cheating. Remove this special attribute.
- if (array_key_exists('ou', $old_attrs) || array_key_exists('ou', $new_attrs)) {
- $old_ou = $old_attrs['ou'];
- $new_ou = $new_attrs['ou'];
- unset($old_attrs['ou']);
- unset($new_attrs['ou']);
- }
- else {
- $old_ou = null;
- $new_ou = null;
- }
-
- // Compare each attribute value of the old attrs with the corresponding value
- // in the new attrs, if any.
- foreach ($old_attrs as $attr => $old_attr_value) {
- if (is_array($old_attr_value)) {
- if (count($old_attr_value) == 1) {
- $old_attrs[$attr] = $old_attr_value[0];
- $old_attr_value = $old_attrs[$attr];
- }
- }
-
- if (array_key_exists($attr, $new_attrs)) {
- if (is_array($new_attrs[$attr])) {
- if (count($new_attrs[$attr]) == 1) {
- $new_attrs[$attr] = $new_attrs[$attr][0];
- }
- }
-
- if (is_array($old_attrs[$attr]) && is_array($new_attrs[$attr])) {
- $_sort1 = $new_attrs[$attr];
- sort($_sort1);
- $_sort2 = $old_attr_value;
- sort($_sort2);
- }
- else {
- $_sort1 = true;
- $_sort2 = false;
- }
-
- if ($new_attrs[$attr] !== $old_attr_value && $_sort1 !== $_sort2) {
- $this->_debug("Attribute $attr changed from " . var_export($old_attr_value, true) . " to " . var_export($new_attrs[$attr], true));
- if ($attr === $rdn_attr) {
- $this->_debug("This attribute is the RDN attribute. Let's see if it is multi-valued, and if the original still exists in the new value.");
- if (is_array($old_attrs[$attr])) {
- if (!is_array($new_attrs[$attr])) {
- if (in_array($new_attrs[$attr], $old_attrs[$attr])) {
- // TODO: Need to remove all $old_attrs[$attr] values not equal to $new_attrs[$attr], and not equal to the current $rdn_attr value [0]
-
- $this->_debug("old attrs. is array, new attrs. is not array. new attr. exists in old attrs.");
-
- $rdn_attr_value = array_shift($old_attrs[$attr]);
- $_attr_to_remove = array();
-
- foreach ($old_attrs[$attr] as $value) {
- if (strtolower($value) != strtolower($new_attrs[$attr])) {
- $_attr_to_remove[] = $value;
- }
- }
-
- $this->_debug("Adding to delete attribute $attr values:" . implode(', ', $_attr_to_remove));
-
- $mod_array['del'][$attr] = $_attr_to_remove;
-
- if (strtolower($new_attrs[$attr]) !== strtolower($rdn_attr_value)) {
- $this->_debug("new attrs is not the same as the old rdn value, issuing a rename");
- $mod_array['rename']['dn'] = $subject_dn;
- $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . $new_attrs[$attr][0];
- }
- }
- else {
- $this->_debug("new attrs is not the same as any of the old rdn value, issuing a full rename");
- $mod_array['rename']['dn'] = $subject_dn;
- $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . $new_attrs[$attr];
- }
- }
- else {
- // TODO: See if the rdn attr. value is still in $new_attrs[$attr]
- if (in_array($old_attrs[$attr][0], $new_attrs[$attr])) {
- $this->_debug("Simply replacing attr $attr as rdn attr value is preserved.");
- $mod_array['replace'][$attr] = $new_attrs[$attr];
- }
- else {
- // TODO: This fails.
- $mod_array['rename']['dn'] = $subject_dn;
- $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . $new_attrs[$attr][0];
- $mod_array['del'][$attr] = $old_attrs[$attr][0];
- }
- }
- }
- else {
- if (!is_array($new_attrs[$attr])) {
- $this->_debug("Renaming " . $old_attrs[$attr] . " to " . $new_attrs[$attr]);
- $mod_array['rename']['dn'] = $subject_dn;
- $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . $new_attrs[$attr];
- }
- else {
- $this->_debug("Adding to replace");
- // An additional attribute value is being supplied. Just replace and continue.
- $mod_array['replace'][$attr] = $new_attrs[$attr];
- continue;
- }
- }
-
- }
- else {
- if (!isset($new_attrs[$attr]) || $new_attrs[$attr] === '' || (is_array($new_attrs[$attr]) && empty($new_attrs[$attr]))) {
- switch ($attr) {
- case "userpassword":
- break;
- default:
- $this->_debug("Adding to del: $attr");
- $mod_array['del'][$attr] = (array)($old_attr_value);
- break;
- }
- }
- else {
- $this->_debug("Adding to replace: $attr");
- $mod_array['replace'][$attr] = (array)($new_attrs[$attr]);
- }
- }
- }
- else {
- $this->_debug("Attribute $attr unchanged");
- }
- }
- else {
- // TODO: Since we're not shipping the entire object back and forth, and only post
- // part of the data... we don't know what is actually removed (think modifiedtimestamp, etc.)
- $this->_debug("Group attribute $attr not mentioned in \$new_attrs..., but not explicitly removed... by assumption");
- }
- }
-
- foreach ($new_attrs as $attr => $value) {
- // OU's parent base dn
- if ($attr == 'base_dn') {
- continue;
- }
-
- if (is_array($value)) {
- if (count($value) == 1) {
- $new_attrs[$attr] = $value[0];
- $value = $new_attrs[$attr];
- }
- }
-
- if (array_key_exists($attr, $old_attrs)) {
- if (is_array($old_attrs[$attr])) {
- if (count($old_attrs[$attr]) == 1) {
- $old_attrs[$attr] = $old_attrs[$attr][0];
- }
- }
-
- if (is_array($new_attrs[$attr]) && is_array($old_attrs[$attr])) {
- $_sort1 = $old_attrs[$attr];
- sort($_sort1);
- $_sort2 = $value;
- sort($_sort2);
- }
- else {
- $_sort1 = true;
- $_sort2 = false;
- }
-
- if ($value === null || $value === '' || (is_array($value) && empty($value))) {
- if (!array_key_exists($attr, $mod_array['del'])) {
- switch ($attr) {
- case 'userpassword':
- break;
- default:
- $this->_debug("Adding to del(2): $attr");
- $mod_array['del'][$attr] = (array)($old_attrs[$attr]);
- break;
- }
- }
- }
- else {
- if (!($old_attrs[$attr] === $value) && !($attr === $rdn_attr) && !($_sort1 === $_sort2)) {
- if (!array_key_exists($attr, $mod_array['replace'])) {
- $this->_debug("Adding to replace(2): $attr");
- $mod_array['replace'][$attr] = $value;
- }
- }
- }
- }
- else {
- if (!empty($value)) {
- $mod_array['add'][$attr] = $value;
- }
- }
- }
-
- if (empty($old_ou)) {
- $subject_dn_components = ldap_explode_dn($subject_dn, 0);
- unset($subject_dn_components["count"]);
- $subject_rdn = array_shift($subject_dn_components);
- $old_ou = implode(',', $subject_dn_components);
- }
-
- // object is an organizational unit
- if (strpos($subject_dn, 'ou=' . $old_ou) === 0) {
- $root = substr($subject_dn, strlen($old_ou) + 4); // remove ou=*,
-
- if ((!empty($new_attrs['base_dn']) && strtolower($new_attrs['base_dn']) !== strtolower($root))
- || (strtolower($old_ou) !== strtolower($new_ou))
- ) {
- if (!empty($new_attrs['base_dn'])) {
- $root = $new_attrs['base_dn'];
- }
-
- $mod_array['rename']['new_parent'] = $root;
- $mod_array['rename']['dn'] = $subject_dn;
- $mod_array['rename']['new_rdn'] = 'ou=' . $new_ou;
- }
- }
- // not OU object, but changed ou attribute
- else if ((!empty($old_ou) && !empty($new_ou)) && strtolower($old_ou) !== strtolower($new_ou)) {
- $mod_array['rename']['new_parent'] = $new_ou;
- if (empty($mod_array['rename']['dn']) || empty($mod_array['rename']['new_rdn'])) {
- $mod_array['rename']['dn'] = $subject_dn;
- $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . $new_attrs[$rdn_attr];
- }
- }
-
- $this->_debug($mod_array);
-
- $result = $this->modify_entry_attributes($subject_dn, $mod_array);
-
- if ($result) {
- return $mod_array;
- }
- }
-
- /**
- * Bind connection with (SASL-) user and password
- *
- * @param string $authc Authentication user
- * @param string $pass Bind password
- * @param string $authz Autorization user
- *
- * @return boolean True on success, False on error
- */
- public function sasl_bind($authc, $pass, $authz=null)
- {
- if (!$this->conn) {
- return false;
- }
-
- if (!function_exists('ldap_sasl_bind')) {
- $this->_error("Unable to bind: ldap_sasl_bind() not exists");
- return false;
- }
-
- if (!empty($authz)) {
- $authz = 'u:' . $authz;
- }
-
- $method = $this->config_get('auth_method');
- if (empty($method)) {
- $method = 'DIGEST-MD5';
- }
-
- $this->_debug("C: Bind [mech: $method, authc: $authc, authz: $authz]");
-
- if (ldap_sasl_bind($this->conn, null, $pass, $method, null, $authc, $authz)) {
- $this->_debug("S: OK");
- return true;
- }
-
- $this->_debug("S: ".ldap_error($this->conn));
- $this->_error("Bind failed for authcid=$authc ".ldap_error($this->conn));
-
- return false;
- }
-
- /**
- * Execute LDAP search
- *
- * @param string $base_dn Base DN to use for searching
- * @param string $filter Filter string to query
- * @param string $scope The LDAP scope (list|sub|base)
- * @param array $attrs List of entry attributes to read
- * @param array $prop Hash array with query configuration properties:
- * - sort: array of sort attributes (has to be in sync with the VLV index)
- * - search: search string used for VLV controls
- * @param bool $count_only Set to true if only entry count is requested
- *
- * @return mixed Net_LDAP3_Result object or number of entries (if $count_only=true) or False on failure
- */
- public function search($base_dn, $filter = '(objectclass=*)', $scope = 'sub', $attrs = array('dn'), $props = array(), $count_only = false)
- {
- if (!$this->conn) {
- $this->_debug("No active connection for " . __CLASS__ . "::" . __FUNCTION__);
- return false;
- }
-
- $this->_debug("C: Search base dn: [$base_dn] scope [$scope] with filter [$filter]");
-
- // make sure attributes list is not empty
- if (empty($attrs)) {
- $attrs = array('dn');
- }
-
- if (!$count_only && ($sort = $this->find_vlv($base_dn, $filter, $scope, $props['sort']))) {
- // when using VLV, we get the total count by...
- // ...either reading numSubOrdinates attribute
- if (($sub_filter = $this->config_get('numsub_filter')) &&
- ($result_count = @$ns_function($this->conn, $base_dn, $sub_filter, array('numSubOrdinates'), 0, 0, 0))
- ) {
- $counts = ldap_get_entries($this->conn, $result_count);
- for ($vlv_count = $j = 0; $j < $counts['count']; $j++) {
- $vlv_count += $counts[$j]['numsubordinates'][0];
- }
- $this->_debug("D: total numsubordinates = " . $vlv_count);
- }
- // ...or by fetching all records dn and count them
- else if (!function_exists('ldap_parse_virtuallist_control')) {
- $vlv_count = $this->search($base_dn, $filter, $scope, array('dn'), $props, true);
- }
-
- $this->vlv_active = $this->_vlv_set_controls($sort, $this->list_page, $this->page_size,
- $this->_vlv_search($sort, $props['search']));
- }
- else {
- $this->vlv_active = false;
- }
-
- $function = self::scope_to_function($scope, $ns_function);
- $sizelimit = (int) $this->config['sizelimit'];
- $timelimit = (int) $this->config['timelimit'];
-
- $this->_debug("Using function $function on scope $scope (\$ns_function is $ns_function)");
-
- if ($this->vlv_active) {
- if (!empty($this->additional_filter)) {
- $filter = "(&" . $filter . $this->additional_filter . ")";
- $this->_debug("C: (With VLV) Setting a filter (with additional filter) of " . $filter);
- }
- else {
- $this->_debug("C: (With VLV) Setting a filter (without additional filter) of " . $filter);
- }
- }
- else {
- if (!empty($this->additional_filter)) {
- $filter = "(&" . $filter . $this->additional_filter . ")";
- }
- $this->_debug("C: (Without VLV) Setting a filter of " . $filter);
- }
-
- $this->_debug("Executing search with return attributes: " . var_export($attrs, true));
-
- $ldap_result = @$function($this->conn, $base_dn, $filter, $attrs, 0, $sizelimit, $timelimit);
-
- if (!$ldap_result) {
- $this->_debug("$function failed for dn=$base_dn: ".ldap_error($this->conn));
- return false;
- }
-
- // when running on a patched PHP we can use the extended functions
- // to retrieve the total count from the LDAP search result
- if ($this->vlv_active && function_exists('ldap_parse_virtuallist_control')) {
- if (ldap_parse_result($this->conn, $ldap_result, $errcode, $matcheddn, $errmsg, $referrals, $serverctrls)) {
- ldap_parse_virtuallist_control($this->conn, $serverctrls, $last_offset, $vlv_count, $vresult);
- $this->_debug("S: VLV result: last_offset=$last_offset; content_count=$vlv_count");
- }
- else {
- $this->_debug("S: ".($errmsg ? $errmsg : ldap_error($this->conn)));
- }
- }
- else if ($this->debug) {
- $this->_debug("S: ".ldap_count_entries($this->conn, $ldap_result)." record(s) found");
- }
-
- $result = new Net_LDAP3_Result($this->conn, $base_dn, $filter, $scope, $ldap_result);
- $result->set('offset', $last_offset);
- $result->set('count', $vlv_count);
- $result->set('vlv', true);
-
- return $count_only ? $result->count() : $result;
- }
-
- /**
- * Similar to Net_LDAP3::search() but using a search array with multiple
- * keys and values that to continue to use the VLV but with an original
- * filter adding the search stuff to an additional filter.
- *
- * @see Net_LDAP3::search()
- */
- public function search_entries($base_dn, $filter = '(objectclass=*)', $scope = 'sub', $attrs = array('dn'), $props = array())
- {
- $this->_debug("Net_LDAP3::search_entries with search " . var_export($props, true));
-
- if (is_array($props['search']) && array_key_exists('params', $props['search'])) {
- $_search = $this->search_filter($props['search']);
- $this->_debug("C: Search filter: $_search");
-
- if (!empty($_search)) {
- $this->additional_filter = $_search;
- }
- else {
- $this->additional_filter = "(|";
-
- foreach ($props['search'] as $attr => $value) {
- $this->additional_filter .= "(" . $attr . "=" . $this->_fuzzy_search_prefix() . $value . $this->_fuzzy_search_suffix() . ")";
- }
-
- $this->additional_filter .= ")";
- }
-
- $this->_debug("C: Setting an additional filter " . $this->additional_filter);
- }
-
- $search = $this->search($base_dn, $filter, $scope, $attrs, $props);
-
- $this->additional_filter = null;
-
- if (!$search) {
- $this->_debug("Net_LDAP3: Search did not succeed!");
- return false;
- }
-
- return $search;
- }
-
- /**
- * Create LDAP search filter string according to defined parameters.
- */
- public function search_filter($search)
- {
- if (empty($search) || !is_array($search) || empty($search['params'])) {
- return null;
- }
-
- $operators = array('=', '~=', '>=', '<=');
- $filter = '';
-
- foreach ((array) $search['params'] as $field => $param) {
- switch ((string)$param['type']) {
- case 'prefix':
- $prefix = '';
- $suffix = '*';
- break;
-
- case 'suffix':
- $prefix = '*';
- $suffix = '';
- break;
-
- case 'exact':
- case '=':
- case '~=':
- case '>=':
- case '<=':
- $prefix = '';
- $suffix = '';
- break;
-
- case 'exists':
- $prefix = '*';
- $suffix = '';
- $param['value'] = '';
- break;
-
- case 'both':
- default:
- $prefix = '*';
- $suffix = '*';
- break;
- }
-
- $operator = $param['type'] && in_array($param['type'], $operators) ? $param['type'] : '=';
-
- if (is_array($param['value'])) {
- $val_filter = array();
- foreach ($param['value'] as $val) {
- $value = self::quote_string($val);
- $val_filter[] = "(" . $field . $operator . $prefix . $value . $suffix . ")";
- }
- $filter .= "(|" . implode($val_filter, '') . ")";
- }
- else {
- $value = self::quote_string($param['value']);
- $filter .= "(" . $field . $operator . $prefix . $value . $suffix . ")";
- }
- }
-
- // join search parameters with specified operator ('OR' or 'AND')
- if (count($search['params']) > 1) {
- $filter = '(' . ($search['operator'] == 'AND' ? '&' : '|') . $filter . ')';
- }
-
- return $filter;
- }
-
- /**
- * Set properties for VLV-based paging
- *
- * @param number $page Page number to list (starting at 1)
- * @param number $size Number of entries to display on one page
- */
- public function set_vlv_page($page, $size = 10)
- {
- $this->list_page = $page;
- $this->page_size = $size;
- }
-
- /**
- * Turn an LDAP entry into a regular PHP array with attributes as keys.
- *
- * @param array $entry Attributes array as retrieved from ldap_get_attributes() or ldap_get_entries()
- *
- * @return array Hash array with attributes as keys
- */
- public static function normalize_entry($entry)
- {
- $rec = array();
- for ($i=0; $i < $entry['count']; $i++) {
- $attr = $entry[$i];
- for ($j=0; $j < $entry[$attr]['count']; $j++) {
- $rec[$attr][$j] = $entry[$attr][$j];
- }
- }
-
- return $rec;
- }
-
- /**
- * Normalize a ldap result by converting entry attribute arrays into single values
- */
- public static function normalize_result($_result)
- {
- if (!is_array($_result)) {
- return array();
- }
-
- $result = array();
-
- for ($x = 0; $x < $_result['count']; $x++) {
- $dn = $_result[$x]['dn'];
- $result[$dn] = array();
- for ($y = 0; $y < $_result[$x]['count']; $y++) {
- $attr = $_result[$x][$y];
- if ($_result[$x][$attr]['count'] == 1) {
- switch ($attr) {
- case 'objectclass':
- $result[$dn][$attr] = array(strtolower($_result[$x][$attr][0]));
- break;
- default:
- $result[$dn][$attr] = $_result[$x][$attr][0];
- break;
- }
- }
- else {
- $result[$dn][$attr] = array();
- for ($z = 0; $z < $_result[$x][$attr]['count']; $z++) {
- switch ($attr) {
- case 'objectclass':
- $result[$dn][$attr][] = strtolower($_result[$x][$attr][$z]);
- break;
- default:
- $result[$dn][$attr][] = $_result[$x][$attr][$z];
- break;
- }
- }
- }
- }
- }
-
- return $result;
- }
-
- public static function scopeint2str($scope)
- {
- switch ($scope) {
- case 2:
- return 'sub';
- break;
- case 1:
- return 'one';
- break;
- case 0:
- return 'base';
- break;
- default:
- $this->_debug("Scope $scope is not a valid scope integer");
- break;
- }
- }
-
- /**
- * Choose the right PHP function according to scope property
- *
- * @param string $scope The LDAP scope (sub|base|list)
- * @param string $ns_function Function to be used for numSubOrdinates queries
- * @return string PHP function to be used to query directory
- */
- public static function scope_to_function($scope, &$ns_function = null)
- {
- switch ($scope) {
- case 'sub':
- $function = $ns_function = 'ldap_search';
- break;
- case 'base':
- $function = $ns_function = 'ldap_read';
- break;
- case 'one':
- case 'list':
- default:
- $function = 'ldap_list';
- $ns_function = 'ldap_read';
- break;
- }
-
- return $function;
- }
-
- private function config_set_config_get_hook($callback)
- {
- $this->_config_get_hook = $callback;
- }
-
- private function config_set_config_set_hook($callback)
- {
- $this->_config_set_hook = $callback;
- }
-
- /**
- * Sets the debug level both for this class and the ldap connection.
- */
- private function config_set_debug($value)
- {
- $this->config['debug'] = (bool) $value;
- if ((int)($value) > 0) {
- ldap_set_option(null, LDAP_OPT_DEBUG_LEVEL, (int)($value));
- }
- }
-
- /**
- * Sets a log hook that is called with every log message in this module.
- */
- private function config_set_log_hook($callback)
- {
- $this->_log_hook = $callback;
- }
-
- /**
- * Find a matching VLV
- */
- protected function find_vlv($base_dn, $filter, $scope, $sort_attrs = null)
- {
- if ($scope == 'base') {
- return false;
- }
-
- $vlv_indexes = $this->find_vlv_indexes_and_searches();
-
- if (empty($vlv_indexes)) {
- return false;
- }
-
- $this->_debug("Existing vlv index and search information", $vlv_indexes);
-
- $filter = strtolower($filter);
-
- foreach ($vlv_indexes as $vlv_index) {
- if (!empty($vlv_index[$base_dn])) {
- $this->_debug("Found a VLV for base_dn: " . $base_dn);
- if ($vlv_index[$base_dn]['filter'] == $filter) {
- if ($vlv_index[$base_dn]['scope'] == $scope) {
- $this->_debug("Scope and filter matches");
-
- // Not passing any sort attributes means you don't care
- if (!empty($sort_attrs)) {
- $sort_attrs = (array) $sort_attrs;
- foreach ($vlv_index[$base_dn]['sort'] as $sss_config) {
- if (count(array_intersect($sort_attrs, $sss_config)) == count($sort_attrs)) {
- return $sort_attrs;
- }
- }
-
- $this->_error("The requested sorting does not match any server-side sorting configuration");
-
- return false;
- }
- else {
- return $vlv_index[$base_dn]['sort'][0];
- }
- }
- else {
- $this->_debug("Scope does not match. VLV: " . var_export($vlv_index[$base_dn]['scope'], true)
- . " while looking for " . var_export($scope, true));
- return false;
- }
- }
- else {
- $this->_debug("Filter does not match");
- }
- }
- }
-
- return false;
- }
-
- /**
- * Return VLV indexes and searches including necessary configuration
- * details.
- */
- protected function find_vlv_indexes_and_searches()
- {
- if ($this->config['vlv'] === false) {
- return false;
- }
-
- if (is_array($this->config['vlv'])) {
- return $this->config['vlv'];
- }
-
- if ($this->_vlv_indexes_and_searches !== null) {
- return $this->_vlv_indexes_and_searches;
- }
-
- $this->_vlv_indexes_and_searches = array();
-
- $config_root_dn = $this->config_get('config_root_dn');
-
- if (empty($config_root_dn)) {
- return array();
- }
-
- if ($this->cache && ($cached_config = $this->cache->get('vlvconfig'))) {
- $this->_vlv_indexes_and_searches = $cached_config;
- return $this->_vlv_indexes_and_searches;
- }
-
- $this->_debug("No VLV information available yet, refreshing");
-
- $search_filter = '(objectclass=vlvsearch)';
- $search_result = ldap_search($this->conn, $config_root_dn, $search_filter, array('*'), 0, 0, 0);
-
- if ($search_result === false) {
- $this->_debug("Search for '$search_filter' on '$config_root_dn' failed:".ldap_error($this->conn));
- return;
- }
-
- $vlv_searches = new Net_LDAP3_Result($this->conn, $config_root_dn, $search_filter, 'sub', $search_result);
-
- if ($vlv_searches->count() < 1) {
- $this->_debug("Empty result from search for '(objectclass=vlvsearch)' on '$config_root_dn'");
- return;
- }
-
- $index_filter = '(objectclass=vlvindex)';
-
- foreach ($vlv_searches->entries(true) as $vlv_search_dn => $vlv_search_attrs) {
- // The attributes we are interested in are as follows:
- $_vlv_base_dn = $vlv_search_attrs['vlvbase'];
- $_vlv_scope = $vlv_search_attrs['vlvscope'];
- $_vlv_filter = $vlv_search_attrs['vlvfilter'];
-
- // Multiple indexes may exist
- $index_result = ldap_search($this->conn, $vlv_search_dn, $index_filter, array('*'), 0, 0, 0);
-
- if ($index_result === false) {
- $this->_debug("Search for '$index_filter' on '$vlv_search_dn' failed:".ldap_error($this->conn));
- continue;
- }
-
- $vlv_indexes = new Net_LDAP3_Result($this->conn, $vlv_search_dn, $index_filter, 'sub', $index_result);
- $vlv_indexes = $vlv_indexes->entries(true);
-
- // Reset this one for each VLV search.
- $_vlv_sort = array();
-
- foreach ($vlv_indexes as $vlv_index_dn => $vlv_index_attrs) {
- $_vlv_sort[] = explode(' ', $vlv_index_attrs['vlvsort']);
- }
-
- $this->_vlv_indexes_and_searches[] = array(
- $_vlv_base_dn => array(
- 'scope' => self::scopeint2str($_vlv_scope),
- 'filter' => strtolower($_vlv_filter),
- 'sort' => $_vlv_sort,
- ),
- );
- }
-
- // cache this
- if ($this->cache) {
- $this->cache->set('vlvconfig', $this->_vlv_indexes_and_searches);
- }
-
- return $this->_vlv_indexes_and_searches;
- }
-
- private function init_schema()
- {
- // use PEAR include if autoloading failed
- if (!class_exists('Net_LDAP2')) {
- require_once('Net/LDAP2.php');
- }
-
- $port = $this->config_get('port', 389);
- $tls = $this->config_get('use_tls', false);
-
- foreach ((array) $this->config_get('hosts') as $host) {
- $this->_debug("C: Connect [$host:$port]");
-
- $_ldap_cfg = array(
- 'host' => $host,
- 'port' => $port,
- 'tls' => $tls,
- 'version' => 3,
- 'binddn' => $this->config_get('service_bind_dn'),
- 'bindpw' => $this->config_get('service_bind_pw')
- );
-
- $_ldap_schema_cache_cfg = array(
- 'path' => "/tmp/" . $host . ":" . ($port ? $port : '389') . "-Net_LDAP2_Schema.cache",
- 'max_age' => 86400,
- );
-
- $_ldap = Net_LDAP2::connect($_ldap_cfg);
-
- if (!is_a($_ldap, 'Net_LDAP2_Error')) {
- $this->_debug("S: OK");
- break;
- }
-
- $this->_debug("S: NOT OK");
- $this->_debug($_ldap->getMessage());
- }
-
- if (is_a($_ldap, 'Net_LDAP2_Error')) {
- return null;
- }
-
- $_ldap_schema_cache = new Net_LDAP2_SimpleFileSchemaCache($_ldap_schema_cache_cfg);
-
- $_ldap->registerSchemaCache($_ldap_schema_cache);
-
- // TODO: We should learn what LDAP tech. we're running against.
- // Perhaps with a scope base objectclass recognize rootdse entry
- $schema_root_dn = $this->config_get('schema_root_dn');
-
- if (!$schema_root_dn) {
- $_schema = $_ldap->schema();
- }
-
- return $_schema;
- }
-
- private function list_group_member($dn, $members, $recurse = true)
- {
- $this->_debug("Called list_group_member(" . $dn . ")");
-
- $members = (array) $members;
- $group_members = array();
-
- // remove possible 'count' item
- unset($members['count']);
-
- // Use the member attributes to return an array of member ldap objects
- // NOTE that the member attribute is supposed to contain a DN
- foreach ($members as $member) {
- $member_entry = $this->get_entry($member, array('member', 'uniquemember', 'memberurl', 'objectclass'));
-
- if (empty($member_entry)) {
- continue;
- }
-
- $group_members[$member] = $member;
-
- if ($recurse) {
- // Nested groups
- $group_group_members = $this->list_group_members($member, $member_entry);
- if ($group_group_members) {
- $group_members = array_merge($group_group_members, $group_members);
- }
- }
- }
-
- return array_filter($group_members);
- }
-
- private function list_group_uniquemember($dn, $uniquemembers, $recurse = true)
- {
- $this->_debug("Called list_group_uniquemember(" . $dn . ")", $entry);
-
- $uniquemembers = (array)($uniquemembers);
- $group_members = array();
-
- // remove possible 'count' item
- unset($uniquemembers['count']);
-
- foreach ($uniquemembers as $member) {
- $member_entry = $this->get_entry($member, array('member', 'uniquemember', 'memberurl', 'objectclass'));
-
- if (empty($member_entry)) {
- continue;
- }
-
- $group_members[$member] = $member;
-
- if ($recurse) {
- // Nested groups
- $group_group_members = $this->list_group_members($member, $member_entry);
- if ($group_group_members) {
- $group_members = array_merge($group_group_members, $group_members);
- }
- }
- }
-
- return array_filter($group_members);
- }
-
- private function list_group_memberurl($dn, $memberurls, $recurse = true)
- {
- $this->_debug("Called list_group_memberurl(" . $dn . ")");
-
- $group_members = array();
- $memberurls = (array) $memberurls;
- $attributes = array('member', 'uniquemember', 'memberurl', 'objectclass');
-
- // remove possible 'count' item
- unset($memberurls['count']);
-
- foreach ($memberurls as $url) {
- $ldap_uri = $this->parse_memberurl($url);
- $result = $this->search($ldap_uri[3], $ldap_uri[6], 'sub', $attributes);
-
- if (!$result) {
- continue;
- }
-
- foreach ($result->entries(true) as $entry_dn => $_entry) {
- $group_members[$entry_dn] = $entry_dn;
- $this->_debug("Found " . $entry_dn);
-
- if ($recurse) {
- // Nested group
- $group_group_members = $this->list_group_members($entry_dn, $_entry);
- if ($group_group_members) {
- $group_members = array_merge($group_members, $group_group_members);
- }
- }
- }
- }
-
- return array_filter($group_members);
- }
-
- /**
- * memberUrl attribute parser
- *
- * @param string $url URL string
- *
- * @return array URL elements
- */
- private function parse_memberurl($url)
- {
- preg_match('/(.*):\/\/(.*)\/(.*)\?(.*)\?(.*)\?(.*)/', $url, $matches);
- return $matches;
- }
-
- private function modify_entry_attributes($subject_dn, $attributes)
- {
- // Opportunities to set false include failed ldap commands.
- $result = true;
-
- if (is_array($attributes['rename']) && !empty($attributes['rename'])) {
- $olddn = $attributes['rename']['dn'];
- $newrdn = $attributes['rename']['new_rdn'];
-
- if (!empty($attributes['rename']['new_parent'])) {
- $new_parent = $attributes['rename']['new_parent'];
- }
- else {
- $new_parent = null;
- }
-
- $this->_debug("LDAP: C: Rename $olddn to $newrdn,$new_parent");
-
- $result = ldap_rename($this->conn, $olddn, $newrdn, $new_parent, true);
-
- if ($result) {
- $this->_debug("LDAP: S: OK");
-
- if ($new_parent) {
- $subject_dn = $newrdn . ',' . $new_parent;
- }
- else {
- $old_parent_dn_components = ldap_explode_dn($olddn, 0);
- unset($old_parent_dn_components["count"]);
- $old_rdn = array_shift($old_parent_dn_components);
- $old_parent_dn = implode(",", $old_parent_dn_components);
- $subject_dn = $newrdn . ',' . $old_parent_dn;
- }
- }
- else {
- $this->_debug("LDAP: S: " . ldap_error($this->conn));
- $this->_warning("LDAP: Failed to rename $olddn to $newrdn,$new_parent");
- return false;
- }
- }
-
- if (is_array($attributes['replace']) && !empty($attributes['replace'])) {
- $this->_debug("LDAP: C: Mod-Replace $subject_dn: " . json_encode($attributes['replace']));
-
- $result = ldap_mod_replace($this->conn, $subject_dn, $attributes['replace']);
-
- if ($result) {
- $this->_debug("LDAP: S: OK");
- }
- else {
- $this->_debug("LDAP: S: " . ldap_error($this->conn));
- $this->_warning("LDAP: Failed to replace attributes on $subject_dn: " . json_encode($attributes['replace']));
- return false;
- }
- }
-
- if (is_array($attributes['del']) && !empty($attributes['del'])) {
- $this->_debug("LDAP: C: Mod-Delete $subject_dn: " . json_encode($attributes['del']));
-
- $result = ldap_mod_del($this->conn, $subject_dn, $attributes['del']);
-
- if ($result) {
- $this->_debug("LDAP: S: OK");
- }
- else {
- $this->_debug("LDAP: S: " . ldap_error($this->conn));
- $this->_warning("LDAP: Failed to delete attributes on $subject_dn: " . json_encode($attributes['del']));
- return false;
- }
- }
-
- if (is_array($attributes['add']) && !empty($attributes['add'])) {
- $this->_debug("LDAP: C: Mod-Add $subject_dn: " . json_encode($attributes['add']));
-
- $result = ldap_mod_add($this->conn, $subject_dn, $attributes['add']);
-
- if ($result) {
- $this->_debug("LDAP: S: OK");
- }
- else {
- $this->_debug("LDAP: S: " . ldap_error($this->conn));
- $this->_warning("LDAP: Failed to add attributes on $subject_dn: " . json_encode($attributes['add']));
- return false;
- }
- }
-
- return true;
- }
-
- private function parse_attribute_level_rights($attribute_value)
- {
- $attribute_value = str_replace(", ", ",", $attribute_value);
- $attribute_values = explode(",", $attribute_value);
- $attribute_value = array();
-
- foreach ($attribute_values as $access_right) {
- $access_right_components = explode(":", $access_right);
- $access_attribute = strtolower(array_shift($access_right_components));
- $access_value = array_shift($access_right_components);
-
- $attribute_value[$access_attribute] = array();
-
- for ($i = 0; $i < strlen($access_value); $i++) {
- $method = $this->attribute_level_rights_map[substr($access_value, $i, 1)];
-
- if (!in_array($method, $attribute_value[$access_attribute])) {
- $attribute_value[$access_attribute][] = $method;
- }
- }
- }
-
- return $attribute_value;
- }
-
- private function parse_entry_level_rights($attribute_value)
- {
- $_attribute_value = array();
-
- for ($i = 0; $i < strlen($attribute_value); $i++) {
- $method = $this->entry_level_rights_map[substr($attribute_value, $i, 1)];
-
- if (!in_array($method, $_attribute_value)) {
- $_attribute_value[] = $method;
- }
- }
-
- return $_attribute_value;
- }
-
- private function supported_controls()
- {
- if (!empty($this->supported_controls)) {
- return $this->supported_controls;
- }
-
- $this->_info("Obtaining supported controls");
-
- if ($result = $this->search('', '(objectclass=*)', 'base', array('supportedcontrol'))) {
- $result = $result->entries(true);
- $control = $result['']['supportedcontrol'];
- }
- else {
- $control = array();
- }
-
- $this->_info("Obtained " . count($control) . " supported controls");
- $this->supported_controls = $control;
-
- return $control;
- }
-
- protected function _alert()
- {
- $this->__log(LOG_ALERT, func_get_args());
- }
-
- protected function _critical()
- {
- $this->__log(LOG_CRIT, func_get_args());
- }
-
- protected function _debug()
- {
- $this->__log(LOG_DEBUG, func_get_args());
- }
-
- protected function _emergency()
- {
- $this->__log(LOG_EMERG, func_get_args());
- }
-
- protected function _error()
- {
- $this->__log(LOG_ERR, func_get_args());
- }
-
- protected function _info()
- {
- $this->__log(LOG_INFO, func_get_args());
- }
-
- protected function _notice()
- {
- $this->__log(LOG_NOTICE, func_get_args());
- }
-
- protected function _warning()
- {
- $this->__log(LOG_WARNING, func_get_args());
- }
-
- /**
- * Log a message.
- */
- private function __log($level, $args)
- {
- $msg = array();
-
- foreach ($args as $arg) {
- $msg[] = !is_string($arg) ? var_export($arg, true) : $arg;
- }
-
- if (!empty($this->_log_hook)) {
- call_user_func_array($this->_log_hook, array($level, $msg));
- return;
- }
-
- if ($this->debug_level > 0) {
- syslog($level, implode("\n", $msg));
- }
- }
-
- /**
- * Add BER sequence with correct length and the given identifier
- */
- private static function _ber_addseq($str, $identifier)
- {
- $len = dechex(strlen($str)/2);
- if (strlen($len) % 2 != 0) {
- $len = '0'.$len;
- }
-
- return $identifier . $len . $str;
- }
-
- /**
- * Returns BER encoded integer value in hex format
- */
- private static function _ber_encode_int($offset)
- {
- $val = dechex($offset);
- $prefix = '';
-
- // check if bit 8 of high byte is 1
- if (preg_match('/^[89abcdef]/', $val)) {
- $prefix = '00';
- }
-
- if (strlen($val)%2 != 0) {
- $prefix .= '0';
- }
-
- return $prefix . $val;
- }
-
- /**
- * Quotes attribute value string
- *
- * @param string $str Attribute value
- * @param bool $dn True if the attribute is a DN
- *
- * @return string Quoted string
- */
- public static function quote_string($str, $is_dn = false)
- {
- // take firt entry if array given
- if (is_array($str)) {
- $str = reset($str);
- }
-
- if ($is_dn) {
- $replace = array(
- ',' => '\2c',
- '=' => '\3d',
- '+' => '\2b',
- '<' => '\3c',
- '>' => '\3e',
- ';' => '\3b',
- "\\"=> '\5c',
- '"' => '\22',
- '#' => '\23'
- );
- }
- else {
- $replace = array(
- '*' => '\2a',
- '(' => '\28',
- ')' => '\29',
- "\\" => '\5c',
- '/' => '\2f'
- );
- }
-
- return strtr($str, $replace);
- }
-
- /**
- * create ber encoding for sort control
- *
- * @param array List of cols to sort by
- * @return string BER encoded option value
- */
- private static function _sort_ber_encode($sortcols)
- {
- $str = '';
- foreach (array_reverse((array)$sortcols) as $col) {
- $ber_val = self::_string2hex($col);
-
- // 30 = ber sequence with a length of octet value
- // 04 = octet string with a length of the ascii value
- $oct = self::_ber_addseq($ber_val, '04');
- $str = self::_ber_addseq($oct, '30') . $str;
- }
-
- // now tack on sequence identifier and length
- $str = self::_ber_addseq($str, '30');
-
- return pack('H'.strlen($str), $str);
- }
-
- /**
- * Returns ascii string encoded in hex
- */
- private static function _string2hex($str)
- {
- $hex = '';
- for ($i=0; $i < strlen($str); $i++)
- $hex .= dechex(ord($str[$i]));
-
- return $hex;
- }
-
- /**
- * Generate BER encoded string for Virtual List View option
- *
- * @param integer List offset (first record)
- * @param integer Records per page
- * @return string BER encoded option value
- */
- private static function _vlv_ber_encode($offset, $rpp, $search = '')
- {
- // This string is ber-encoded, php will prefix this value with:
- // 04 (octet string) and 10 (length of 16 bytes)
- // the code behind this string is broken down as follows:
- // 30 = ber sequence with a length of 0e (14) bytes following
- // 02 = type integer (in two's complement form) with 2 bytes following (beforeCount): 01 00 (ie 0)
- // 02 = type integer (in two's complement form) with 2 bytes following (afterCount): 01 18 (ie 25-1=24)
- // a0 = type context-specific/constructed with a length of 06 (6) bytes following
- // 02 = type integer with 2 bytes following (offset): 01 01 (ie 1)
- // 02 = type integer with 2 bytes following (contentCount): 01 00
-
- // whith a search string present:
- // 81 = type context-specific/constructed with a length of 04 (4) bytes following (the length will change here)
- // 81 indicates a user string is present where as a a0 indicates just a offset search
- // 81 = type context-specific/constructed with a length of 06 (6) bytes following
-
- // the following info was taken from the ISO/IEC 8825-1:2003 x.690 standard re: the
- // encoding of integer values (note: these values are in
- // two-complement form so since offset will never be negative bit 8 of the
- // leftmost octet should never by set to 1):
- // 8.3.2: If the contents octets of an integer value encoding consist
- // of more than one octet, then the bits of the first octet (rightmost) and bit 8
- // of the second (to the left of first octet) octet:
- // a) shall not all be ones; and
- // b) shall not all be zero
-
- if ($search) {
- $search = preg_replace('/[^-[:alpha:] ,.()0-9]+/', '', $search);
- $ber_val = self::_string2hex($search);
- $str = self::_ber_addseq($ber_val, '81');
- }
- else {
- // construct the string from right to left
- $str = "020100"; # contentCount
-
- // returns encoded integer value in hex format
- $ber_val = self::_ber_encode_int($offset);
-
- // calculate octet length of $ber_val
- $str = self::_ber_addseq($ber_val, '02') . $str;
-
- // now compute length over $str
- $str = self::_ber_addseq($str, 'a0');
- }
-
- // now tack on records per page
- $str = "020100" . self::_ber_addseq(self::_ber_encode_int($rpp-1), '02') . $str;
-
- // now tack on sequence identifier and length
- $str = self::_ber_addseq($str, '30');
-
- return pack('H'.strlen($str), $str);
- }
-
- private function _fuzzy_search_prefix()
- {
- switch ($this->config_get("fuzzy_search", 2)) {
- case 2:
- return "*";
- break;
- case 1:
- case 0:
- default:
- return "";
- break;
- }
- }
-
- private function _fuzzy_search_suffix()
- {
- switch ($this->config_get("fuzzy_search", 2)) {
- case 2:
- return "*";
- break;
- case 1:
- return "*";
- case 0:
- default:
- return "";
- break;
- }
- }
-
- /**
- * Return the search string value to be used in VLV controls
- */
- private function _vlv_search($sort, $search)
- {
- if (!empty($this->additional_filter)) {
- $this->_debug("Not setting a VLV search filter because we already have a filter");
- return;
- }
-
- if (empty($search)) {
- return;
- }
-
- $search_suffix = $this->_fuzzy_search_suffix();
-
- foreach ($search as $attr => $value) {
- if (!in_array(strtolower($attr), $sort)) {
- $this->_debug("Cannot use VLV search using attribute not indexed: $attr (not in " . var_export($sort, true) . ")");
- return;
- }
- else {
- return $value . $search_suffix;
- }
- }
- }
-
- /**
- * Set server controls for Virtual List View (paginated listing)
- */
- private function _vlv_set_controls($sort, $list_page, $page_size, $search = null)
- {
- $sort_ctrl = array(
- 'oid' => "1.2.840.113556.1.4.473",
- 'value' => self::_sort_ber_encode($sort)
- );
-
- if (!empty($search)) {
- $this->_debug("_vlv_set_controls to include search: " . var_export($search, true));
- }
-
- $vlv_ctrl = array(
- 'oid' => "2.16.840.1.113730.3.4.9",
- 'value' => self::_vlv_ber_encode(
- $offset = ($list_page-1) * $page_size + 1,
- $page_size,
- $search
- ),
- 'iscritical' => true
- );
-
- $this->_debug("C: set controls sort=" . join(' ', unpack('H'.(strlen($sort_ctrl['value'])*2), $sort_ctrl['value']))
- . " (" . implode(',', (array) $sort) . ");"
- . " vlv=" . join(' ', (unpack('H'.(strlen($vlv_ctrl['value'])*2), $vlv_ctrl['value']))) . " ($offset/$page_size)");
-
- if (!ldap_set_option($this->conn, LDAP_OPT_SERVER_CONTROLS, array($sort_ctrl, $vlv_ctrl))) {
- $this->_debug("S: ".ldap_error($this->conn));
- $this->set_error(self::ERROR_SEARCH, 'vlvnotsupported');
-
- return false;
- }
-
- return true;
- }
-
-}
diff --git a/program/lib/Net/LDAP3/Result.php b/program/lib/Net/LDAP3/Result.php
deleted file mode 100644
index 0759df087..000000000
--- a/program/lib/Net/LDAP3/Result.php
+++ /dev/null
@@ -1,152 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | Net/LDAP3/Result.php |
- | |
- | Based on code created by the Roundcube Webmail team. |
- | |
- | Copyright (C) 2006-2014, The Roundcube Dev Team |
- | Copyright (C) 2012-2014, Kolab Systems AG |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Provide advanced functionality for accessing LDAP directories |
- | |
- +-----------------------------------------------------------------------+
- | Authors: Thomas Bruederli <roundcube@gmail.com> |
- | Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Model class representing an LDAP search result
- *
- * @package LDAP
- */
-class Net_LDAP3_Result implements Iterator
-{
- protected $conn;
- protected $base_dn;
- protected $filter;
- protected $scope;
-
- private $count;
- private $current;
- private $iteratorkey = 0;
-
- /**
- * Default constructor
- *
- * @param resource $conn LDAP link identifier
- * @param string $base_dn Base DN used to get this result
- * @param string $filter Filter query used to get this result
- * @param string $scope Scope of the result
- * @param resource $result LDAP result entry identifier
- */
- function __construct($conn, $base_dn, $filter, $scope, $result)
- {
- $this->conn = $conn;
- $this->base_dn = $base_dn;
- $this->filter = $filter;
- $this->scope = $scope;
- $this->result = $result;
- }
-
- public function get($property, $default = null)
- {
- if (isset($this->$property)) {
- return $this->$property;
- } else {
- return $default;
- }
- }
-
- public function set($property, $value)
- {
- $this->$property = $value;
- }
-
- /**
- * Wrapper for ldap_sort()
- */
- public function sort($attr)
- {
- return ldap_sort($this->conn, $this->result, $attr);
- }
-
- /**
- * Get entries count
- */
- public function count()
- {
- if (!isset($this->count)) {
- $this->count = ldap_count_entries($this->conn, $this->result);
- }
-
- return $this->count;
- }
-
- /**
- * Wrapper for ldap_get_entries()
- *
- * @param bool $normalize Optionally normalize the entries to a list of hash arrays
- *
- * @return array List of LDAP entries
- */
- public function entries($normalize = false)
- {
- $entries = ldap_get_entries($this->conn, $this->result);
-
- if ($normalize) {
- return Net_LDAP3::normalize_result($entries);
- }
-
- return $entries;
- }
-
- /**
- * Wrapper for ldap_get_dn() using the current entry pointer
- */
- public function get_dn()
- {
- return $this->current ? ldap_get_dn($this->conn, $this->current) : null;
- }
-
-
- /*** Implement PHP 5 Iterator interface to make foreach work ***/
-
- function current()
- {
- $attrib = ldap_get_attributes($this->conn, $this->current);
- $attrib['dn'] = ldap_get_dn($this->conn, $this->current);
-
- return $attrib;
- }
-
- function key()
- {
- return $this->iteratorkey;
- }
-
- function rewind()
- {
- $this->iteratorkey = 0;
- $this->current = ldap_first_entry($this->conn, $this->result);
- }
-
- function next()
- {
- $this->iteratorkey++;
- $this->current = ldap_next_entry($this->conn, $this->current);
- }
-
- function valid()
- {
- return (bool)$this->current;
- }
-
-}
diff --git a/program/lib/Net/SMTP.php b/program/lib/Net/SMTP.php
deleted file mode 100644
index 2c1ef5c55..000000000
--- a/program/lib/Net/SMTP.php
+++ /dev/null
@@ -1,1338 +0,0 @@
-<?php
-/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP Version 4 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 of the PHP license, |
-// | that is bundled with this package in the file LICENSE, and is |
-// | available at through the world-wide-web at |
-// | http://www.php.net/license/2_02.txt. |
-// | If you did not receive a copy of the PHP license and are unable to |
-// | obtain it through the world-wide-web, please send a note to |
-// | license@php.net so we can mail you a copy immediately. |
-// +----------------------------------------------------------------------+
-// | Authors: Chuck Hagenbuch <chuck@horde.org> |
-// | Jon Parise <jon@php.net> |
-// | Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar> |
-// +----------------------------------------------------------------------+
-
-require_once 'PEAR.php';
-require_once 'Net/Socket.php';
-
-/**
- * Provides an implementation of the SMTP protocol using PEAR's
- * Net_Socket:: class.
- *
- * @package Net_SMTP
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @author Jon Parise <jon@php.net>
- * @author Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar>
- *
- * @example basic.php A basic implementation of the Net_SMTP package.
- */
-class Net_SMTP
-{
- /**
- * The server to connect to.
- * @var string
- * @access public
- */
- var $host = 'localhost';
-
- /**
- * The port to connect to.
- * @var int
- * @access public
- */
- var $port = 25;
-
- /**
- * The value to give when sending EHLO or HELO.
- * @var string
- * @access public
- */
- var $localhost = 'localhost';
-
- /**
- * List of supported authentication methods, in preferential order.
- * @var array
- * @access public
- */
- var $auth_methods = array();
-
- /**
- * Use SMTP command pipelining (specified in RFC 2920) if the SMTP
- * server supports it.
- *
- * When pipeling is enabled, rcptTo(), mailFrom(), sendFrom(),
- * somlFrom() and samlFrom() do not wait for a response from the
- * SMTP server but return immediately.
- *
- * @var bool
- * @access public
- */
- var $pipelining = false;
-
- /**
- * Number of pipelined commands.
- * @var int
- * @access private
- */
- var $_pipelined_commands = 0;
-
- /**
- * Should debugging output be enabled?
- * @var boolean
- * @access private
- */
- var $_debug = false;
-
- /**
- * Debug output handler.
- * @var callback
- * @access private
- */
- var $_debug_handler = null;
-
- /**
- * The socket resource being used to connect to the SMTP server.
- * @var resource
- * @access private
- */
- var $_socket = null;
-
- /**
- * Array of socket options that will be passed to Net_Socket::connect().
- * @see stream_context_create()
- * @var array
- * @access private
- */
- var $_socket_options = null;
-
- /**
- * The socket I/O timeout value in seconds.
- * @var int
- * @access private
- */
- var $_timeout = 0;
-
- /**
- * The most recent server response code.
- * @var int
- * @access private
- */
- var $_code = -1;
-
- /**
- * The most recent server response arguments.
- * @var array
- * @access private
- */
- var $_arguments = array();
-
- /**
- * Stores the SMTP server's greeting string.
- * @var string
- * @access private
- */
- var $_greeting = null;
-
- /**
- * Stores detected features of the SMTP server.
- * @var array
- * @access private
- */
- var $_esmtp = array();
-
- /**
- * Instantiates a new Net_SMTP object, overriding any defaults
- * with parameters that are passed in.
- *
- * If you have SSL support in PHP, you can connect to a server
- * over SSL using an 'ssl://' prefix:
- *
- * // 465 is a common smtps port.
- * $smtp = new Net_SMTP('ssl://mail.host.com', 465);
- * $smtp->connect();
- *
- * @param string $host The server to connect to.
- * @param integer $port The port to connect to.
- * @param string $localhost The value to give when sending EHLO or HELO.
- * @param boolean $pipeling Use SMTP command pipelining
- * @param integer $timeout Socket I/O timeout in seconds.
- * @param array $socket_options Socket stream_context_create() options.
- *
- * @access public
- * @since 1.0
- */
- function Net_SMTP($host = null, $port = null, $localhost = null,
- $pipelining = false, $timeout = 0, $socket_options = null)
- {
- if (isset($host)) {
- $this->host = $host;
- }
- if (isset($port)) {
- $this->port = $port;
- }
- if (isset($localhost)) {
- $this->localhost = $localhost;
- }
- $this->pipelining = $pipelining;
-
- $this->_socket = new Net_Socket();
- $this->_socket_options = $socket_options;
- $this->_timeout = $timeout;
-
- /* Include the Auth_SASL package. If the package is available, we
- * enable the authentication methods that depend upon it. */
- if (@include_once 'Auth/SASL.php') {
- $this->setAuthMethod('CRAM-MD5', array($this, '_authCram_MD5'));
- $this->setAuthMethod('DIGEST-MD5', array($this, '_authDigest_MD5'));
- }
-
- /* These standard authentication methods are always available. */
- $this->setAuthMethod('LOGIN', array($this, '_authLogin'), false);
- $this->setAuthMethod('PLAIN', array($this, '_authPlain'), false);
- }
-
- /**
- * Set the socket I/O timeout value in seconds plus microseconds.
- *
- * @param integer $seconds Timeout value in seconds.
- * @param integer $microseconds Additional value in microseconds.
- *
- * @access public
- * @since 1.5.0
- */
- function setTimeout($seconds, $microseconds = 0) {
- return $this->_socket->setTimeout($seconds, $microseconds);
- }
-
- /**
- * Set the value of the debugging flag.
- *
- * @param boolean $debug New value for the debugging flag.
- *
- * @access public
- * @since 1.1.0
- */
- function setDebug($debug, $handler = null)
- {
- $this->_debug = $debug;
- $this->_debug_handler = $handler;
- }
-
- /**
- * Write the given debug text to the current debug output handler.
- *
- * @param string $message Debug mesage text.
- *
- * @access private
- * @since 1.3.3
- */
- function _debug($message)
- {
- if ($this->_debug) {
- if ($this->_debug_handler) {
- call_user_func_array($this->_debug_handler,
- array(&$this, $message));
- } else {
- echo "DEBUG: $message\n";
- }
- }
- }
-
- /**
- * Send the given string of data to the server.
- *
- * @param string $data The string of data to send.
- *
- * @return mixed The number of bytes that were actually written,
- * or a PEAR_Error object on failure.
- *
- * @access private
- * @since 1.1.0
- */
- function _send($data)
- {
- $this->_debug("Send: $data");
-
- $result = $this->_socket->write($data);
- if (!$result || PEAR::isError($result)) {
- $msg = ($result) ? $result->getMessage() : "unknown error";
- return PEAR::raiseError("Failed to write to socket: $msg",
- null, PEAR_ERROR_RETURN);
- }
-
- return $result;
- }
-
- /**
- * Send a command to the server with an optional string of
- * arguments. A carriage return / linefeed (CRLF) sequence will
- * be appended to each command string before it is sent to the
- * SMTP server - an error will be thrown if the command string
- * already contains any newline characters. Use _send() for
- * commands that must contain newlines.
- *
- * @param string $command The SMTP command to send to the server.
- * @param string $args A string of optional arguments to append
- * to the command.
- *
- * @return mixed The result of the _send() call.
- *
- * @access private
- * @since 1.1.0
- */
- function _put($command, $args = '')
- {
- if (!empty($args)) {
- $command .= ' ' . $args;
- }
-
- if (strcspn($command, "\r\n") !== strlen($command)) {
- return PEAR::raiseError('Commands cannot contain newlines',
- null, PEAR_ERROR_RETURN);
- }
-
- return $this->_send($command . "\r\n");
- }
-
- /**
- * Read a reply from the SMTP server. The reply consists of a response
- * code and a response message.
- *
- * @param mixed $valid The set of valid response codes. These
- * may be specified as an array of integer
- * values or as a single integer value.
- * @param bool $later Do not parse the response now, but wait
- * until the last command in the pipelined
- * command group
- *
- * @return mixed True if the server returned a valid response code or
- * a PEAR_Error object is an error condition is reached.
- *
- * @access private
- * @since 1.1.0
- *
- * @see getResponse
- */
- function _parseResponse($valid, $later = false)
- {
- $this->_code = -1;
- $this->_arguments = array();
-
- if ($later) {
- $this->_pipelined_commands++;
- return true;
- }
-
- for ($i = 0; $i <= $this->_pipelined_commands; $i++) {
- while ($line = $this->_socket->readLine()) {
- $this->_debug("Recv: $line");
-
- /* If we receive an empty line, the connection was closed. */
- if (empty($line)) {
- $this->disconnect();
- return PEAR::raiseError('Connection was closed',
- null, PEAR_ERROR_RETURN);
- }
-
- /* Read the code and store the rest in the arguments array. */
- $code = substr($line, 0, 3);
- $this->_arguments[] = trim(substr($line, 4));
-
- /* Check the syntax of the response code. */
- if (is_numeric($code)) {
- $this->_code = (int)$code;
- } else {
- $this->_code = -1;
- break;
- }
-
- /* If this is not a multiline response, we're done. */
- if (substr($line, 3, 1) != '-') {
- break;
- }
- }
- }
-
- $this->_pipelined_commands = 0;
-
- /* Compare the server's response code with the valid code/codes. */
- if (is_int($valid) && ($this->_code === $valid)) {
- return true;
- } elseif (is_array($valid) && in_array($this->_code, $valid, true)) {
- return true;
- }
-
- return PEAR::raiseError('Invalid response code received from server',
- $this->_code, PEAR_ERROR_RETURN);
- }
-
- /**
- * Issue an SMTP command and verify its response.
- *
- * @param string $command The SMTP command string or data.
- * @param mixed $valid The set of valid response codes. These
- * may be specified as an array of integer
- * values or as a single integer value.
- *
- * @return mixed True on success or a PEAR_Error object on failure.
- *
- * @access public
- * @since 1.6.0
- */
- function command($command, $valid)
- {
- if (PEAR::isError($error = $this->_put($command))) {
- return $error;
- }
- if (PEAR::isError($error = $this->_parseResponse($valid))) {
- return $error;
- }
-
- return true;
- }
-
- /**
- * Return a 2-tuple containing the last response from the SMTP server.
- *
- * @return array A two-element array: the first element contains the
- * response code as an integer and the second element
- * contains the response's arguments as a string.
- *
- * @access public
- * @since 1.1.0
- */
- function getResponse()
- {
- return array($this->_code, join("\n", $this->_arguments));
- }
-
- /**
- * Return the SMTP server's greeting string.
- *
- * @return string A string containing the greeting string, or null if a
- * greeting has not been received.
- *
- * @access public
- * @since 1.3.3
- */
- function getGreeting()
- {
- return $this->_greeting;
- }
-
- /**
- * Attempt to connect to the SMTP server.
- *
- * @param int $timeout The timeout value (in seconds) for the
- * socket connection attempt.
- * @param bool $persistent Should a persistent socket connection
- * be used?
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- * @access public
- * @since 1.0
- */
- function connect($timeout = null, $persistent = false)
- {
- $this->_greeting = null;
- $result = $this->_socket->connect($this->host, $this->port,
- $persistent, $timeout,
- $this->_socket_options);
- if (PEAR::isError($result)) {
- return PEAR::raiseError('Failed to connect socket: ' .
- $result->getMessage());
- }
-
- /*
- * Now that we're connected, reset the socket's timeout value for
- * future I/O operations. This allows us to have different socket
- * timeout values for the initial connection (our $timeout parameter)
- * and all other socket operations.
- */
- if ($this->_timeout > 0) {
- if (PEAR::isError($error = $this->setTimeout($this->_timeout))) {
- return $error;
- }
- }
-
- if (PEAR::isError($error = $this->_parseResponse(220))) {
- return $error;
- }
-
- /* Extract and store a copy of the server's greeting string. */
- list(, $this->_greeting) = $this->getResponse();
-
- if (PEAR::isError($error = $this->_negotiate())) {
- return $error;
- }
-
- return true;
- }
-
- /**
- * Attempt to disconnect from the SMTP server.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- * @access public
- * @since 1.0
- */
- function disconnect()
- {
- if (PEAR::isError($error = $this->_put('QUIT'))) {
- return $error;
- }
- if (PEAR::isError($error = $this->_parseResponse(221))) {
- return $error;
- }
- if (PEAR::isError($error = $this->_socket->disconnect())) {
- return PEAR::raiseError('Failed to disconnect socket: ' .
- $error->getMessage());
- }
-
- return true;
- }
-
- /**
- * Attempt to send the EHLO command and obtain a list of ESMTP
- * extensions available, and failing that just send HELO.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- *
- * @access private
- * @since 1.1.0
- */
- function _negotiate()
- {
- if (PEAR::isError($error = $this->_put('EHLO', $this->localhost))) {
- return $error;
- }
-
- if (PEAR::isError($this->_parseResponse(250))) {
- /* If we receive a 503 response, we're already authenticated. */
- if ($this->_code === 503) {
- return true;
- }
-
- /* If the EHLO failed, try the simpler HELO command. */
- if (PEAR::isError($error = $this->_put('HELO', $this->localhost))) {
- return $error;
- }
- if (PEAR::isError($this->_parseResponse(250))) {
- return PEAR::raiseError('HELO was not accepted: ', $this->_code,
- PEAR_ERROR_RETURN);
- }
-
- return true;
- }
-
- foreach ($this->_arguments as $argument) {
- $verb = strtok($argument, ' ');
- $arguments = substr($argument, strlen($verb) + 1,
- strlen($argument) - strlen($verb) - 1);
- $this->_esmtp[$verb] = $arguments;
- }
-
- if (!isset($this->_esmtp['PIPELINING'])) {
- $this->pipelining = false;
- }
-
- return true;
- }
-
- /**
- * Returns the name of the best authentication method that the server
- * has advertised.
- *
- * @return mixed Returns a string containing the name of the best
- * supported authentication method or a PEAR_Error object
- * if a failure condition is encountered.
- * @access private
- * @since 1.1.0
- */
- function _getBestAuthMethod()
- {
- $available_methods = explode(' ', $this->_esmtp['AUTH']);
-
- foreach ($this->auth_methods as $method => $callback) {
- if (in_array($method, $available_methods)) {
- return $method;
- }
- }
-
- return PEAR::raiseError('No supported authentication methods',
- null, PEAR_ERROR_RETURN);
- }
-
- /**
- * Attempt to do SMTP authentication.
- *
- * @param string The userid to authenticate as.
- * @param string The password to authenticate with.
- * @param string The requested authentication method. If none is
- * specified, the best supported method will be used.
- * @param bool Flag indicating whether or not TLS should be attempted.
- * @param string An optional authorization identifier. If specified, this
- * identifier will be used as the authorization proxy.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- * @access public
- * @since 1.0
- */
- function auth($uid, $pwd , $method = '', $tls = true, $authz = '')
- {
- /* We can only attempt a TLS connection if one has been requested,
- * we're running PHP 5.1.0 or later, have access to the OpenSSL
- * extension, are connected to an SMTP server which supports the
- * STARTTLS extension, and aren't already connected over a secure
- * (SSL) socket connection. */
- if ($tls && version_compare(PHP_VERSION, '5.1.0', '>=') &&
- extension_loaded('openssl') && isset($this->_esmtp['STARTTLS']) &&
- strncasecmp($this->host, 'ssl://', 6) !== 0) {
- /* Start the TLS connection attempt. */
- if (PEAR::isError($result = $this->_put('STARTTLS'))) {
- return $result;
- }
- if (PEAR::isError($result = $this->_parseResponse(220))) {
- return $result;
- }
- if (PEAR::isError($result = $this->_socket->enableCrypto(true, STREAM_CRYPTO_METHOD_TLS_CLIENT))) {
- return $result;
- } elseif ($result !== true) {
- return PEAR::raiseError('STARTTLS failed');
- }
-
- /* Send EHLO again to recieve the AUTH string from the
- * SMTP server. */
- $this->_negotiate();
- }
-
- if (empty($this->_esmtp['AUTH'])) {
- return PEAR::raiseError('SMTP server does not support authentication');
- }
-
- /* If no method has been specified, get the name of the best
- * supported method advertised by the SMTP server. */
- if (empty($method)) {
- if (PEAR::isError($method = $this->_getBestAuthMethod())) {
- /* Return the PEAR_Error object from _getBestAuthMethod(). */
- return $method;
- }
- } else {
- $method = strtoupper($method);
- if (!array_key_exists($method, $this->auth_methods)) {
- return PEAR::raiseError("$method is not a supported authentication method");
- }
- }
-
- if (!isset($this->auth_methods[$method])) {
- return PEAR::raiseError("$method is not a supported authentication method");
- }
-
- if (!is_callable($this->auth_methods[$method], false)) {
- return PEAR::raiseError("$method authentication method cannot be called");
- }
-
- if (is_array($this->auth_methods[$method])) {
- list($object, $method) = $this->auth_methods[$method];
- $result = $object->{$method}($uid, $pwd, $authz, $this);
- } else {
- $func = $this->auth_methods[$method];
- $result = $func($uid, $pwd, $authz, $this);
- }
-
- /* If an error was encountered, return the PEAR_Error object. */
- if (PEAR::isError($result)) {
- return $result;
- }
-
- return true;
- }
-
- /**
- * Add a new authentication method.
- *
- * @param string The authentication method name (e.g. 'PLAIN')
- * @param mixed The authentication callback (given as the name of a
- * function or as an (object, method name) array).
- * @param bool Should the new method be prepended to the list of
- * available methods? This is the default behavior,
- * giving the new method the highest priority.
- *
- * @return mixed True on success or a PEAR_Error object on failure.
- *
- * @access public
- * @since 1.6.0
- */
- function setAuthMethod($name, $callback, $prepend = true)
- {
- if (!is_string($name)) {
- return PEAR::raiseError('Method name is not a string');
- }
-
- if (!is_string($callback) && !is_array($callback)) {
- return PEAR::raiseError('Method callback must be string or array');
- }
-
- if (is_array($callback)) {
- if (!is_object($callback[0]) || !is_string($callback[1]))
- return PEAR::raiseError('Bad mMethod callback array');
- }
-
- if ($prepend) {
- $this->auth_methods = array_merge(array($name => $callback),
- $this->auth_methods);
- } else {
- $this->auth_methods[$name] = $callback;
- }
-
- return true;
- }
-
- /**
- * Authenticates the user using the DIGEST-MD5 method.
- *
- * @param string The userid to authenticate as.
- * @param string The password to authenticate with.
- * @param string The optional authorization proxy identifier.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- * @access private
- * @since 1.1.0
- */
- function _authDigest_MD5($uid, $pwd, $authz = '')
- {
- if (PEAR::isError($error = $this->_put('AUTH', 'DIGEST-MD5'))) {
- return $error;
- }
- /* 334: Continue authentication request */
- if (PEAR::isError($error = $this->_parseResponse(334))) {
- /* 503: Error: already authenticated */
- if ($this->_code === 503) {
- return true;
- }
- return $error;
- }
-
- $challenge = base64_decode($this->_arguments[0]);
- $digest = &Auth_SASL::factory('digest-md5');
- $auth_str = base64_encode($digest->getResponse($uid, $pwd, $challenge,
- $this->host, "smtp",
- $authz));
-
- if (PEAR::isError($error = $this->_put($auth_str))) {
- return $error;
- }
- /* 334: Continue authentication request */
- if (PEAR::isError($error = $this->_parseResponse(334))) {
- return $error;
- }
-
- /* We don't use the protocol's third step because SMTP doesn't
- * allow subsequent authentication, so we just silently ignore
- * it. */
- if (PEAR::isError($error = $this->_put(''))) {
- return $error;
- }
- /* 235: Authentication successful */
- if (PEAR::isError($error = $this->_parseResponse(235))) {
- return $error;
- }
- }
-
- /**
- * Authenticates the user using the CRAM-MD5 method.
- *
- * @param string The userid to authenticate as.
- * @param string The password to authenticate with.
- * @param string The optional authorization proxy identifier.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- * @access private
- * @since 1.1.0
- */
- function _authCRAM_MD5($uid, $pwd, $authz = '')
- {
- if (PEAR::isError($error = $this->_put('AUTH', 'CRAM-MD5'))) {
- return $error;
- }
- /* 334: Continue authentication request */
- if (PEAR::isError($error = $this->_parseResponse(334))) {
- /* 503: Error: already authenticated */
- if ($this->_code === 503) {
- return true;
- }
- return $error;
- }
-
- $challenge = base64_decode($this->_arguments[0]);
- $cram = &Auth_SASL::factory('cram-md5');
- $auth_str = base64_encode($cram->getResponse($uid, $pwd, $challenge));
-
- if (PEAR::isError($error = $this->_put($auth_str))) {
- return $error;
- }
-
- /* 235: Authentication successful */
- if (PEAR::isError($error = $this->_parseResponse(235))) {
- return $error;
- }
- }
-
- /**
- * Authenticates the user using the LOGIN method.
- *
- * @param string The userid to authenticate as.
- * @param string The password to authenticate with.
- * @param string The optional authorization proxy identifier.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- * @access private
- * @since 1.1.0
- */
- function _authLogin($uid, $pwd, $authz = '')
- {
- if (PEAR::isError($error = $this->_put('AUTH', 'LOGIN'))) {
- return $error;
- }
- /* 334: Continue authentication request */
- if (PEAR::isError($error = $this->_parseResponse(334))) {
- /* 503: Error: already authenticated */
- if ($this->_code === 503) {
- return true;
- }
- return $error;
- }
-
- if (PEAR::isError($error = $this->_put(base64_encode($uid)))) {
- return $error;
- }
- /* 334: Continue authentication request */
- if (PEAR::isError($error = $this->_parseResponse(334))) {
- return $error;
- }
-
- if (PEAR::isError($error = $this->_put(base64_encode($pwd)))) {
- return $error;
- }
-
- /* 235: Authentication successful */
- if (PEAR::isError($error = $this->_parseResponse(235))) {
- return $error;
- }
-
- return true;
- }
-
- /**
- * Authenticates the user using the PLAIN method.
- *
- * @param string The userid to authenticate as.
- * @param string The password to authenticate with.
- * @param string The optional authorization proxy identifier.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- * @access private
- * @since 1.1.0
- */
- function _authPlain($uid, $pwd, $authz = '')
- {
- if (PEAR::isError($error = $this->_put('AUTH', 'PLAIN'))) {
- return $error;
- }
- /* 334: Continue authentication request */
- if (PEAR::isError($error = $this->_parseResponse(334))) {
- /* 503: Error: already authenticated */
- if ($this->_code === 503) {
- return true;
- }
- return $error;
- }
-
- $auth_str = base64_encode($authz . chr(0) . $uid . chr(0) . $pwd);
-
- if (PEAR::isError($error = $this->_put($auth_str))) {
- return $error;
- }
-
- /* 235: Authentication successful */
- if (PEAR::isError($error = $this->_parseResponse(235))) {
- return $error;
- }
-
- return true;
- }
-
- /**
- * Send the HELO command.
- *
- * @param string The domain name to say we are.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- * @access public
- * @since 1.0
- */
- function helo($domain)
- {
- if (PEAR::isError($error = $this->_put('HELO', $domain))) {
- return $error;
- }
- if (PEAR::isError($error = $this->_parseResponse(250))) {
- return $error;
- }
-
- return true;
- }
-
- /**
- * Return the list of SMTP service extensions advertised by the server.
- *
- * @return array The list of SMTP service extensions.
- * @access public
- * @since 1.3
- */
- function getServiceExtensions()
- {
- return $this->_esmtp;
- }
-
- /**
- * Send the MAIL FROM: command.
- *
- * @param string $sender The sender (reverse path) to set.
- * @param string $params String containing additional MAIL parameters,
- * such as the NOTIFY flags defined by RFC 1891
- * or the VERP protocol.
- *
- * If $params is an array, only the 'verp' option
- * is supported. If 'verp' is true, the XVERP
- * parameter is appended to the MAIL command. If
- * the 'verp' value is a string, the full
- * XVERP=value parameter is appended.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- * @access public
- * @since 1.0
- */
- function mailFrom($sender, $params = null)
- {
- $args = "FROM:<$sender>";
-
- /* Support the deprecated array form of $params. */
- if (is_array($params) && isset($params['verp'])) {
- /* XVERP */
- if ($params['verp'] === true) {
- $args .= ' XVERP';
-
- /* XVERP=something */
- } elseif (trim($params['verp'])) {
- $args .= ' XVERP=' . $params['verp'];
- }
- } elseif (is_string($params) && !empty($params)) {
- $args .= ' ' . $params;
- }
-
- if (PEAR::isError($error = $this->_put('MAIL', $args))) {
- return $error;
- }
- if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) {
- return $error;
- }
-
- return true;
- }
-
- /**
- * Send the RCPT TO: command.
- *
- * @param string $recipient The recipient (forward path) to add.
- * @param string $params String containing additional RCPT parameters,
- * such as the NOTIFY flags defined by RFC 1891.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- *
- * @access public
- * @since 1.0
- */
- function rcptTo($recipient, $params = null)
- {
- $args = "TO:<$recipient>";
- if (is_string($params)) {
- $args .= ' ' . $params;
- }
-
- if (PEAR::isError($error = $this->_put('RCPT', $args))) {
- return $error;
- }
- if (PEAR::isError($error = $this->_parseResponse(array(250, 251), $this->pipelining))) {
- return $error;
- }
-
- return true;
- }
-
- /**
- * Quote the data so that it meets SMTP standards.
- *
- * This is provided as a separate public function to facilitate
- * easier overloading for the cases where it is desirable to
- * customize the quoting behavior.
- *
- * @param string $data The message text to quote. The string must be passed
- * by reference, and the text will be modified in place.
- *
- * @access public
- * @since 1.2
- */
- function quotedata(&$data)
- {
- /* Because a single leading period (.) signifies an end to the
- * data, legitimate leading periods need to be "doubled" ('..'). */
- $data = preg_replace('/^\./m', '..', $data);
-
- /* Change Unix (\n) and Mac (\r) linefeeds into CRLF's (\r\n). */
- $data = preg_replace('/(?:\r\n|\n|\r(?!\n))/', "\r\n", $data);
- }
-
- /**
- * Send the DATA command.
- *
- * @param mixed $data The message data, either as a string or an open
- * file resource.
- * @param string $headers The message headers. If $headers is provided,
- * $data is assumed to contain only body data.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- * @access public
- * @since 1.0
- */
- function data($data, $headers = null)
- {
- /* Verify that $data is a supported type. */
- if (!is_string($data) && !is_resource($data)) {
- return PEAR::raiseError('Expected a string or file resource');
- }
-
- /* Start by considering the size of the optional headers string. We
- * also account for the addition 4 character "\r\n\r\n" separator
- * sequence. */
- $size = (is_null($headers)) ? 0 : strlen($headers) + 4;
-
- if (is_resource($data)) {
- $stat = fstat($data);
- if ($stat === false) {
- return PEAR::raiseError('Failed to get file size');
- }
- $size += $stat['size'];
- } else {
- $size += strlen($data);
- }
-
- /* RFC 1870, section 3, subsection 3 states "a value of zero indicates
- * that no fixed maximum message size is in force". Furthermore, it
- * says that if "the parameter is omitted no information is conveyed
- * about the server's fixed maximum message size". */
- $limit = (isset($this->_esmtp['SIZE'])) ? $this->_esmtp['SIZE'] : 0;
- if ($limit > 0 && $size >= $limit) {
- $this->disconnect();
- return PEAR::raiseError('Message size exceeds server limit');
- }
-
- /* Initiate the DATA command. */
- if (PEAR::isError($error = $this->_put('DATA'))) {
- return $error;
- }
- if (PEAR::isError($error = $this->_parseResponse(354))) {
- return $error;
- }
-
- /* If we have a separate headers string, send it first. */
- if (!is_null($headers)) {
- $this->quotedata($headers);
- if (PEAR::isError($result = $this->_send($headers . "\r\n\r\n"))) {
- return $result;
- }
- }
-
- /* Now we can send the message body data. */
- if (is_resource($data)) {
- /* Stream the contents of the file resource out over our socket
- * connection, line by line. Each line must be run through the
- * quoting routine. */
- while (strlen($line = fread($data, 8192)) > 0) {
- /* If the last character is an newline, we need to grab the
- * next character to check to see if it is a period. */
- while (!feof($data)) {
- $char = fread($data, 1);
- $line .= $char;
- if ($char != "\n") {
- break;
- }
- }
- $this->quotedata($line);
- if (PEAR::isError($result = $this->_send($line))) {
- return $result;
- }
- }
- } else {
- /*
- * Break up the data by sending one chunk (up to 512k) at a time.
- * This approach reduces our peak memory usage.
- */
- for ($offset = 0; $offset < $size;) {
- $end = $offset + 512000;
-
- /*
- * Ensure we don't read beyond our data size or span multiple
- * lines. quotedata() can't properly handle character data
- * that's split across two line break boundaries.
- */
- if ($end >= $size) {
- $end = $size;
- } else {
- for (; $end < $size; $end++) {
- if ($data[$end] != "\n") {
- break;
- }
- }
- }
-
- /* Extract our chunk and run it through the quoting routine. */
- $chunk = substr($data, $offset, $end - $offset);
- $this->quotedata($chunk);
-
- /* If we run into a problem along the way, abort. */
- if (PEAR::isError($result = $this->_send($chunk))) {
- return $result;
- }
-
- /* Advance the offset to the end of this chunk. */
- $offset = $end;
- }
- }
-
- /* Finally, send the DATA terminator sequence. */
- if (PEAR::isError($result = $this->_send("\r\n.\r\n"))) {
- return $result;
- }
-
- /* Verify that the data was successfully received by the server. */
- if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) {
- return $error;
- }
-
- return true;
- }
-
- /**
- * Send the SEND FROM: command.
- *
- * @param string The reverse path to send.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- * @access public
- * @since 1.2.6
- */
- function sendFrom($path)
- {
- if (PEAR::isError($error = $this->_put('SEND', "FROM:<$path>"))) {
- return $error;
- }
- if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) {
- return $error;
- }
-
- return true;
- }
-
- /**
- * Backwards-compatibility wrapper for sendFrom().
- *
- * @param string The reverse path to send.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- *
- * @access public
- * @since 1.0
- * @deprecated 1.2.6
- */
- function send_from($path)
- {
- return sendFrom($path);
- }
-
- /**
- * Send the SOML FROM: command.
- *
- * @param string The reverse path to send.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- * @access public
- * @since 1.2.6
- */
- function somlFrom($path)
- {
- if (PEAR::isError($error = $this->_put('SOML', "FROM:<$path>"))) {
- return $error;
- }
- if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) {
- return $error;
- }
-
- return true;
- }
-
- /**
- * Backwards-compatibility wrapper for somlFrom().
- *
- * @param string The reverse path to send.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- *
- * @access public
- * @since 1.0
- * @deprecated 1.2.6
- */
- function soml_from($path)
- {
- return somlFrom($path);
- }
-
- /**
- * Send the SAML FROM: command.
- *
- * @param string The reverse path to send.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- * @access public
- * @since 1.2.6
- */
- function samlFrom($path)
- {
- if (PEAR::isError($error = $this->_put('SAML', "FROM:<$path>"))) {
- return $error;
- }
- if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) {
- return $error;
- }
-
- return true;
- }
-
- /**
- * Backwards-compatibility wrapper for samlFrom().
- *
- * @param string The reverse path to send.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- *
- * @access public
- * @since 1.0
- * @deprecated 1.2.6
- */
- function saml_from($path)
- {
- return samlFrom($path);
- }
-
- /**
- * Send the RSET command.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- * @access public
- * @since 1.0
- */
- function rset()
- {
- if (PEAR::isError($error = $this->_put('RSET'))) {
- return $error;
- }
- if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) {
- return $error;
- }
-
- return true;
- }
-
- /**
- * Send the VRFY command.
- *
- * @param string The string to verify
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- * @access public
- * @since 1.0
- */
- function vrfy($string)
- {
- /* Note: 251 is also a valid response code */
- if (PEAR::isError($error = $this->_put('VRFY', $string))) {
- return $error;
- }
- if (PEAR::isError($error = $this->_parseResponse(array(250, 252)))) {
- return $error;
- }
-
- return true;
- }
-
- /**
- * Send the NOOP command.
- *
- * @return mixed Returns a PEAR_Error with an error message on any
- * kind of failure, or true on success.
- * @access public
- * @since 1.0
- */
- function noop()
- {
- if (PEAR::isError($error = $this->_put('NOOP'))) {
- return $error;
- }
- if (PEAR::isError($error = $this->_parseResponse(250))) {
- return $error;
- }
-
- return true;
- }
-
- /**
- * Backwards-compatibility method. identifySender()'s functionality is
- * now handled internally.
- *
- * @return boolean This method always return true.
- *
- * @access public
- * @since 1.0
- */
- function identifySender()
- {
- return true;
- }
-
-}
diff --git a/program/lib/Net/Sieve.php b/program/lib/Net/Sieve.php
deleted file mode 100644
index 8ebdf0958..000000000
--- a/program/lib/Net/Sieve.php
+++ /dev/null
@@ -1,1274 +0,0 @@
-<?php
-/**
- * This file contains the Net_Sieve class.
- *
- * PHP version 4
- *
- * +-----------------------------------------------------------------------+
- * | All rights reserved. |
- * | |
- * | Redistribution and use in source and binary forms, with or without |
- * | modification, are permitted provided that the following conditions |
- * | are met: |
- * | |
- * | o Redistributions of source code must retain the above copyright |
- * | notice, this list of conditions and the following disclaimer. |
- * | o Redistributions in binary form must reproduce the above copyright |
- * | notice, this list of conditions and the following disclaimer in the |
- * | documentation and/or other materials provided with the distribution.|
- * | |
- * | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
- * | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
- * | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
- * | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
- * | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
- * | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
- * | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
- * | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
- * | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
- * | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
- * | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
- * +-----------------------------------------------------------------------+
- *
- * @category Networking
- * @package Net_Sieve
- * @author Richard Heyes <richard@phpguru.org>
- * @author Damian Fernandez Sosa <damlists@cnba.uba.ar>
- * @author Anish Mistry <amistry@am-productions.biz>
- * @author Jan Schneider <jan@horde.org>
- * @copyright 2002-2003 Richard Heyes
- * @copyright 2006-2008 Anish Mistry
- * @license http://www.opensource.org/licenses/bsd-license.php BSD
- * @version SVN: $Id$
- * @link http://pear.php.net/package/Net_Sieve
- */
-
-require_once 'PEAR.php';
-require_once 'Net/Socket.php';
-
-/**
- * TODO
- *
- * o supportsAuthMech()
- */
-
-/**
- * Disconnected state
- * @const NET_SIEVE_STATE_DISCONNECTED
- */
-define('NET_SIEVE_STATE_DISCONNECTED', 1, true);
-
-/**
- * Authorisation state
- * @const NET_SIEVE_STATE_AUTHORISATION
- */
-define('NET_SIEVE_STATE_AUTHORISATION', 2, true);
-
-/**
- * Transaction state
- * @const NET_SIEVE_STATE_TRANSACTION
- */
-define('NET_SIEVE_STATE_TRANSACTION', 3, true);
-
-
-/**
- * A class for talking to the timsieved server which comes with Cyrus IMAP.
- *
- * @category Networking
- * @package Net_Sieve
- * @author Richard Heyes <richard@phpguru.org>
- * @author Damian Fernandez Sosa <damlists@cnba.uba.ar>
- * @author Anish Mistry <amistry@am-productions.biz>
- * @author Jan Schneider <jan@horde.org>
- * @copyright 2002-2003 Richard Heyes
- * @copyright 2006-2008 Anish Mistry
- * @license http://www.opensource.org/licenses/bsd-license.php BSD
- * @version Release: 1.3.2
- * @link http://pear.php.net/package/Net_Sieve
- * @link http://tools.ietf.org/html/rfc5228 RFC 5228 (Sieve: An Email
- * Filtering Language)
- * @link http://tools.ietf.org/html/rfc5804 RFC 5804 A Protocol for
- * Remotely Managing Sieve Scripts
- */
-class Net_Sieve
-{
- /**
- * The authentication methods this class supports.
- *
- * Can be overwritten if having problems with certain methods.
- *
- * @var array
- */
- var $supportedAuthMethods = array('DIGEST-MD5', 'CRAM-MD5', 'EXTERNAL',
- 'PLAIN' , 'LOGIN');
-
- /**
- * SASL authentication methods that require Auth_SASL.
- *
- * @var array
- */
- var $supportedSASLAuthMethods = array('DIGEST-MD5', 'CRAM-MD5');
-
- /**
- * The socket handle.
- *
- * @var resource
- */
- var $_sock;
-
- /**
- * Parameters and connection information.
- *
- * @var array
- */
- var $_data;
-
- /**
- * Current state of the connection.
- *
- * One of the NET_SIEVE_STATE_* constants.
- *
- * @var integer
- */
- var $_state;
-
- /**
- * Constructor error.
- *
- * @var PEAR_Error
- */
- var $_error;
-
- /**
- * Whether to enable debugging.
- *
- * @var boolean
- */
- var $_debug = false;
-
- /**
- * Debug output handler.
- *
- * This has to be a valid callback.
- *
- * @var string|array
- */
- var $_debug_handler = null;
-
- /**
- * Whether to pick up an already established connection.
- *
- * @var boolean
- */
- var $_bypassAuth = false;
-
- /**
- * Whether to use TLS if available.
- *
- * @var boolean
- */
- var $_useTLS = true;
-
- /**
- * Additional options for stream_context_create().
- *
- * @var array
- */
- var $_options = null;
-
- /**
- * Maximum number of referral loops
- *
- * @var array
- */
- var $_maxReferralCount = 15;
-
- /**
- * Constructor.
- *
- * Sets up the object, connects to the server and logs in. Stores any
- * generated error in $this->_error, which can be retrieved using the
- * getError() method.
- *
- * @param string $user Login username.
- * @param string $pass Login password.
- * @param string $host Hostname of server.
- * @param string $port Port of server.
- * @param string $logintype Type of login to perform (see
- * $supportedAuthMethods).
- * @param string $euser Effective user. If authenticating as an
- * administrator, login as this user.
- * @param boolean $debug Whether to enable debugging (@see setDebug()).
- * @param string $bypassAuth Skip the authentication phase. Useful if the
- * socket is already open.
- * @param boolean $useTLS Use TLS if available.
- * @param array $options Additional options for
- * stream_context_create().
- * @param mixed $handler A callback handler for the debug output.
- */
- function Net_Sieve($user = null, $pass = null, $host = 'localhost',
- $port = 2000, $logintype = '', $euser = '',
- $debug = false, $bypassAuth = false, $useTLS = true,
- $options = null, $handler = null)
- {
- $this->_state = NET_SIEVE_STATE_DISCONNECTED;
- $this->_data['user'] = $user;
- $this->_data['pass'] = $pass;
- $this->_data['host'] = $host;
- $this->_data['port'] = $port;
- $this->_data['logintype'] = $logintype;
- $this->_data['euser'] = $euser;
- $this->_sock = new Net_Socket();
- $this->_bypassAuth = $bypassAuth;
- $this->_useTLS = $useTLS;
- $this->_options = $options;
- $this->setDebug($debug, $handler);
-
- /* Try to include the Auth_SASL package. If the package is not
- * available, we disable the authentication methods that depend upon
- * it. */
- if ((@include_once 'Auth/SASL.php') === false) {
- $this->_debug('Auth_SASL not present');
- foreach ($this->supportedSASLAuthMethods as $SASLMethod) {
- $pos = array_search($SASLMethod, $this->supportedAuthMethods);
- $this->_debug('Disabling method ' . $SASLMethod);
- unset($this->supportedAuthMethods[$pos]);
- }
- }
-
- if (strlen($user) && strlen($pass)) {
- $this->_error = $this->_handleConnectAndLogin();
- }
- }
-
- /**
- * Returns any error that may have been generated in the constructor.
- *
- * @return boolean|PEAR_Error False if no error, PEAR_Error otherwise.
- */
- function getError()
- {
- return PEAR::isError($this->_error) ? $this->_error : false;
- }
-
- /**
- * Sets the debug state and handler function.
- *
- * @param boolean $debug Whether to enable debugging.
- * @param string $handler A custom debug handler. Must be a valid callback.
- *
- * @return void
- */
- function setDebug($debug = true, $handler = null)
- {
- $this->_debug = $debug;
- $this->_debug_handler = $handler;
- }
-
- /**
- * Connects to the server and logs in.
- *
- * @return boolean True on success, PEAR_Error on failure.
- */
- function _handleConnectAndLogin()
- {
- if (PEAR::isError($res = $this->connect($this->_data['host'], $this->_data['port'], $this->_options, $this->_useTLS))) {
- return $res;
- }
- if ($this->_bypassAuth === false) {
- if (PEAR::isError($res = $this->login($this->_data['user'], $this->_data['pass'], $this->_data['logintype'], $this->_data['euser'], $this->_bypassAuth))) {
- return $res;
- }
- }
- return true;
- }
-
- /**
- * Handles connecting to the server and checks the response validity.
- *
- * @param string $host Hostname of server.
- * @param string $port Port of server.
- * @param array $options List of options to pass to
- * stream_context_create().
- * @param boolean $useTLS Use TLS if available.
- *
- * @return boolean True on success, PEAR_Error otherwise.
- */
- function connect($host, $port, $options = null, $useTLS = true)
- {
- $this->_data['host'] = $host;
- $this->_data['port'] = $port;
- $this->_useTLS = $useTLS;
- if (is_array($options)) {
- $this->_options = array_merge($this->_options, $options);
- }
-
- if (NET_SIEVE_STATE_DISCONNECTED != $this->_state) {
- return PEAR::raiseError('Not currently in DISCONNECTED state', 1);
- }
-
- if (PEAR::isError($res = $this->_sock->connect($host, $port, false, 5, $options))) {
- return $res;
- }
-
- if ($this->_bypassAuth) {
- $this->_state = NET_SIEVE_STATE_TRANSACTION;
- } else {
- $this->_state = NET_SIEVE_STATE_AUTHORISATION;
- if (PEAR::isError($res = $this->_doCmd())) {
- return $res;
- }
- }
-
- // Explicitly ask for the capabilities in case the connection is
- // picked up from an existing connection.
- if (PEAR::isError($res = $this->_cmdCapability())) {
- return PEAR::raiseError(
- 'Failed to connect, server said: ' . $res->getMessage(), 2
- );
- }
-
- // Check if we can enable TLS via STARTTLS.
- if ($useTLS && !empty($this->_capability['starttls'])
- && function_exists('stream_socket_enable_crypto')
- ) {
- if (PEAR::isError($res = $this->_startTLS())) {
- return $res;
- }
- }
-
- return true;
- }
-
- /**
- * Disconnect from the Sieve server.
- *
- * @param boolean $sendLogoutCMD Whether to send LOGOUT command before
- * disconnecting.
- *
- * @return boolean True on success, PEAR_Error otherwise.
- */
- function disconnect($sendLogoutCMD = true)
- {
- return $this->_cmdLogout($sendLogoutCMD);
- }
-
- /**
- * Logs into server.
- *
- * @param string $user Login username.
- * @param string $pass Login password.
- * @param string $logintype Type of login method to use.
- * @param string $euser Effective UID (perform on behalf of $euser).
- * @param boolean $bypassAuth Do not perform authentication.
- *
- * @return boolean True on success, PEAR_Error otherwise.
- */
- function login($user, $pass, $logintype = null, $euser = '', $bypassAuth = false)
- {
- $this->_data['user'] = $user;
- $this->_data['pass'] = $pass;
- $this->_data['logintype'] = $logintype;
- $this->_data['euser'] = $euser;
- $this->_bypassAuth = $bypassAuth;
-
- if (NET_SIEVE_STATE_AUTHORISATION != $this->_state) {
- return PEAR::raiseError('Not currently in AUTHORISATION state', 1);
- }
-
- if (!$bypassAuth ) {
- if (PEAR::isError($res = $this->_cmdAuthenticate($user, $pass, $logintype, $euser))) {
- return $res;
- }
- }
- $this->_state = NET_SIEVE_STATE_TRANSACTION;
-
- return true;
- }
-
- /**
- * Returns an indexed array of scripts currently on the server.
- *
- * @return array Indexed array of scriptnames.
- */
- function listScripts()
- {
- if (is_array($scripts = $this->_cmdListScripts())) {
- $this->_active = $scripts[1];
- return $scripts[0];
- } else {
- return $scripts;
- }
- }
-
- /**
- * Returns the active script.
- *
- * @return string The active scriptname.
- */
- function getActive()
- {
- if (!empty($this->_active)) {
- return $this->_active;
- }
- if (is_array($scripts = $this->_cmdListScripts())) {
- $this->_active = $scripts[1];
- return $scripts[1];
- }
- }
-
- /**
- * Sets the active script.
- *
- * @param string $scriptname The name of the script to be set as active.
- *
- * @return boolean True on success, PEAR_Error on failure.
- */
- function setActive($scriptname)
- {
- return $this->_cmdSetActive($scriptname);
- }
-
- /**
- * Retrieves a script.
- *
- * @param string $scriptname The name of the script to be retrieved.
- *
- * @return string The script on success, PEAR_Error on failure.
- */
- function getScript($scriptname)
- {
- return $this->_cmdGetScript($scriptname);
- }
-
- /**
- * Adds a script to the server.
- *
- * @param string $scriptname Name of the script.
- * @param string $script The script content.
- * @param boolean $makeactive Whether to make this the active script.
- *
- * @return boolean True on success, PEAR_Error on failure.
- */
- function installScript($scriptname, $script, $makeactive = false)
- {
- if (PEAR::isError($res = $this->_cmdPutScript($scriptname, $script))) {
- return $res;
- }
- if ($makeactive) {
- return $this->_cmdSetActive($scriptname);
- }
- return true;
- }
-
- /**
- * Removes a script from the server.
- *
- * @param string $scriptname Name of the script.
- *
- * @return boolean True on success, PEAR_Error on failure.
- */
- function removeScript($scriptname)
- {
- return $this->_cmdDeleteScript($scriptname);
- }
-
- /**
- * Checks if the server has space to store the script by the server.
- *
- * @param string $scriptname The name of the script to mark as active.
- * @param integer $size The size of the script.
- *
- * @return boolean|PEAR_Error True if there is space, PEAR_Error otherwise.
- *
- * @todo Rename to hasSpace()
- */
- function haveSpace($scriptname, $size)
- {
- if (NET_SIEVE_STATE_TRANSACTION != $this->_state) {
- return PEAR::raiseError('Not currently in TRANSACTION state', 1);
- }
-
- if (PEAR::isError($res = $this->_doCmd(sprintf('HAVESPACE %s %d', $this->_escape($scriptname), $size)))) {
- return $res;
- }
- return true;
- }
-
- /**
- * Returns the list of extensions the server supports.
- *
- * @return array List of extensions or PEAR_Error on failure.
- */
- function getExtensions()
- {
- if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) {
- return PEAR::raiseError('Not currently connected', 7);
- }
- return $this->_capability['extensions'];
- }
-
- /**
- * Returns whether the server supports an extension.
- *
- * @param string $extension The extension to check.
- *
- * @return boolean Whether the extension is supported or PEAR_Error on
- * failure.
- */
- function hasExtension($extension)
- {
- if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) {
- return PEAR::raiseError('Not currently connected', 7);
- }
-
- $extension = trim($this->_toUpper($extension));
- if (is_array($this->_capability['extensions'])) {
- foreach ($this->_capability['extensions'] as $ext) {
- if ($ext == $extension) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Returns the list of authentication methods the server supports.
- *
- * @return array List of authentication methods or PEAR_Error on failure.
- */
- function getAuthMechs()
- {
- if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) {
- return PEAR::raiseError('Not currently connected', 7);
- }
- return $this->_capability['sasl'];
- }
-
- /**
- * Returns whether the server supports an authentication method.
- *
- * @param string $method The method to check.
- *
- * @return boolean Whether the method is supported or PEAR_Error on
- * failure.
- */
- function hasAuthMech($method)
- {
- if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) {
- return PEAR::raiseError('Not currently connected', 7);
- }
-
- $method = trim($this->_toUpper($method));
- if (is_array($this->_capability['sasl'])) {
- foreach ($this->_capability['sasl'] as $sasl) {
- if ($sasl == $method) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Handles the authentication using any known method.
- *
- * @param string $uid The userid to authenticate as.
- * @param string $pwd The password to authenticate with.
- * @param string $userMethod The method to use. If empty, the class chooses
- * the best (strongest) available method.
- * @param string $euser The effective uid to authenticate as.
- *
- * @return void
- */
- function _cmdAuthenticate($uid, $pwd, $userMethod = null, $euser = '')
- {
- if (PEAR::isError($method = $this->_getBestAuthMethod($userMethod))) {
- return $method;
- }
- switch ($method) {
- case 'DIGEST-MD5':
- return $this->_authDigestMD5($uid, $pwd, $euser);
- case 'CRAM-MD5':
- $result = $this->_authCRAMMD5($uid, $pwd, $euser);
- break;
- case 'LOGIN':
- $result = $this->_authLOGIN($uid, $pwd, $euser);
- break;
- case 'PLAIN':
- $result = $this->_authPLAIN($uid, $pwd, $euser);
- break;
- case 'EXTERNAL':
- $result = $this->_authEXTERNAL($uid, $pwd, $euser);
- break;
- default :
- $result = PEAR::raiseError(
- $method . ' is not a supported authentication method'
- );
- break;
- }
-
- if (PEAR::isError($res = $this->_doCmd())) {
- return $res;
- }
-
- // Query the server capabilities again now that we are authenticated.
- if (PEAR::isError($res = $this->_cmdCapability())) {
- return PEAR::raiseError(
- 'Failed to connect, server said: ' . $res->getMessage(), 2
- );
- }
-
- return $result;
- }
-
- /**
- * Authenticates the user using the PLAIN method.
- *
- * @param string $user The userid to authenticate as.
- * @param string $pass The password to authenticate with.
- * @param string $euser The effective uid to authenticate as.
- *
- * @return void
- */
- function _authPLAIN($user, $pass, $euser)
- {
- return $this->_sendCmd(
- sprintf(
- 'AUTHENTICATE "PLAIN" "%s"',
- base64_encode($euser . chr(0) . $user . chr(0) . $pass)
- )
- );
- }
-
- /**
- * Authenticates the user using the LOGIN method.
- *
- * @param string $user The userid to authenticate as.
- * @param string $pass The password to authenticate with.
- * @param string $euser The effective uid to authenticate as.
- *
- * @return void
- */
- function _authLOGIN($user, $pass, $euser)
- {
- if (PEAR::isError($result = $this->_sendCmd('AUTHENTICATE "LOGIN"'))) {
- return $result;
- }
- if (PEAR::isError($result = $this->_doCmd('"' . base64_encode($user) . '"', true))) {
- return $result;
- }
- return $this->_doCmd('"' . base64_encode($pass) . '"', true);
- }
-
- /**
- * Authenticates the user using the CRAM-MD5 method.
- *
- * @param string $user The userid to authenticate as.
- * @param string $pass The password to authenticate with.
- * @param string $euser The effective uid to authenticate as.
- *
- * @return void
- */
- function _authCRAMMD5($user, $pass, $euser)
- {
- if (PEAR::isError($challenge = $this->_doCmd('AUTHENTICATE "CRAM-MD5"', true))) {
- return $challenge;
- }
-
- $challenge = base64_decode(trim($challenge));
- $cram = Auth_SASL::factory('crammd5');
- if (PEAR::isError($response = $cram->getResponse($user, $pass, $challenge))) {
- return $response;
- }
-
- return $this->_sendStringResponse(base64_encode($response));
- }
-
- /**
- * Authenticates the user using the DIGEST-MD5 method.
- *
- * @param string $user The userid to authenticate as.
- * @param string $pass The password to authenticate with.
- * @param string $euser The effective uid to authenticate as.
- *
- * @return void
- */
- function _authDigestMD5($user, $pass, $euser)
- {
- if (PEAR::isError($challenge = $this->_doCmd('AUTHENTICATE "DIGEST-MD5"', true))) {
- return $challenge;
- }
-
- $challenge = base64_decode(trim($challenge));
- $digest = Auth_SASL::factory('digestmd5');
- // @todo Really 'localhost'?
- if (PEAR::isError($response = $digest->getResponse($user, $pass, $challenge, 'localhost', 'sieve', $euser))) {
- return $response;
- }
-
- if (PEAR::isError($result = $this->_sendStringResponse(base64_encode($response)))) {
- return $result;
- }
- if (PEAR::isError($result = $this->_doCmd('', true))) {
- return $result;
- }
- if ($this->_toUpper(substr($result, 0, 2)) == 'OK') {
- return;
- }
-
- /* We don't use the protocol's third step because SIEVE doesn't allow
- * subsequent authentication, so we just silently ignore it. */
- if (PEAR::isError($result = $this->_sendStringResponse(''))) {
- return $result;
- }
-
- return $this->_doCmd();
- }
-
- /**
- * Authenticates the user using the EXTERNAL method.
- *
- * @param string $user The userid to authenticate as.
- * @param string $pass The password to authenticate with.
- * @param string $euser The effective uid to authenticate as.
- *
- * @return void
- *
- * @since 1.1.7
- */
- function _authEXTERNAL($user, $pass, $euser)
- {
- $cmd = sprintf(
- 'AUTHENTICATE "EXTERNAL" "%s"',
- base64_encode(strlen($euser) ? $euser : $user)
- );
- return $this->_sendCmd($cmd);
- }
-
- /**
- * Removes a script from the server.
- *
- * @param string $scriptname Name of the script to delete.
- *
- * @return boolean True on success, PEAR_Error otherwise.
- */
- function _cmdDeleteScript($scriptname)
- {
- if (NET_SIEVE_STATE_TRANSACTION != $this->_state) {
- return PEAR::raiseError('Not currently in AUTHORISATION state', 1);
- }
-
- if (PEAR::isError($res = $this->_doCmd(sprintf('DELETESCRIPT %s', $this->_escape($scriptname))))) {
- return $res;
- }
- return true;
- }
-
- /**
- * Retrieves the contents of the named script.
- *
- * @param string $scriptname Name of the script to retrieve.
- *
- * @return string The script if successful, PEAR_Error otherwise.
- */
- function _cmdGetScript($scriptname)
- {
- if (NET_SIEVE_STATE_TRANSACTION != $this->_state) {
- return PEAR::raiseError('Not currently in AUTHORISATION state', 1);
- }
-
- if (PEAR::isError($res = $this->_doCmd(sprintf('GETSCRIPT %s', $this->_escape($scriptname))))) {
- return $res;
- }
-
- return preg_replace('/^{[0-9]+}\r\n/', '', $res);
- }
-
- /**
- * Sets the active script, i.e. the one that gets run on new mail by the
- * server.
- *
- * @param string $scriptname The name of the script to mark as active.
- *
- * @return boolean True on success, PEAR_Error otherwise.
- */
- function _cmdSetActive($scriptname)
- {
- if (NET_SIEVE_STATE_TRANSACTION != $this->_state) {
- return PEAR::raiseError('Not currently in AUTHORISATION state', 1);
- }
-
- if (PEAR::isError($res = $this->_doCmd(sprintf('SETACTIVE %s', $this->_escape($scriptname))))) {
- return $res;
- }
-
- $this->_activeScript = $scriptname;
- return true;
- }
-
- /**
- * Returns the list of scripts on the server.
- *
- * @return array An array with the list of scripts in the first element
- * and the active script in the second element on success,
- * PEAR_Error otherwise.
- */
- function _cmdListScripts()
- {
- if (NET_SIEVE_STATE_TRANSACTION != $this->_state) {
- return PEAR::raiseError('Not currently in AUTHORISATION state', 1);
- }
-
- if (PEAR::isError($res = $this->_doCmd('LISTSCRIPTS'))) {
- return $res;
- }
-
- $scripts = array();
- $activescript = null;
- $res = explode("\r\n", $res);
- foreach ($res as $value) {
- if (preg_match('/^"(.*)"( ACTIVE)?$/i', $value, $matches)) {
- $script_name = stripslashes($matches[1]);
- $scripts[] = $script_name;
- if (!empty($matches[2])) {
- $activescript = $script_name;
- }
- }
- }
-
- return array($scripts, $activescript);
- }
-
- /**
- * Adds a script to the server.
- *
- * @param string $scriptname Name of the new script.
- * @param string $scriptdata The new script.
- *
- * @return boolean True on success, PEAR_Error otherwise.
- */
- function _cmdPutScript($scriptname, $scriptdata)
- {
- if (NET_SIEVE_STATE_TRANSACTION != $this->_state) {
- return PEAR::raiseError('Not currently in AUTHORISATION state', 1);
- }
-
- $stringLength = $this->_getLineLength($scriptdata);
- $command = sprintf("PUTSCRIPT %s {%d+}\r\n%s",
- $this->_escape($scriptname),
- $stringLength,
- $scriptdata);
- if (PEAR::isError($res = $this->_doCmd($command))) {
- return $res;
- }
-
- return true;
- }
-
- /**
- * Logs out of the server and terminates the connection.
- *
- * @param boolean $sendLogoutCMD Whether to send LOGOUT command before
- * disconnecting.
- *
- * @return boolean True on success, PEAR_Error otherwise.
- */
- function _cmdLogout($sendLogoutCMD = true)
- {
- if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) {
- return PEAR::raiseError('Not currently connected', 1);
- }
-
- if ($sendLogoutCMD) {
- if (PEAR::isError($res = $this->_doCmd('LOGOUT'))) {
- return $res;
- }
- }
-
- $this->_sock->disconnect();
- $this->_state = NET_SIEVE_STATE_DISCONNECTED;
-
- return true;
- }
-
- /**
- * Sends the CAPABILITY command
- *
- * @return boolean True on success, PEAR_Error otherwise.
- */
- function _cmdCapability()
- {
- if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) {
- return PEAR::raiseError('Not currently connected', 1);
- }
- if (PEAR::isError($res = $this->_doCmd('CAPABILITY'))) {
- return $res;
- }
- $this->_parseCapability($res);
- return true;
- }
-
- /**
- * Parses the response from the CAPABILITY command and stores the result
- * in $_capability.
- *
- * @param string $data The response from the capability command.
- *
- * @return void
- */
- function _parseCapability($data)
- {
- // Clear the cached capabilities.
- $this->_capability = array('sasl' => array(),
- 'extensions' => array());
-
- $data = preg_split('/\r?\n/', $this->_toUpper($data), -1, PREG_SPLIT_NO_EMPTY);
-
- for ($i = 0; $i < count($data); $i++) {
- if (!preg_match('/^"([A-Z]+)"( "(.*)")?$/', $data[$i], $matches)) {
- continue;
- }
- switch ($matches[1]) {
- case 'IMPLEMENTATION':
- $this->_capability['implementation'] = $matches[3];
- break;
-
- case 'SASL':
- $this->_capability['sasl'] = preg_split('/\s+/', $matches[3]);
- break;
-
- case 'SIEVE':
- $this->_capability['extensions'] = preg_split('/\s+/', $matches[3]);
- break;
-
- case 'STARTTLS':
- $this->_capability['starttls'] = true;
- break;
- }
- }
- }
-
- /**
- * Sends a command to the server
- *
- * @param string $cmd The command to send.
- *
- * @return void
- */
- function _sendCmd($cmd)
- {
- $status = $this->_sock->getStatus();
- if (PEAR::isError($status) || $status['eof']) {
- return PEAR::raiseError('Failed to write to socket: connection lost');
- }
- if (PEAR::isError($error = $this->_sock->write($cmd . "\r\n"))) {
- return PEAR::raiseError(
- 'Failed to write to socket: ' . $error->getMessage()
- );
- }
- $this->_debug("C: $cmd");
- }
-
- /**
- * Sends a string response to the server.
- *
- * @param string $str The string to send.
- *
- * @return void
- */
- function _sendStringResponse($str)
- {
- return $this->_sendCmd('{' . $this->_getLineLength($str) . "+}\r\n" . $str);
- }
-
- /**
- * Receives a single line from the server.
- *
- * @return string The server response line.
- */
- function _recvLn()
- {
- if (PEAR::isError($lastline = $this->_sock->gets(8192))) {
- return PEAR::raiseError(
- 'Failed to read from socket: ' . $lastline->getMessage()
- );
- }
-
- $lastline = rtrim($lastline);
- $this->_debug("S: $lastline");
-
- if ($lastline === '') {
- return PEAR::raiseError('Failed to read from socket');
- }
-
- return $lastline;
- }
-
- /**
- * Receives a number of bytes from the server.
- *
- * @param integer $length Number of bytes to read.
- *
- * @return string The server response.
- */
- function _recvBytes($length)
- {
- $response = '';
- $response_length = 0;
- while ($response_length < $length) {
- $response .= $this->_sock->read($length - $response_length);
- $response_length = $this->_getLineLength($response);
- }
- $this->_debug('S: ' . rtrim($response));
- return $response;
- }
-
- /**
- * Send a command and retrieves a response from the server.
- *
- * @param string $cmd The command to send.
- * @param boolean $auth Whether this is an authentication command.
- *
- * @return string|PEAR_Error Reponse string if an OK response, PEAR_Error
- * if a NO response.
- */
- function _doCmd($cmd = '', $auth = false)
- {
- $referralCount = 0;
- while ($referralCount < $this->_maxReferralCount) {
- if (strlen($cmd)) {
- if (PEAR::isError($error = $this->_sendCmd($cmd))) {
- return $error;
- }
- }
-
- $response = '';
- while (true) {
- if (PEAR::isError($line = $this->_recvLn())) {
- return $line;
- }
- $uc_line = $this->_toUpper($line);
-
- if ('OK' == substr($uc_line, 0, 2)) {
- $response .= $line;
- return rtrim($response);
- }
-
- if ('NO' == substr($uc_line, 0, 2)) {
- // Check for string literal error message.
- if (preg_match('/{([0-9]+)}$/', $line, $matches)) {
- $line = substr($line, 0, -(strlen($matches[1])+2))
- . str_replace(
- "\r\n", ' ', $this->_recvBytes($matches[1] + 2)
- );
- }
- return PEAR::raiseError(trim($response . substr($line, 2)), 3);
- }
-
- if ('BYE' == substr($uc_line, 0, 3)) {
- if (PEAR::isError($error = $this->disconnect(false))) {
- return PEAR::raiseError(
- 'Cannot handle BYE, the error was: '
- . $error->getMessage(),
- 4
- );
- }
- // Check for referral, then follow it. Otherwise, carp an
- // error.
- if (preg_match('/^bye \(referral "(sieve:\/\/)?([^"]+)/i', $line, $matches)) {
- // Replace the old host with the referral host
- // preserving any protocol prefix.
- $this->_data['host'] = preg_replace(
- '/\w+(?!(\w|\:\/\/)).*/', $matches[2],
- $this->_data['host']
- );
- if (PEAR::isError($error = $this->_handleConnectAndLogin())) {
- return PEAR::raiseError(
- 'Cannot follow referral to '
- . $this->_data['host'] . ', the error was: '
- . $error->getMessage(),
- 5
- );
- }
- break;
- }
- return PEAR::raiseError(trim($response . $line), 6);
- }
-
- if (preg_match('/^{([0-9]+)}/', $line, $matches)) {
- // Matches literal string responses.
- $line = $this->_recvBytes($matches[1] + 2);
- if (!$auth) {
- // Receive the pending OK only if we aren't
- // authenticating since string responses during
- // authentication don't need an OK.
- $this->_recvLn();
- }
- return $line;
- }
-
- if ($auth) {
- // String responses during authentication don't need an
- // OK.
- $response .= $line;
- return rtrim($response);
- }
-
- $response .= $line . "\r\n";
- $referralCount++;
- }
- }
-
- return PEAR::raiseError('Max referral count (' . $referralCount . ') reached. Cyrus murder loop error?', 7);
- }
-
- /**
- * Returns the name of the best authentication method that the server
- * has advertised.
- *
- * @param string $userMethod Only consider this method as available.
- *
- * @return string The name of the best supported authentication method or
- * a PEAR_Error object on failure.
- */
- function _getBestAuthMethod($userMethod = null)
- {
- if (!isset($this->_capability['sasl'])) {
- return PEAR::raiseError('This server doesn\'t support any authentication methods. SASL problem?');
- }
- if (!$this->_capability['sasl']) {
- return PEAR::raiseError('This server doesn\'t support any authentication methods.');
- }
-
- if ($userMethod) {
- if (in_array($userMethod, $this->_capability['sasl'])) {
- return $userMethod;
- }
- return PEAR::raiseError(
- sprintf('No supported authentication method found. The server supports these methods: %s, but we want to use: %s',
- implode(', ', $this->_capability['sasl']),
- $userMethod));
- }
-
- foreach ($this->supportedAuthMethods as $method) {
- if (in_array($method, $this->_capability['sasl'])) {
- return $method;
- }
- }
-
- return PEAR::raiseError(
- sprintf('No supported authentication method found. The server supports these methods: %s, but we only support: %s',
- implode(', ', $this->_capability['sasl']),
- implode(', ', $this->supportedAuthMethods)));
- }
-
- /**
- * Starts a TLS connection.
- *
- * @return boolean True on success, PEAR_Error on failure.
- */
- function _startTLS()
- {
- if (PEAR::isError($res = $this->_doCmd('STARTTLS'))) {
- return $res;
- }
-
- if (!stream_socket_enable_crypto($this->_sock->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
- return PEAR::raiseError('Failed to establish TLS connection', 2);
- }
-
- $this->_debug('STARTTLS negotiation successful');
-
- // The server should be sending a CAPABILITY response after
- // negotiating TLS. Read it, and ignore if it doesn't.
- // Unfortunately old Cyrus versions are broken and don't send a
- // CAPABILITY response, thus we would wait here forever. Parse the
- // Cyrus version and work around this broken behavior.
- if (!preg_match('/^CYRUS TIMSIEVED V([0-9.]+)/', $this->_capability['implementation'], $matches) ||
- version_compare($matches[1], '2.3.10', '>=')) {
- $this->_doCmd();
- }
-
- // Query the server capabilities again now that we are under
- // encryption.
- if (PEAR::isError($res = $this->_cmdCapability())) {
- return PEAR::raiseError(
- 'Failed to connect, server said: ' . $res->getMessage(), 2
- );
- }
-
- return true;
- }
-
- /**
- * Returns the length of a string.
- *
- * @param string $string A string.
- *
- * @return integer The length of the string.
- */
- function _getLineLength($string)
- {
- if (extension_loaded('mbstring')) {
- return mb_strlen($string, 'latin1');
- } else {
- return strlen($string);
- }
- }
-
- /**
- * Locale independant strtoupper() implementation.
- *
- * @param string $string The string to convert to lowercase.
- *
- * @return string The lowercased string, based on ASCII encoding.
- */
- function _toUpper($string)
- {
- $language = setlocale(LC_CTYPE, 0);
- setlocale(LC_CTYPE, 'C');
- $string = strtoupper($string);
- setlocale(LC_CTYPE, $language);
- return $string;
- }
-
- /**
- * Converts strings into RFC's quoted-string or literal-c2s form.
- *
- * @param string $string The string to convert.
- *
- * @return string Result string.
- */
- function _escape($string)
- {
- // Some implementations don't allow UTF-8 characters in quoted-string,
- // use literal-c2s.
- if (preg_match('/[^\x01-\x09\x0B-\x0C\x0E-\x7F]/', $string)) {
- return sprintf("{%d+}\r\n%s", $this->_getLineLength($string), $string);
- }
-
- return '"' . addcslashes($string, '\\"') . '"';
- }
-
- /**
- * Write debug text to the current debug output handler.
- *
- * @param string $message Debug message text.
- *
- * @return void
- */
- function _debug($message)
- {
- if ($this->_debug) {
- if ($this->_debug_handler) {
- call_user_func_array($this->_debug_handler, array(&$this, $message));
- } else {
- echo "$message\n";
- }
- }
- }
-}
diff --git a/program/lib/Net/Socket.php b/program/lib/Net/Socket.php
deleted file mode 100644
index bf1d1bbcd..000000000
--- a/program/lib/Net/Socket.php
+++ /dev/null
@@ -1,686 +0,0 @@
-<?php
-/**
- * Net_Socket
- *
- * PHP Version 4
- *
- * Copyright (c) 1997-2013 The PHP Group
- *
- * This source file is subject to version 2.0 of the PHP license,
- * that is bundled with this package in the file LICENSE, and is
- * available at through the world-wide-web at
- * http://www.php.net/license/2_02.txt.
- * If you did not receive a copy of the PHP license and are unable to
- * obtain it through the world-wide-web, please send a note to
- * license@php.net so we can mail you a copy immediately.
- *
- * Authors: Stig Bakken <ssb@php.net>
- * Chuck Hagenbuch <chuck@horde.org>
- *
- * @category Net
- * @package Net_Socket
- * @author Stig Bakken <ssb@php.net>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @copyright 1997-2003 The PHP Group
- * @license http://www.php.net/license/2_02.txt PHP 2.02
- * @link http://pear.php.net/packages/Net_Socket
- */
-
-require_once 'PEAR.php';
-
-define('NET_SOCKET_READ', 1);
-define('NET_SOCKET_WRITE', 2);
-define('NET_SOCKET_ERROR', 4);
-
-/**
- * Generalized Socket class.
- *
- * @category Net
- * @package Net_Socket
- * @author Stig Bakken <ssb@php.net>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @copyright 1997-2003 The PHP Group
- * @license http://www.php.net/license/2_02.txt PHP 2.02
- * @link http://pear.php.net/packages/Net_Socket
- */
-class Net_Socket extends PEAR
-{
- /**
- * Socket file pointer.
- * @var resource $fp
- */
- var $fp = null;
-
- /**
- * Whether the socket is blocking. Defaults to true.
- * @var boolean $blocking
- */
- var $blocking = true;
-
- /**
- * Whether the socket is persistent. Defaults to false.
- * @var boolean $persistent
- */
- var $persistent = false;
-
- /**
- * The IP address to connect to.
- * @var string $addr
- */
- var $addr = '';
-
- /**
- * The port number to connect to.
- * @var integer $port
- */
- var $port = 0;
-
- /**
- * Number of seconds to wait on socket operations before assuming
- * there's no more data. Defaults to no timeout.
- * @var integer|float $timeout
- */
- var $timeout = null;
-
- /**
- * Number of bytes to read at a time in readLine() and
- * readAll(). Defaults to 2048.
- * @var integer $lineLength
- */
- var $lineLength = 2048;
-
- /**
- * The string to use as a newline terminator. Usually "\r\n" or "\n".
- * @var string $newline
- */
- var $newline = "\r\n";
-
- /**
- * Connect to the specified port. If called when the socket is
- * already connected, it disconnects and connects again.
- *
- * @param string $addr IP address or host name (may be with protocol prefix).
- * @param integer $port TCP port number.
- * @param boolean $persistent (optional) Whether the connection is
- * persistent (kept open between requests
- * by the web server).
- * @param integer $timeout (optional) Connection socket timeout.
- * @param array $options See options for stream_context_create.
- *
- * @access public
- *
- * @return boolean|PEAR_Error True on success or a PEAR_Error on failure.
- */
- function connect($addr, $port = 0, $persistent = null,
- $timeout = null, $options = null)
- {
- if (is_resource($this->fp)) {
- @fclose($this->fp);
- $this->fp = null;
- }
-
- if (!$addr) {
- return $this->raiseError('$addr cannot be empty');
- } else if (strspn($addr, ':.0123456789') == strlen($addr)) {
- $this->addr = strpos($addr, ':') !== false ? '['.$addr.']' : $addr;
- } else {
- $this->addr = $addr;
- }
-
- $this->port = $port % 65536;
-
- if ($persistent !== null) {
- $this->persistent = $persistent;
- }
-
- $openfunc = $this->persistent ? 'pfsockopen' : 'fsockopen';
- $errno = 0;
- $errstr = '';
-
- $old_track_errors = @ini_set('track_errors', 1);
-
- if ($timeout <= 0) {
- $timeout = @ini_get('default_socket_timeout');
- }
-
- if ($options && function_exists('stream_context_create')) {
- $context = stream_context_create($options);
-
- // Since PHP 5 fsockopen doesn't allow context specification
- if (function_exists('stream_socket_client')) {
- $flags = STREAM_CLIENT_CONNECT;
-
- if ($this->persistent) {
- $flags = STREAM_CLIENT_PERSISTENT;
- }
-
- $addr = $this->addr . ':' . $this->port;
- $fp = stream_socket_client($addr, $errno, $errstr,
- $timeout, $flags, $context);
- } else {
- $fp = @$openfunc($this->addr, $this->port, $errno,
- $errstr, $timeout, $context);
- }
- } else {
- $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $timeout);
- }
-
- if (!$fp) {
- if ($errno == 0 && !strlen($errstr) && isset($php_errormsg)) {
- $errstr = $php_errormsg;
- }
- @ini_set('track_errors', $old_track_errors);
- return $this->raiseError($errstr, $errno);
- }
-
- @ini_set('track_errors', $old_track_errors);
- $this->fp = $fp;
- $this->setTimeout();
- return $this->setBlocking($this->blocking);
- }
-
- /**
- * Disconnects from the peer, closes the socket.
- *
- * @access public
- * @return mixed true on success or a PEAR_Error instance otherwise
- */
- function disconnect()
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- @fclose($this->fp);
- $this->fp = null;
- return true;
- }
-
- /**
- * Set the newline character/sequence to use.
- *
- * @param string $newline Newline character(s)
- * @return boolean True
- */
- function setNewline($newline)
- {
- $this->newline = $newline;
- return true;
- }
-
- /**
- * Find out if the socket is in blocking mode.
- *
- * @access public
- * @return boolean The current blocking mode.
- */
- function isBlocking()
- {
- return $this->blocking;
- }
-
- /**
- * Sets whether the socket connection should be blocking or
- * not. A read call to a non-blocking socket will return immediately
- * if there is no data available, whereas it will block until there
- * is data for blocking sockets.
- *
- * @param boolean $mode True for blocking sockets, false for nonblocking.
- *
- * @access public
- * @return mixed true on success or a PEAR_Error instance otherwise
- */
- function setBlocking($mode)
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- $this->blocking = $mode;
- stream_set_blocking($this->fp, (int)$this->blocking);
- return true;
- }
-
- /**
- * Sets the timeout value on socket descriptor,
- * expressed in the sum of seconds and microseconds
- *
- * @param integer $seconds Seconds.
- * @param integer $microseconds Microseconds, optional.
- *
- * @access public
- * @return mixed True on success or false on failure or
- * a PEAR_Error instance when not connected
- */
- function setTimeout($seconds = null, $microseconds = null)
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- if ($seconds === null && $microseconds === null) {
- $seconds = (int) $this->timeout;
- $microseconds = (int) (($this->timeout - $seconds) * 1000000);
- } else {
- $this->timeout = $seconds + $microseconds/1000000;
- }
-
- if ($this->timeout > 0) {
- return stream_set_timeout($this->fp, (int) $seconds, (int) $microseconds);
- }
- else {
- return false;
- }
- }
-
- /**
- * Sets the file buffering size on the stream.
- * See php's stream_set_write_buffer for more information.
- *
- * @param integer $size Write buffer size.
- *
- * @access public
- * @return mixed on success or an PEAR_Error object otherwise
- */
- function setWriteBuffer($size)
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- $returned = stream_set_write_buffer($this->fp, $size);
- if ($returned == 0) {
- return true;
- }
- return $this->raiseError('Cannot set write buffer.');
- }
-
- /**
- * Returns information about an existing socket resource.
- * Currently returns four entries in the result array:
- *
- * <p>
- * timed_out (bool) - The socket timed out waiting for data<br>
- * blocked (bool) - The socket was blocked<br>
- * eof (bool) - Indicates EOF event<br>
- * unread_bytes (int) - Number of bytes left in the socket buffer<br>
- * </p>
- *
- * @access public
- * @return mixed Array containing information about existing socket
- * resource or a PEAR_Error instance otherwise
- */
- function getStatus()
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- return stream_get_meta_data($this->fp);
- }
-
- /**
- * Get a specified line of data
- *
- * @param int $size Reading ends when size - 1 bytes have been read,
- * or a newline or an EOF (whichever comes first).
- * If no size is specified, it will keep reading from
- * the stream until it reaches the end of the line.
- *
- * @access public
- * @return mixed $size bytes of data from the socket, or a PEAR_Error if
- * not connected. If an error occurs, FALSE is returned.
- */
- function gets($size = null)
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- if (is_null($size)) {
- return @fgets($this->fp);
- } else {
- return @fgets($this->fp, $size);
- }
- }
-
- /**
- * Read a specified amount of data. This is guaranteed to return,
- * and has the added benefit of getting everything in one fread()
- * chunk; if you know the size of the data you're getting
- * beforehand, this is definitely the way to go.
- *
- * @param integer $size The number of bytes to read from the socket.
- *
- * @access public
- * @return $size bytes of data from the socket, or a PEAR_Error if
- * not connected.
- */
- function read($size)
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- return @fread($this->fp, $size);
- }
-
- /**
- * Write a specified amount of data.
- *
- * @param string $data Data to write.
- * @param integer $blocksize Amount of data to write at once.
- * NULL means all at once.
- *
- * @access public
- * @return mixed If the socket is not connected, returns an instance of
- * PEAR_Error.
- * If the write succeeds, returns the number of bytes written.
- * If the write fails, returns false.
- * If the socket times out, returns an instance of PEAR_Error.
- */
- function write($data, $blocksize = null)
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- if (is_null($blocksize) && !OS_WINDOWS) {
- $written = @fwrite($this->fp, $data);
-
- // Check for timeout or lost connection
- if (!$written) {
- $meta_data = $this->getStatus();
-
- if (!is_array($meta_data)) {
- return $meta_data; // PEAR_Error
- }
-
- if (!empty($meta_data['timed_out'])) {
- return $this->raiseError('timed out');
- }
- }
-
- return $written;
- } else {
- if (is_null($blocksize)) {
- $blocksize = 1024;
- }
-
- $pos = 0;
- $size = strlen($data);
- while ($pos < $size) {
- $written = @fwrite($this->fp, substr($data, $pos, $blocksize));
-
- // Check for timeout or lost connection
- if (!$written) {
- $meta_data = $this->getStatus();
-
- if (!is_array($meta_data)) {
- return $meta_data; // PEAR_Error
- }
-
- if (!empty($meta_data['timed_out'])) {
- return $this->raiseError('timed out');
- }
-
- return $written;
- }
-
- $pos += $written;
- }
-
- return $pos;
- }
- }
-
- /**
- * Write a line of data to the socket, followed by a trailing newline.
- *
- * @param string $data Data to write
- *
- * @access public
- * @return mixed fwrite() result, or PEAR_Error when not connected
- */
- function writeLine($data)
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- return fwrite($this->fp, $data . $this->newline);
- }
-
- /**
- * Tests for end-of-file on a socket descriptor.
- *
- * Also returns true if the socket is disconnected.
- *
- * @access public
- * @return bool
- */
- function eof()
- {
- return (!is_resource($this->fp) || feof($this->fp));
- }
-
- /**
- * Reads a byte of data
- *
- * @access public
- * @return 1 byte of data from the socket, or a PEAR_Error if
- * not connected.
- */
- function readByte()
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- return ord(@fread($this->fp, 1));
- }
-
- /**
- * Reads a word of data
- *
- * @access public
- * @return 1 word of data from the socket, or a PEAR_Error if
- * not connected.
- */
- function readWord()
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- $buf = @fread($this->fp, 2);
- return (ord($buf[0]) + (ord($buf[1]) << 8));
- }
-
- /**
- * Reads an int of data
- *
- * @access public
- * @return integer 1 int of data from the socket, or a PEAR_Error if
- * not connected.
- */
- function readInt()
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- $buf = @fread($this->fp, 4);
- return (ord($buf[0]) + (ord($buf[1]) << 8) +
- (ord($buf[2]) << 16) + (ord($buf[3]) << 24));
- }
-
- /**
- * Reads a zero-terminated string of data
- *
- * @access public
- * @return string, or a PEAR_Error if
- * not connected.
- */
- function readString()
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- $string = '';
- while (($char = @fread($this->fp, 1)) != "\x00") {
- $string .= $char;
- }
- return $string;
- }
-
- /**
- * Reads an IP Address and returns it in a dot formatted string
- *
- * @access public
- * @return Dot formatted string, or a PEAR_Error if
- * not connected.
- */
- function readIPAddress()
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- $buf = @fread($this->fp, 4);
- return sprintf('%d.%d.%d.%d', ord($buf[0]), ord($buf[1]),
- ord($buf[2]), ord($buf[3]));
- }
-
- /**
- * Read until either the end of the socket or a newline, whichever
- * comes first. Strips the trailing newline from the returned data.
- *
- * @access public
- * @return All available data up to a newline, without that
- * newline, or until the end of the socket, or a PEAR_Error if
- * not connected.
- */
- function readLine()
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- $line = '';
-
- $timeout = time() + $this->timeout;
-
- while (!feof($this->fp) && (!$this->timeout || time() < $timeout)) {
- $line .= @fgets($this->fp, $this->lineLength);
- if (substr($line, -1) == "\n") {
- return rtrim($line, $this->newline);
- }
- }
- return $line;
- }
-
- /**
- * Read until the socket closes, or until there is no more data in
- * the inner PHP buffer. If the inner buffer is empty, in blocking
- * mode we wait for at least 1 byte of data. Therefore, in
- * blocking mode, if there is no data at all to be read, this
- * function will never exit (unless the socket is closed on the
- * remote end).
- *
- * @access public
- *
- * @return string All data until the socket closes, or a PEAR_Error if
- * not connected.
- */
- function readAll()
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- $data = '';
- while (!feof($this->fp)) {
- $data .= @fread($this->fp, $this->lineLength);
- }
- return $data;
- }
-
- /**
- * Runs the equivalent of the select() system call on the socket
- * with a timeout specified by tv_sec and tv_usec.
- *
- * @param integer $state Which of read/write/error to check for.
- * @param integer $tv_sec Number of seconds for timeout.
- * @param integer $tv_usec Number of microseconds for timeout.
- *
- * @access public
- * @return False if select fails, integer describing which of read/write/error
- * are ready, or PEAR_Error if not connected.
- */
- function select($state, $tv_sec, $tv_usec = 0)
- {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
-
- $read = null;
- $write = null;
- $except = null;
- if ($state & NET_SOCKET_READ) {
- $read[] = $this->fp;
- }
- if ($state & NET_SOCKET_WRITE) {
- $write[] = $this->fp;
- }
- if ($state & NET_SOCKET_ERROR) {
- $except[] = $this->fp;
- }
- if (false === ($sr = stream_select($read, $write, $except,
- $tv_sec, $tv_usec))) {
- return false;
- }
-
- $result = 0;
- if (count($read)) {
- $result |= NET_SOCKET_READ;
- }
- if (count($write)) {
- $result |= NET_SOCKET_WRITE;
- }
- if (count($except)) {
- $result |= NET_SOCKET_ERROR;
- }
- return $result;
- }
-
- /**
- * Turns encryption on/off on a connected socket.
- *
- * @param bool $enabled Set this parameter to true to enable encryption
- * and false to disable encryption.
- * @param integer $type Type of encryption. See stream_socket_enable_crypto()
- * for values.
- *
- * @see http://se.php.net/manual/en/function.stream-socket-enable-crypto.php
- * @access public
- * @return false on error, true on success and 0 if there isn't enough data
- * and the user should try again (non-blocking sockets only).
- * A PEAR_Error object is returned if the socket is not
- * connected
- */
- function enableCrypto($enabled, $type)
- {
- if (version_compare(phpversion(), "5.1.0", ">=")) {
- if (!is_resource($this->fp)) {
- return $this->raiseError('not connected');
- }
- return @stream_socket_enable_crypto($this->fp, $enabled, $type);
- } else {
- $msg = 'Net_Socket::enableCrypto() requires php version >= 5.1.0';
- return $this->raiseError($msg);
- }
- }
-
-}