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

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