Xataface Email Module 0.2
Email/Mailmerge Module for Xataface
lib/XPM/PHP5/SMTP5.php
Go to the documentation of this file.
00001 <?php
00002 
00003 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
00004  *                                                                                         *
00005  *  XPertMailer is a PHP Mail Class that can send and read messages in MIME format.        *
00006  *  This file is part of the XPertMailer package (http://xpertmailer.sourceforge.net/)     *
00007  *  Copyright (C) 2007 Tanase Laurentiu Iulian                                             *
00008  *                                                                                         *
00009  *  This library is free software; you can redistribute it and/or modify it under the      *
00010  *  terms of the GNU Lesser General Public License as published by the Free Software       *
00011  *  Foundation; either version 2.1 of the License, or (at your option) any later version.  *
00012  *                                                                                         *
00013  *  This library is distributed in the hope that it will be useful, but WITHOUT ANY        *
00014  *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A        *
00015  *  PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.        *
00016  *                                                                                         *
00017  *  You should have received a copy of the GNU Lesser General Public License along with    *
00018  *  this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, *
00019  *  Fifth Floor, Boston, MA 02110-1301, USA                                                *
00020  *                                                                                         *
00021  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00022 
00023 if (!class_exists('MIME5')) require_once 'MIME5.php';
00024 
00025 $_RESULT = array();
00026 
00027 class SMTP5 {
00028 
00029         const CRLF = "\r\n";
00030         const PORT = 25;
00031         const TOUT = 30;
00032         const COUT = 5;
00033         const BLEN = 1024;
00034 
00035         static private function _cres($conn = null, &$resp, $code1 = null, $code2 = null, $debug = null) {
00036                 if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
00037                 $err = array();
00038                 if (!is_resource($conn)) $err[] = 'invalid resource connection';
00039                 if (!(is_int($code1) && $code1 > 99 && $code1 < 1000)) $err[] = 'invalid 1 code value';
00040                 if ($code2 != null) {
00041                         if (!(is_int($code2) && $code2 > 99 && $code2 < 1000)) $err[] = 'invalid 2 code value';
00042                 }
00043                 if (count($err) > 0) return FUNC5::trace($debug, implode(', ', $err), 1);
00044                 else {
00045                         $ret = true;
00046                         do {
00047                                 if ($result = fgets($conn, self::BLEN)) {
00048                                         $resp[] = $result;
00049                                         $rescode = substr($result, 0, 3);
00050                                         if (!($rescode == $code1 || $rescode == $code2)) {
00051                                                 $ret = false;
00052                                                 break;
00053                                         }
00054                                 } else {
00055                                         $resp[] = 'can not read';
00056                                         $ret = false;
00057                                         break;
00058                                 }
00059                         } while ($result[3] == '-');
00060                         return $ret;
00061                 }
00062         }
00063 
00064         static public function mxconnect($host = null, $port = null, $tout = null, $name = null, $context = null, $debug = null) {
00065                 global $_RESULT;
00066                 $_RESULT = array();
00067                 if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
00068                 if (!is_string($host)) FUNC5::trace($debug, 'invalid host type');
00069                 else {
00070                         $host = strtolower(trim($host));
00071                         if (!($host != '' && FUNC5::is_hostname($host, true, $debug))) FUNC5::trace($debug, 'invalid host value');
00072                 }
00073                 $res = FUNC5::is_win() ? FUNC5::getmxrr_win($host, $arr, $debug) : getmxrr($host, $arr);
00074                 $con = false;
00075                 if ($res) {
00076                         foreach ($arr as $mx) {
00077                                 if ($con = self::connect($mx, $port, null, null, null, $tout, $name, $context, null, $debug)) break;
00078                         }
00079                 }
00080                 if (!$con) $con = self::connect($host, $port, null, null, null, $tout, $name, $context, null, $debug);
00081                 return $con;
00082         }
00083 
00084         static public function connect($host = null, $port = null, $user = null, $pass = null, $vssl = null, $tout = null, $name = null, $context = null, $login = null, $debug = null) {
00085                 if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
00086                 global $_RESULT;
00087                 $_RESULT = $err = array();
00088                 if ($port == null) $port = self::PORT;
00089                 if ($tout == null) $tout = self::TOUT;
00090                 if (!is_string($host)) $err[] = 'invalid host type';
00091                 else {
00092                         $host = strtolower(trim($host));
00093                         if (!($host != '' && ($host == 'localhost' || FUNC5::is_ipv4($host) || FUNC5::is_hostname($host, true, $debug)))) $err[] = 'invalid host value';
00094                 }
00095                 if (!(is_int($port) && $port > 0)) $err[] = 'invalid port value';
00096                 if ($user != null) {
00097                         if (!is_string($user)) $err[] = 'invalid username type';
00098                         else if (($user = FUNC5::str_clear($user)) == '') $err[] = 'invalid username value';
00099                 }
00100                 if ($pass != null) {
00101                         if (!is_string($pass)) $err[] = 'invalid password type';
00102                         else if (($pass = FUNC5::str_clear($pass)) == '') $err[] = 'invalid password value';
00103                 }
00104                 if (($user != null && $pass == null) || ($user == null && $pass != null)) $err[] = 'invalid username/password combination';
00105                 if ($vssl != null) {
00106                         if (!is_string($vssl)) $err[] = 'invalid ssl version type';
00107                         else {
00108                                 $vssl = strtolower($vssl);
00109                                 if (!($vssl == 'tls' || $vssl == 'ssl' || $vssl == 'sslv2' || $vssl == 'sslv3')) $err[] = 'invalid ssl version value';
00110                         }
00111                 }
00112                 if (!(is_int($tout) && $tout > 0)) $err[] = 'invalid timeout value';
00113                 if ($name != null) {
00114                         if (!is_string($name)) $err[] = 'invalid name type';
00115                         else {
00116                                 $name = strtolower(trim($name));
00117                                 if (!($name != '' && ($name == 'localhost' || FUNC5::is_ipv4($name) || FUNC5::is_hostname($name, true, $debug)))) $err[] = 'invalid name value';
00118                         }
00119                 } else $name = '127.0.0.1';
00120                 if ($context != null && !is_resource($context)) $err[] = 'invalid context type';
00121                 if ($login != null) {
00122                         $login = strtolower(trim($login));
00123                         if (!($login == 'login' || $login == 'plain' || $login == 'cram-md5')) $err[] = 'invalid authentication type value';
00124                 }
00125                 if (count($err) > 0) FUNC5::trace($debug, implode(', ', $err));
00126                 else {
00127                         $ret = false;
00128                         $prt = ($vssl == null) ? 'tcp' : $vssl;
00129                         $conn = ($context == null) ? stream_socket_client($prt.'://'.$host.':'.$port, $errno, $errstr, $tout) : stream_socket_client($prt.'://'.$host.':'.$port, $errno, $errstr, $tout, STREAM_CLIENT_CONNECT, $context);
00130                         if (!$conn) $_RESULT[101] = $errstr;
00131                         else if (!stream_set_timeout($conn, self::COUT)) $_RESULT[102] = 'could not set stream timeout';
00132                         else if (!self::_cres($conn, $resp, 220, null, $debug)) $_RESULT[103] = $resp;
00133                         else {
00134                                 $continue = true;
00135                                 if (!self::ehlo($conn, $name, $debug)) $continue = self::helo($conn, $name, $debug);
00136                                 if ($continue) {
00137                                         if ($user == null) $ret = true;
00138                                         else if ($login != null) $ret = self::auth($conn, $user, $pass, $login, $debug);
00139                                         else {
00140                                                 list($code, $arr) = each($_RESULT);
00141                                                 $auth['default'] = $auth['login'] = $auth['plain'] = $auth['cram-md5'] = false;
00142                                                 foreach ($arr as $line) {
00143                                                         if (substr($line, 0, strlen('250-AUTH ')) == '250-AUTH ') {
00144                                                                 foreach (explode(' ', substr($line, strlen('250-AUTH '))) as $type) {
00145                                                                         $type = strtolower(trim($type));
00146                                                                         if ($type == 'login' || $type == 'plain' || $type == 'cram-md5') $auth[$type] = true;
00147                                                                 }
00148                                                         } else if (substr($line, 0, strlen('250 AUTH=')) == '250 AUTH=') {
00149                                                                 $expl = explode(' ', strtolower(trim(substr($line, strlen('250 AUTH=')))), 2);
00150                                                                 if ($expl[0] == 'login' || $expl[0] == 'plain' || $expl[0] == 'cram-md5') $auth['default'] = $expl[0];
00151                                                         }
00152                                                 }
00153                                                 if ($auth['default']) $ret = self::auth($conn, $user, $pass, $auth['default'], $debug);
00154                                                 if (!$ret && $auth['login'] && $auth['default'] != 'login') $ret = self::auth($conn, $user, $pass, 'login', $debug);
00155                                                 if (!$ret && $auth['plain'] && $auth['default'] != 'plain') $ret = self::auth($conn, $user, $pass, 'plain', $debug);
00156                                                 if (!$ret && $auth['cram-md5'] && $auth['default'] != 'cram-md5') $ret = self::auth($conn, $user, $pass, 'cram-md5', $debug);
00157                                                 if (!$ret && !$auth['login'] && $auth['default'] != 'login') $ret = self::auth($conn, $user, $pass, 'login', $debug);
00158                                                 if (!$ret && !$auth['plain'] && $auth['default'] != 'plain') $ret = self::auth($conn, $user, $pass, 'plain', $debug);
00159                                                 if (!$ret && !$auth['cram-md5'] && $auth['default'] != 'cram-md5') $ret = self::auth($conn, $user, $pass, 'cram-md5', $debug);
00160                                         }
00161                                 }
00162                         }
00163                         if (!$ret) {
00164                                 if (is_resource($conn)) self::disconnect($conn, $debug);
00165                                 $conn = false;
00166                         }
00167                         return $conn;
00168                 }
00169         }
00170 
00171         static public function send($conn = null, $addrs = null, $mess = null, $from = null, $debug = null) {
00172                 if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
00173                 global $_RESULT;
00174                 $_RESULT = $err = array();
00175                 if (!is_resource($conn)) $err[] = 'invalid resource connection';
00176                 if (!is_array($addrs)) $err[] = 'invalid to address type';
00177                 else {
00178                         $aver = true;
00179                         if (count($addrs) > 0) {
00180                                 foreach ($addrs as $addr) {
00181                                         if (!FUNC5::is_mail($addr)) {
00182                                                 $aver = false;
00183                                                 break;
00184                                         }
00185                                 }
00186                         } else $aver = false;
00187                         if (!$aver) $err[] = 'invalid to address value';
00188                 }
00189                 if (!is_string($mess)) $err[] = 'invalid message value';
00190                 if ($from == null) {
00191                         $from = @ini_get('sendmail_from');
00192                         if ($from == '' || !FUNC5::is_mail($from)) $from = (isset($_SERVER['SERVER_ADMIN']) && FUNC5::is_mail($_SERVER['SERVER_ADMIN'])) ? $_SERVER['SERVER_ADMIN'] : 'postmaster@localhost';
00193                 } else {
00194                         if (!is_string($from)) $err[] = 'invalid from address type';
00195                         else if (!($from != '' && FUNC5::is_mail($from))) $err[] = 'invalid from address value';
00196                 }
00197                 if (count($err) > 0) FUNC5::trace($debug, implode(', ', $err));
00198                 else {
00199                         $ret = false;
00200                         if (self::from($conn, $from, $debug)) {
00201                                 $continue = true;
00202                                 foreach ($addrs as $dest) {
00203                                         if (!self::to($conn, $dest, $debug)) {
00204                                                 $continue = false;
00205                                                 break;
00206                                         }
00207                                 }
00208                                 if ($continue) {
00209                                         if (self::data($conn, $mess, $debug)) $ret = self::rset($conn, $debug);
00210                                 }
00211                         }
00212                         return $ret;
00213                 }
00214         }
00215 
00216         static public function disconnect($conn = null, $debug = null) {
00217                 if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
00218                 global $_RESULT;
00219                 $_RESULT = array();
00220                 if (!is_resource($conn)) return FUNC5::trace($debug, 'invalid resource connection', 1);
00221                 else {
00222                         if (!fwrite($conn, 'QUIT'.self::CRLF)) $_RESULT[300] = 'can not write';
00223                         else $_RESULT[301] = 'Send QUIT';
00224                         return @fclose($conn);
00225                 }
00226         }
00227 
00228         static public function quit($conn = null, $debug = null) {
00229                 if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
00230                 global $_RESULT;
00231                 $_RESULT = array();
00232                 $ret = false;
00233                 if (!is_resource($conn)) FUNC5::trace($debug, 'invalid resource connection');
00234                 else if (!fwrite($conn, 'QUIT'.self::CRLF)) $_RESULT[302] = 'can not write';
00235                 else {
00236                         $_RESULT[303] = ($vget = @fgets($conn, self::BLEN)) ? $vget : 'can not read';
00237                         $ret = true;
00238                 }
00239                 return $ret;
00240         }
00241 
00242         static public function helo($conn = null, $host = null, $debug = null) {
00243                 if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
00244                 global $_RESULT;
00245                 $_RESULT = $err = array();
00246                 if (!is_resource($conn)) $err[] = 'invalid resource connection';
00247                 if (!is_string($host)) $err[] = 'invalid host type';
00248                 else {
00249                         $host = strtolower(trim($host));
00250                         if (!($host != '' && ($host == 'localhost' || FUNC5::is_ipv4($host) || FUNC5::is_hostname($host, true, $debug)))) $err[] = 'invalid host value';
00251                 }
00252                 if (count($err) > 0) FUNC5::trace($debug, implode(', ', $err));
00253                 else {
00254                         $ret = false;
00255                         if (!fwrite($conn, 'HELO '.$host.self::CRLF)) $_RESULT[304] = 'can not write';
00256                         else if (!self::_cres($conn, $resp, 250, null, $debug)) $_RESULT[305] = $resp;
00257                         else {
00258                                 $_RESULT[306] = $resp;
00259                                 $ret = true;
00260                         }
00261                         return $ret;
00262                 }
00263         }
00264 
00265         static public function ehlo($conn = null, $host = null, $debug = null) {
00266                 if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
00267                 global $_RESULT;
00268                 $_RESULT = $err = array();
00269                 if (!is_resource($conn)) $err[] = 'invalid resource connection';
00270                 if (!is_string($host)) $err[] = 'invalid host type';
00271                 else {
00272                         $host = strtolower(trim($host));
00273                         if (!($host != '' && ($host == 'localhost' || FUNC5::is_ipv4($host) || FUNC5::is_hostname($host, true, $debug)))) $err[] = 'invalid host value';
00274                 }
00275                 if (count($err) > 0) FUNC5::trace($debug, implode(', ', $err));
00276                 else {
00277                         $ret = false;
00278                         if (!fwrite($conn, 'EHLO '.$host.self::CRLF)) $_RESULT[307] = 'can not write';
00279                         else if (!self::_cres($conn, $resp, 250, null, $debug)) $_RESULT[308] = $resp;
00280                         else {
00281                                 $_RESULT[309] = $resp;
00282                                 $ret = true;
00283                         }
00284                         return $ret;
00285                 }
00286         }
00287 
00288         static public function auth($conn = null, $user = null, $pass = null, $type = null, $debug = null) {
00289                 if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
00290                 global $_RESULT;
00291                 $_RESULT = $err = array();
00292                 if (!is_resource($conn)) $err[] = 'invalid resource connection';
00293                 if (!is_string($user)) $err[] = 'invalid username type';
00294                 else if (($user = FUNC5::str_clear($user)) == '') $err[] = 'invalid username value';
00295                 if (!is_string($pass)) $err[] = 'invalid password type';
00296                 else if (($pass = FUNC5::str_clear($pass)) == '') $err[] = 'invalid password value';
00297                 if ($type == null) $type = 'login';
00298                 if (!is_string($type)) $err[] = 'invalid authentication type';
00299                 else {
00300                         $type = strtolower(trim($type));
00301                         if (!($type == 'login' || $type == 'plain' || $type == 'cram-md5')) $err[] = 'invalid authentication type value';
00302                 }
00303                 if (count($err) > 0) FUNC5::trace($debug, implode(', ', $err));
00304                 else {
00305                         $ret = false;
00306                         if ($type == 'login') {
00307                                 if (!fwrite($conn, 'AUTH LOGIN'.self::CRLF)) $_RESULT[310] = 'can not write';
00308                                 else if (!self::_cres($conn, $resp, 334, null, $debug)) $_RESULT[311] = $resp;
00309                                 else if (!fwrite($conn, base64_encode($user).self::CRLF)) $_RESULT[312] = 'can not write';
00310                                 else if (!self::_cres($conn, $resp, 334, null, $debug)) $_RESULT[313] = $resp;
00311                                 else if (!fwrite($conn, base64_encode($pass).self::CRLF)) $_RESULT[314] = 'can not write';
00312                                 else if (!self::_cres($conn, $resp, 235, null, $debug)) $_RESULT[315] = $resp;
00313                                 else {
00314                                         $_RESULT[316] = $resp;
00315                                         $ret = true;
00316                                 }
00317                         } else if ($type == 'plain') {
00318                                 if (!fwrite($conn, 'AUTH PLAIN '.base64_encode($user.chr(0).$user.chr(0).$pass).self::CRLF)) $_RESULT[317] = 'can not write';
00319                                 else if (!self::_cres($conn, $resp, 235, null, $debug)) $_RESULT[318] = $resp;
00320                                 else {
00321                                         $_RESULT[319] = $resp;
00322                                         $ret = true;
00323                                 }
00324                         } else if ($type == 'cram-md5') {
00325                                 if (!fwrite($conn, 'AUTH CRAM-MD5'.self::CRLF)) $_RESULT[200] = 'can not write';
00326                                 else if (!self::_cres($conn, $resp, 334, null, $debug)) $_RESULT[201] = $resp;
00327                                 else {
00328                                         if (strlen($pass) > 64) $pass = pack('H32', md5($pass));
00329                                         if (strlen($pass) < 64) $pass = str_pad($pass, 64, chr(0));
00330                                         $pad1 = substr($pass, 0, 64) ^ str_repeat(chr(0x36), 64);
00331                                         $pad2 = substr($pass, 0, 64) ^ str_repeat(chr(0x5C), 64);
00332                                         $chal = substr($resp[count($resp)-1], 4);
00333                                         $innr = pack('H32', md5($pad1.base64_decode($chal)));
00334                                         if (!fwrite($conn, base64_encode($user.' '.md5($pad2.$innr)).self::CRLF)) $_RESULT[202] = 'can not write';
00335                                         else if (!self::_cres($conn, $resp, 235, null, $debug)) $_RESULT[203] = $resp;
00336                                         else {
00337                                                 $_RESULT[204] = $resp;
00338                                                 $ret = true;
00339                                         }
00340                                 }
00341                         }
00342                         return $ret;
00343                 }
00344         }
00345 
00346         static public function from($conn = null, $addr = null, $debug = null) {
00347                 if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
00348                 global $_RESULT;
00349                 $_RESULT = $err = array();
00350                 if (!is_resource($conn)) $err[] = 'invalid resource connection';
00351                 if (!is_string($addr)) $err[] = 'invalid from address type';
00352                 else if (!($addr != '' && FUNC5::is_mail($addr))) $err[] = 'invalid from address value';
00353                 if (count($err) > 0) FUNC5::trace($debug, implode(', ', $err));
00354                 else {
00355                         $ret = false;
00356                         if (!fwrite($conn, 'MAIL FROM:<'.$addr.'>'.self::CRLF)) $_RESULT[320] = 'can not write';
00357                         else if (!self::_cres($conn, $resp, 250, null, $debug)) $_RESULT[321] = $resp;
00358                         else {
00359                                 $_RESULT[322] = $resp;
00360                                 $ret = true;
00361                         }
00362                         return $ret;
00363                 }
00364         }
00365 
00366         static public function to($conn = null, $addr = null, $debug = null) {
00367                 if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
00368                 global $_RESULT;
00369                 $_RESULT = $err = array();
00370                 if (!is_resource($conn)) $err[] = 'invalid resource connection';
00371                 if (!is_string($addr)) $err[] = 'invalid to address type';
00372                 else if (!($addr != '' && FUNC5::is_mail($addr))) $err[] = 'invalid to address value';
00373                 if (count($err) > 0) FUNC5::trace($debug, implode(', ', $err));
00374                 else {
00375                         $ret = false;
00376                         if (!fwrite($conn, 'RCPT TO:<'.$addr.'>'.self::CRLF)) $_RESULT[323] = 'can not write';
00377                         else if (!self::_cres($conn, $resp, 250, 251, $debug)) $_RESULT[324] = $resp;
00378                         else {
00379                                 $_RESULT[325] = $resp;
00380                                 $ret = true;
00381                         }
00382                         return $ret;
00383                 }
00384         }
00385 
00386         static public function data($conn = null, $mess = null, $debug = null) {
00387                 if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
00388                 global $_RESULT;
00389                 $_RESULT = $err = array();
00390                 if (!is_resource($conn)) $err[] = 'invalid resource connection';
00391                 if (!(is_string($mess) && $mess != '')) $err[] = 'invalid message value';
00392                 if (count($err) > 0) FUNC5::trace($debug, implode(', ', $err));
00393                 else {
00394                         $ret = false;
00395                         if (!fwrite($conn, 'DATA'.self::CRLF)) $_RESULT[326] = 'can not write';
00396                         else if (!self::_cres($conn, $resp, 354, null, $debug)) $_RESULT[327] = $resp;
00397                         else {
00398                                 $continue = true;
00399                                 foreach (explode(self::CRLF, $mess) as $line) {
00400                                         if ($line != '' && $line[0] == '.') $line = '.'.$line;
00401                                         if (!fwrite($conn, $line.self::CRLF)) {
00402                                                 $_RESULT[328] = 'can not write';
00403                                                 $continue = false;
00404                                                 break;
00405                                         }
00406                                 }
00407                                 if ($continue) {
00408                                         if (!fwrite($conn, '.'.self::CRLF)) $_RESULT[329] = 'can not write';
00409                                         else if (!self::_cres($conn, $resp, 250, null, $debug)) $_RESULT[330] = $resp;
00410                                         else {
00411                                                 $_RESULT[331] = $resp;
00412                                                 $ret = true;
00413                                         }
00414                                 }
00415                         }
00416                         return $ret;
00417                 }
00418         }
00419 
00420         static public function rset($conn = null, $debug = null) {
00421                 if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
00422                 global $_RESULT;
00423                 $_RESULT = array();
00424                 $ret = false;
00425                 if (!is_resource($conn)) FUNC5::trace($debug, 'invalid resource connection');
00426                 else if (!fwrite($conn, 'RSET'.self::CRLF)) $_RESULT[332] = 'can not write';
00427                 else if (!self::_cres($conn, $resp, 250, null, $debug)) $_RESULT[333] = $resp;
00428                 else {
00429                         $_RESULT[334] = $resp;
00430                         $ret = true;
00431                 }
00432                 return $ret;
00433         }
00434 
00435         static public function recv($conn = null, $code1 = null, $code2 = null, $debug = null) {
00436                 if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
00437                 global $_RESULT;
00438                 $_RESULT = array();
00439                 $ret = false;
00440                 if (!self::_cres($conn, $resp, $code1, $code2, $debug)) $_RESULT[335] = $resp;
00441                 else {
00442                         $_RESULT[336] = $resp;
00443                         $ret = true;
00444                 }
00445                 return $ret;
00446         }
00447 
00448 }
00449 
00450 ?>
 All Data Structures Files Functions Variables Enumerations