source: trunk/instant_messenger/inc/Jabber.abstract.php @ 239

Revision 239, 9.7 KB checked in by niltonneto, 17 years ago (diff)
  • Property svn:eol-style set to native
  • Property svn:executable set to *
Line 
1<?php
2/*
3+---------------------------------------------------------------------------------+
4|                                                                                 |
5| @FILE:        Jabber.abstract.php                                               |
6| @ABSTRACT:    Jabber                                                            |
7| @EXTENDS:     Socket (Socket.class.php)                                         |
8|                                                                                 |
9| @DATE:        Wed May,16 2007 08:18:59                                          |
10| @LAST_CHANGE: Wed May,16 2007 09:03:28                                          |
11|                                                                                 |
12| @AUTHOR:      [NUTS] Rodrigo Souza - rodrigosouzadossantos [at] gmail [dot] com |
13|                                                                                 |
14| @BRIEF:       Abstract class for connect with any Jabber server                 |
15|                                                                                 |
16+---------------------------------------------------------------------------------+
17*/
18
19require_once 'Socket.abstract.php';
20
21abstract class Jabber extends Socket
22{
23        const J_FILE    = 'Jabber.log';
24        const J_ALL     = false;
25        const J_ERROR   = true;
26        const J_WARNING = true;
27        const J_NOTICE  = true;
28
29        const ALL     = 'ALL';
30        const ERROR   = 'ERROR';
31        const WARNING = 'WARNING';
32        const NOTICE  = 'NOTICE';
33
34        private final function _connect( $pUser = false, $pPassword = false, $pConnectionType = false )
35        {
36                try
37                {
38                        if ( !preg_match('/^(.+)@(.+)\/(.+):(\d+)$/',$pUser, $matches) )
39                                throw new Exception('[connect] #1 ' . $pUser . ' must be [USER]@[DOMAIN]/[RESOURCE]:[PORT] and [PORT] is integer. File: ' . __FILE__ . '  ::  ' . __LINE__);
40
41                        list($subject, $USER, $SERVER, $RESOURCE, $PORT) = $matches;
42
43                        if ( !($socket = $this->open('tcp://' . $SERVER . ':' . $PORT, 1, 1)) )
44                                throw new Exception('[connect] #2 can\'t access tcp://' . $SERVER . ':' . $PORT . '. File: ' . __FILE__ . '  ::  ' . __LINE__);
45
46                        $this->_socket = $socket;
47
48                        fwrite($socket, "{$USER}@{$SERVER}##{$pPassword}##{$pConnectionType}");
49
50                        $return = fread($socket, 3);
51
52                        if ( $return == "new" )
53                        {
54                                $xml  = "<?xml version='1.0' ?>";
55                                $xml .= "<stream:stream to='" . $SERVER . "' xmlns='jabber:client' ";
56                                $xml .= "xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>";
57
58                                if ( $this->write($xml) === false )
59                                        throw new Exception('[connect] #4 it isn\'t possible connect in the server because exists a client connected with same user. File: ' . __FILE__ . '  ::  ' . __LINE__);
60                        }
61
62                        $this->_server = $SERVER;
63                        $this->_username = $USER;
64                        $this->_password = $pPassword;
65                        $this->_resource = $RESOURCE;
66
67                        return $return;
68                }
69                catch(Exception $e)
70                {
71                        $this->writeLog('ERROR', $e->getMessage());
72                        return false;
73                }
74        }
75
76        protected function connect($pUser = false, $pPassword = false, $pConnectionType = false)
77        {
78                try
79                {
80                        $_connect = $this->_connect($pUser, $pPassword, $pConnectionType);
81
82                        if ( !$_connect )
83                                throw new Exception('[connect] #0. File: ' . __FILE__ . '  ::  ' . __LINE__);
84
85                        if ( $_connect == "new" )
86                        {
87                                if ( ($xml = $this->read()) === false )
88                                        throw new Exception('[connect] #1 it isn\'t possible read the socket. File: ' . __FILE__ . '  ::  ' . __LINE__);
89
90
91                                if ( preg_match('/(<starttls .*<required\/><\/starttls>)/', $xml, $matches) )
92                                {
93                                        if ( !$this->starttls() )
94                                                throw new Exception('[connect] #2 it isn\'t possible start tls. File: ' . __FILE__ . '  ::  ' . __LINE__);
95
96                                        # $this->writeLog('NOTICE', 'Connected TLS');
97                                }
98                                else
99                                {
100                                        if ( !$this->_plain() )
101                                                throw new Exception('[connect] #3 it isn\'t possible carry out the verification. File: ' . __FILE__ . '  ::  ' . __LINE__);
102                                }
103                        }
104
105                        return $_connect;
106                }
107                catch(Exception $e)
108                {
109                        $this->writeLog('ERROR', $e->getMessage());
110                        $this->_disconnect();
111                        return false;
112                }
113        }
114
115        protected final function _disconnect()
116        {
117                try
118                {
119                        $xml = "</stream:stream>";
120
121                        #if ( $this->write($xml) === false )
122                        #       throw new Exception('[disconnect] #1 Cannot write to socket (' . $this->_socket . '). File: ' . __FILE__ . '  ::  ' . __LINE__);
123
124                        #if ( ($xml = $this->read()) === false )
125                        #       throw new Exception('[disconnect] #2 it isn\'t possible read the socket. File: ' . __FILE__ . '  ::  ' . __LINE__);
126                }
127                catch(Exception $e)
128                {
129                        $this->writeLog('ERROR', $e->getMessage());
130                        return false;
131                }
132        }
133
134        private final function starttls()
135        {
136                try
137                {
138                        $xml = "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>";
139                        if ( $this->write($xml) === false )
140                                throw new Exception('[starttls] #1 Cannot write to socket (' . $this->_socket . '). File: ' . __FILE__ . '  ::  ' . __LINE__);
141
142                        usleep(50000);
143                        fread($this->_socket, 4096);
144
145                        stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
146
147                        $xml  = "<?xml version='1.0' encoding='UTF-8'?>";
148                        $xml .= "<stream:stream to='" . $this->_server . "' xmlns='jabber:client' ";
149                        $xml .= "xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>";
150
151                        if ( $this->write($xml) === false )
152                                throw new Exception('[starttls] #2 Cannot write to socket (' . $this->_socket . '). File: ' . __FILE__ . '  ::  ' . __LINE__);
153
154                        usleep(50000);
155
156                        fread($this->_socket, 4096);
157
158                        usleep(50000);
159                       
160                        fread($this->_socket, 4096);
161                       
162                        if ( !$this->_plain() )
163                                throw new Exception('[starttls] #3 it isn\'t possible carry out the verification. File: ' . __FILE__ . '  ::  ' . __LINE__);
164
165                        return true;
166                }
167                catch(Exception $e)
168                {
169                        $this->writeLog('ERROR', $e->getMessage());
170                        return false;
171                }
172        }
173
174        private final function _plain()
175        {
176                try
177                {
178                        $this->blocking($this->_socket, 0);
179
180                        if ( ($xml = $this->read()) === false )
181                                throw new Exception('[_plain] #1 it isn\'t possible read the socket. File: ' . __FILE__ . '  ::  ' . __LINE__);
182
183                        $xml  = "<username>" . $this->_username . "</username>";
184                        $xml .= "<password>" . $this->_password . "</password>";
185                        $xml .= "<resource>" . $this->_resource . "</resource>";
186
187                        unset($this->_password);
188
189                        if ( !$this->iq('set', 'auth_1', NULL, NULL, "jabber:iq:auth", $xml) )
190                                throw new Exception('[_plain] #2 it isn\'t possible carry out the verification. File: ' . __FILE__ . '  ::  ' . __LINE__);
191
192                        while ( !preg_match("/<iq xmlns='jabber:client' id='auth_1' type='(result|error)'/", ($readSocket = $this->read()), $matches) )
193                                usleep(10000);
194
195                        if($matches[1] == "error")
196                                return false;
197
198                        if ( ($xml = $this->read()) === false )
199                                throw new Exception('[_plain] #3 it isn\'t possible read the socket. File: ' . __FILE__ . '  ::  ' . __LINE__);
200
201                        return true;
202                }
203                catch(Exception $e)
204                {
205                        $this->writeLog('ERROR', $e->getMessage());
206                        return false;
207                }
208        }
209
210        private final function _iq($pType = false, $pId = false, $pTo = false, $pFrom = false, $pXmlns = false, $pLoad = false )
211        {
212                $xml  = "<iq type='" . $pType . "' id='" . $pId . "'";
213                $xml .= ( $pTo ) ? " to='" . $pTo . "'" : "";
214                $xml .= ( $pFrom ) ? " from='" . $pFrom . "'" : "";
215
216                if ( $pXmlns == "vcard-temp" )
217                {
218                        $xml .= ">";
219                        $xml .= $pLoad;
220                }
221                else
222                {
223                        $xml .= "><query xmlns='" . $pXmlns . "'";
224                        $xml .= ( $pLoad ) ? ">" . $pLoad . "</query>" : "/>";
225                }
226
227                $xml .= "</iq>";
228
229                return $xml;
230        }
231
232        protected final function iq($pType = false, $pId = false, $pTo = false, $pFrom = false, $pXmlns = false, $pLoad = false)
233        {
234                try
235                {
236                        if ( !preg_match("/^(get|set|result|error)$/i", $pType, $matches) )
237                                throw new Exception('[iq] #1 type must be GET, SET, RESULT or ERROR. File: ' . __FILE__ . '  ::  ' . __LINE__);
238
239                        if ( $this->write($this->_iq($pType, $pId, $pTo, $pFrom, $pXmlns, $pLoad)) === false )
240                                throw new Exception('[iq] #2 Cannot write to socket (' . $this->_socket . '). File: ' . __FILE__ . '  ::  ' . __LINE__);
241                        else
242                                return true;
243                }
244                catch(Exception $e)
245                {
246                        $this->writeLog('ERROR', $e->getMessage());
247                        return false;
248                }
249        }
250
251        protected final function presence($pType = false, $pTo = false, $pShow = false, $pStatus = false, $pPriority = false)
252        {
253                try
254                {
255                        $xml  = "<presence";
256                        $xml .= ($pTo)   ? " to='{$pTo}'" : '';
257                        $xml .= ($pType) ? " type='{$pType}'" : '';
258
259                        if ( !($pStatus || $pShow || $pPriority) )
260                                $xml .= "/>";
261                        else
262                        {
263                                $xml .= ">";
264                                $xml .= ($pStatus) ? "<status>" . $pStatus . "</status>" : '';
265                                $xml .= ($pShow) ? "<show>" . $pShow . "</show>" : '';
266                                $xml .= ($pPriority) ? "<priority>" . $pPriority . "</priority>" : '';
267                                $xml .= ($pStatus || $pShow || $pPriority) ? "</presence>" : '';
268                        }
269
270                        if ( $this->write($xml) === false )
271                                throw new Exception('[presence] #1 it isn\'t possible send presence for ' . $this->_server . '. File: ' . __FILE__ . '  ::  ' . __LINE__);
272
273                        return true;
274                }
275                catch(Exception $e)
276                {
277                        $this->writeLog('ERROR', $e->getMessage());
278                        return false;
279                }
280        }
281
282        protected final function read()
283        {
284                $return = NULL;
285                do
286                {
287                        $line = NULL;
288                        $line = utf8_decode(parent::read($this->_socket, 4096));
289
290                        if ( $line === false )
291                        {
292                                $return = false;
293                                break;
294                        }
295
296                        if ( $line != NULL )
297                                $return .= $line;// . "\n";
298                }
299                while ( $line != NULL );
300
301                return $return;
302        }
303
304        protected final function write($pData = false)
305        {
306                if ( !$pData )
307                        return false;
308
309                return parent::write($this->_socket, utf8_encode($pData));
310        }
311
312        function __destruct()
313        {
314                $this->close($this->_socket);
315        }
316
317        protected final function writeLog($pType = false, $pLog = false)
318        {
319                if ( !defined('self::'.$pType) && !$pLog )
320                        return false;
321
322                if ( !(bool)constant('self::J_'.$pType) && !(bool)constant('self::J_ALL') )
323                        return false;
324
325                $log  = date('m/d/Y H:i:s');
326                $log .= ' [' . constant('self::'.$pType) . '] :: ';
327                $log .= $pLog . "\n";
328                if ( $fp = fopen (self::J_FILE, "a+") )
329                {
330                        fwrite($fp, $log);
331                        fclose($fp);
332                }
333        }
334}
335?>
Note: See TracBrowser for help on using the repository browser.