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

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