source: 3thparty/jmessenger/src/nu/fw/jeti/backend/Connect.java @ 3952

Revision 3952, 35.1 KB checked in by alexandrecorreia, 13 years ago (diff)

Ticket #1710 - Adicao do codigo fonte java do componente jmessenger(jabberit_messenger)

  • Property svn:executable set to *
Line 
1/*
2 *      Jeti, a Java Jabber client, Copyright (C) 2003 E.S. de Boer 
3 *
4 *  This program is free software; you can redistribute it and/or modify
5 *  it under the terms of the GNU General Public License as published by
6 *  the Free Software Foundation; either version 2 of the License, or
7 *  (at your option) any later version.
8 *
9 *  This program is distributed in the hope that it will be useful,
10 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 *      GNU General Public License for more details.
13 *
14 *  You should have received a copy of the GNU General Public License
15 *  along with this program; if not, write to the Free Software
16 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 *
18 *      For questions, comments etc,
19 *      use the website at http://jeti.jabberstudio.org
20 *  or mail/im me at jeti@jabber.org
21 */
22
23package nu.fw.jeti.backend;
24
25import java.awt.Color;
26import java.awt.Dimension;
27import java.awt.Font;
28import java.awt.GridBagConstraints;
29import java.awt.GridBagLayout;
30import java.awt.Insets;
31import java.awt.event.ActionEvent;
32import java.io.BufferedReader;
33import java.io.IOException;
34import java.io.InputStream;
35import java.io.InputStreamReader;
36import java.io.OutputStream;
37import java.io.PrintWriter;
38import java.io.UnsupportedEncodingException;
39import java.net.InetAddress;
40import java.net.Socket;
41import java.net.UnknownHostException;
42import java.security.KeyManagementException;
43import java.security.MessageDigest;
44import java.security.NoSuchAlgorithmException;
45import java.security.cert.CertificateExpiredException;
46import java.security.cert.CertificateNotYetValidException;
47import java.security.cert.X509Certificate;
48import java.text.MessageFormat;
49import java.util.Iterator;
50
51import javax.net.ssl.HandshakeCompletedEvent;
52import javax.net.ssl.HandshakeCompletedListener;
53import javax.net.ssl.SSLContext;
54import javax.net.ssl.SSLSocket;
55import javax.net.ssl.SSLSocketFactory;
56import javax.net.ssl.TrustManager;
57import javax.net.ssl.X509TrustManager;
58import javax.swing.JButton;
59import javax.swing.JDialog;
60import javax.swing.JLabel;
61import javax.swing.JOptionPane;
62import javax.swing.JPanel;
63import javax.swing.JPasswordField;
64import javax.swing.JTextField;
65import javax.swing.border.EmptyBorder;
66
67import nu.fw.jeti.events.DiscoveryListener;
68import nu.fw.jeti.events.LoginListener;
69import nu.fw.jeti.jabber.Backend;
70import nu.fw.jeti.jabber.JID;
71import nu.fw.jeti.jabber.elements.DiscoveryInfo;
72import nu.fw.jeti.jabber.elements.DiscoveryItem;
73import nu.fw.jeti.jabber.elements.IQAuth;
74import nu.fw.jeti.jabber.elements.IQAuthBuilder;
75import nu.fw.jeti.jabber.elements.IQExtension;
76import nu.fw.jeti.jabber.elements.IQPrivate;
77import nu.fw.jeti.jabber.elements.IQXRoster;
78import nu.fw.jeti.jabber.elements.InfoQuery;
79import nu.fw.jeti.jabber.elements.JetiPrivateExtension;
80import nu.fw.jeti.jabber.elements.JetiPrivateRosterExtension;
81import nu.fw.jeti.jabber.elements.Packet;
82import nu.fw.jeti.jabber.elements.Presence;
83import nu.fw.jeti.jabber.elements.PresenceBuilder;
84import nu.fw.jeti.jabber.elements.StreamError;
85import nu.fw.jeti.plugins.PluginsInfo;
86import nu.fw.jeti.plugins.XMPP;
87import nu.fw.jeti.util.Digest;
88import nu.fw.jeti.util.I18N;
89import nu.fw.jeti.util.Log;
90import nu.fw.jeti.util.Utils;
91
92/**
93 * @author E.S. de Boer
94 */
95
96//TODO stop packet start spul en de andere dingen in aparte class??
97//TODO improve error reporting, make it translatable
98 //class voor connectie
99
100public class Connect implements ConnectionPacketReceiver
101{
102        private Output output;
103        private Input input;
104        private String authenticationId="yytr";
105        private JabberHandler jabberHandler;
106        private LoginInfo loginInfo;
107        private Backend backend;
108        private static JID myJID = new JID("test","test","test");
109        private boolean authenticated = false;
110        private boolean reconnecting = false;
111        private long latestConnected=0;
112        private int show;
113        private String status;
114        private String connectionID;
115        private Discovery discovery;
116        private OwnCapabilities capabilities;
117        private Socket socket;//socket needed to close if abort
118        private Thread connectThread;//login thread
119        private volatile boolean abort = false;//abort login
120        private IQTimerQueue iqTimerQueue;
121        private Handlers handlers;
122        private XMPP xmpp;
123       
124        // windowProxy
125        private JButton buttonCancel;
126        private JButton buttonOk;
127        private JDialog dialog;
128        private JLabel infoLabel;
129        private JLabel lblUsername;
130        private JLabel lblPassword;
131        private JPanel buttonPanel;
132        private JPanel panelMain;
133        private JPasswordField txtPassword;
134        private JOptionPane optionPane;
135        private JTextField txtUsername;
136   
137        public Connect(Backend backend,IQTimerQueue timerQueue,Handlers handlers)
138        {
139                this.backend = backend;
140                iqTimerQueue = timerQueue;
141                this.handlers = handlers;
142                discovery = new Discovery(backend) ;
143                capabilities = new OwnCapabilities(backend);
144        }
145
146        public void addCapability(String capability,String feature)
147        {
148                capabilities.addCapability(capability, feature);
149        }
150       
151        public void removeCapability(String capability,String feature)
152        {
153                capabilities.removeCapability(capability, feature);
154        }
155       
156        public int getStatus()
157        {
158                return show;
159        }
160       
161        public void getItems(JID jid, DiscoveryListener listener, boolean useCache)
162        {
163                discovery.getItems(jid,listener,useCache);
164        }
165       
166        public void getItems(JID jid, DiscoveryListener listener)
167        {
168                discovery.getItems(jid,listener);
169        }
170       
171        public void getInfo(JID jid, DiscoveryListener listener)
172        {
173                discovery.getInfo(jid,listener);
174        }
175       
176        public void getItems(JID jid,String node, DiscoveryListener listener)
177        {
178                discovery.getItems(jid,node,listener);
179        }
180       
181        public void getInfo(JID jid,String node, DiscoveryListener listener)
182        {
183                discovery.getInfo(jid,node,listener);
184        }
185       
186        public boolean isLoggedIn()
187        {
188                return authenticated;
189        }
190       
191        public boolean isPasswordValid(String password)
192        {
193                return loginInfo.getPassword().equals(password);
194        }
195
196    public void login(LoginInfo info)
197    {
198        autoLogin(info,2);
199    }
200   
201    public void autoLogin(LoginInfo info,final int tries)
202        {
203                abort = false;
204                loginInfo = info;
205                connectThread = new Thread()
206                {
207                        int tel = 0;
208                       
209                        public void run()
210                        {
211                                boolean connected = false;
212                                int triesc      = 0;
213                                int posIn       = 0;
214                                int posFi       = 0;
215                               
216                                String hosts = loginInfo.getHost();
217                               
218                                if( hosts.indexOf(" ") != -1 )
219                                {
220                                        hosts = hosts + " ";
221                                       
222                                        for( int i = 0; i < hosts.length(); i++ )
223                                        {
224                                                String w = String.valueOf(hosts.charAt(i));
225                                               
226                                                if( w.equals(" ") )
227                                                {
228                                                        posIn = posFi;
229                                                        posFi = i;
230                                                       
231                                                        String hostConnect = hosts.substring(posIn, posFi).trim();
232                                                       
233                                                        while( tel < tries )
234                                                        {
235                                                                if( tel == 0)
236                                                                {
237                                                                        connected = connect( hostConnect, false );
238                                                                }
239                                                                else
240                                                                {
241                                                                        connected = connect( hostConnect, true );
242                                                                }
243
244                                                                if( connected )
245                                                                {
246                                                                        i = hosts.length();
247                                                                        break;
248                                                                }       
249                                                               
250                                                                try { Thread.sleep(600);}
251                                                                catch (InterruptedException e){}
252                                                                tel++;
253                                                        }       
254                                                       
255                                                               
256                                                        tel = 0;
257                                                }
258                                        }
259                                }
260                                else
261                                {
262                                       
263                                        while( tel < tries )
264                                        {
265                                                if( tel == 0)
266                                                {
267                                                        connected = connect( hosts, false );
268                                                }
269                                                else
270                                                {
271                                                        connected = connect( hosts, true );
272                                                }
273
274                                                if( connected )
275                                                {
276                                                        break;
277                                                }       
278                                               
279                                                try { Thread.sleep(600);}
280                                                catch (InterruptedException e){}
281                                                tel++;
282                                        }       
283                                }
284
285                                if( !connected )
286                                {
287                                        interrupt();
288                                loginInfo.setProxyUsername(null);
289                                loginInfo.setProxyPassword(null);
290                                        System.out.println("***** Login Failed *****");                                 
291                                }
292                        }
293                };
294               
295                connectThread.start();
296        }
297   
298    public void abort()
299    {
300                abort = true;
301               
302                if( socket != null )
303                {
304                        try
305                        {
306                                socket.close();
307                        }
308                        catch (IOException e)
309                        {
310                                e.printStackTrace();
311                        }
312                }
313        connectThread.interrupt();
314                disconnect();
315    }
316   
317    public boolean isAborted()
318    {
319        return abort;
320    }
321
322        synchronized private boolean connect( String host, boolean proxy )
323        {       
324                latestConnected = System.currentTimeMillis();
325               
326                if( loginInfo == null )
327                        return true;
328
329                if( authenticated )
330                        disconnect();//clear old connection
331               
332                jabberHandler = new JabberHandler(this,handlers);
333               
334                if( xmpp == null && PluginsInfo.isPluginLoaded("xmpp") )
335                {
336                        xmpp = (XMPP)PluginsInfo.newPluginInstance("xmpp");
337                        handlers.loadExtraHandlers(xmpp.getXMPPHandlers());
338                }
339                               
340                try
341                {               
342           
343                        if (host == null || host.length() == 0)
344            {
345                if(loginInfo.useProxy(LoginInfo.NO_PROXY) && PluginsInfo.isPluginLoaded("xmpp"))
346                {
347                        host = xmpp.resolveXMPPDomain(loginInfo.getServer());
348                }
349                else host = loginInfo.getServer();
350            }
351                       
352                        if( loginInfo.isSSl() )
353                {
354                                if( proxy )
355                                {
356                                        //System.out.println("CONNECT COM PROXY - SEGURA : " + host);
357                                        Socket tunnel = createHTTPTunel(host);
358                                socket = new DummySSLSocketFactory().createSocket(tunnel, host, loginInfo.getPort(),true);
359                        }
360                                else
361                                {
362                                        //System.out.println("CONNECT SEM PROXY - SEGURA : " + host);
363                                        socket = new DummySSLSocketFactory().createSocket(host,loginInfo.getPort());
364                                }
365                }
366                else
367                {
368                        if( proxy )
369                        {
370                                //System.out.println("CONNECT COM PROXY - NÃO SEGURA : " + host);
371                                socket = createHTTPTunel(host);
372                        }
373                        else
374                        {
375                                //System.out.println("CONNECT SEM PROXY - NÃO SEGURA : " + host);
376                                socket = new Socket( host,loginInfo.getPort() );
377                        }
378                }
379        }
380                catch (UnknownHostException ex){ return false; }
381                catch (IOException ex){ return false; }
382
383                if( abort )
384                        return false;
385               
386                try
387                {
388                        input = new Input(socket.getInputStream(), this, jabberHandler);
389        }
390                catch (IOException ex){ return false; }
391               
392                if( abort )
393                        return false;
394               
395            try
396            {
397                        output = new Output(socket, loginInfo.getServer(), this, socket.getOutputStream());
398        }
399            catch (IOException ex){ return false; }
400               
401        return true;
402        }
403       
404        String host;
405       
406        public boolean startTls(ConnectionPacketReceiver cpr)
407        {
408                if(abort)
409                        return false;
410               
411                try
412                {               
413           //TODO stop output
414                        output.disconnect(false);
415                        input.disconnect();
416            socket = new DummySSLSocketFactory().createSocket(socket,host,loginInfo.getPort(),true);
417            jabberHandler = new JabberHandler(cpr,handlers);
418         
419            try
420            {
421                    input = new Input(socket.getInputStream(),this,jabberHandler);
422                }
423            catch (IOException ex)
424                {
425                                return false;
426                }
427               
428            try
429            {
430                        output = new Output(socket,loginInfo.getServer(),this,socket.getOutputStream());
431                }
432            catch (IOException ex)
433                {
434                                //sendLoginError(I18N.gettext("main.loginstatus.Could_not_open_output_because") + " " +ex.getMessage());
435                                return false;
436                }
437                           
438                if(abort)
439                        return false;
440               
441                }
442                catch(IOException e){}
443               
444                return true;
445        }
446       
447        //used by compression plugin
448        public Socket getSocket()
449        {
450                return socket;
451        }
452       
453        public boolean startCompressed(ConnectionPacketReceiver cpr,InputStream inputStream,OutputStream outputStream)
454        {
455                jabberHandler = new JabberHandler(cpr,handlers);
456                if ( abort )
457                        return false;
458       
459                output.disconnect(false);
460                Input input2 = input;
461                input = new Input(inputStream,this,jabberHandler);
462        try
463        {
464                output = new Output(socket,loginInfo.getServer(),this,outputStream);
465        }
466        catch (IOException ex)
467        {
468                        sendLoginError(I18N.gettext("main.loginstatus.Could_not_open_output_because") + " " +ex.getMessage());
469                        ex.printStackTrace();
470                        return false;
471        }
472                   
473        if ( abort )
474                return false;
475        input2.disconnect();
476        //FIXME Using thread.stop because throwing an exception to stop the sax parser in the input thread fails
477        input2.stop();
478        //throw new RuntimeException();
479
480                return true;
481        }
482       
483        public void startSasl(ConnectionPacketReceiver cpr)
484        {
485                if( abort )
486                        return;
487               
488                //kill old input and send new stream
489                //input.disconnect();
490                jabberHandler = new JabberHandler(cpr,handlers);
491               
492                try
493                {
494                        input = new Input(socket.getInputStream(),this,jabberHandler);
495                }
496                catch (IOException e)
497                {
498                        e.printStackTrace();
499                }
500               
501                try
502                {
503                        output.writeHeader();
504                }
505                catch (IOException e)
506                {
507                        e.printStackTrace();
508                }
509               
510                throw new UnsupportedOperationException("end xmlparser");
511        }
512       
513        private Socket createHTTPTunel(String host) throws IOException
514        {
515                String tunnelHost = loginInfo.getProxyServer();
516            int tunnelPort = Integer.valueOf(loginInfo.getProxyPort()).intValue();
517            String typeProxy = typeProxy(tunnelHost, tunnelPort, host, loginInfo.getPort());
518
519                if( typeProxy.indexOf("Proxy-Authenticate: Digest") != -1 )
520                {
521                        // Proxy Username and Password
522                        if( loginInfo.getProxyPassword() == null && loginInfo.getProxyPassword() == null)
523                                windowProxy(tunnelHost);
524
525                        return doTunnelHandshakeDigest(host, loginInfo.getPort());
526                }
527                else if( typeProxy.indexOf("Proxy-Authenticate: Basic") != -1 )
528                {
529                        // Proxy Username and Password
530                        if( loginInfo.getProxyPassword() == null && loginInfo.getProxyPassword() == null)
531                                windowProxy(tunnelHost);
532
533                        Socket tunnel = new Socket(tunnelHost, tunnelPort);
534                        doTunnelHandshake(tunnel, host, loginInfo.getPort());
535                        return tunnel;
536                }
537                else if( typeProxy.indexOf("HTTP/1.0 200") != -1 )
538                {
539                        Socket tunnel = new Socket(tunnelHost, tunnelPort);
540                        PrintWriter writeConnection = new PrintWriter( tunnel.getOutputStream(), true );
541                        BufferedReader readConnection = new BufferedReader(new InputStreamReader(tunnel.getInputStream()));
542
543                        String msg = "CONNECT " + host + ":" + loginInfo.getPort() + " HTTP/1.1\r\n" +
544                                                 "User-Agent: " + sun.net.www.protocol.http.HttpURLConnection.userAgent + "\r\n" +
545                                                 "Proxy-Connection: Keep-Alive\r\n";
546                       
547                        writeConnection.println(msg);
548                        String line = "";
549                       
550                        while((line = readConnection.readLine()) != null )
551                        {
552                                if( line.indexOf("HTTP/1.0 200") != -1 )
553                                        break;
554                        }
555                       
556                        return tunnel;
557                }
558
559                return new Socket();
560        }
561
562        private void windowProxy(String tunnelHost)
563        {
564                panelMain = new JPanel();
565                panelMain.setBackground(Color.ORANGE);
566                panelMain.setPreferredSize(new Dimension(400,120));
567                panelMain.setLayout(new GridBagLayout());
568                GridBagConstraints gbc = new GridBagConstraints();
569
570                // Espaco entre elementos;
571                gbc.insets = new Insets(2, 2, 2, 2);
572            gbc.gridy = 0; // row
573            gbc.gridx = 0; // col
574            gbc.gridwidth = 2;
575            gbc.anchor = GridBagConstraints.WEST;
576           
577            infoLabel = new JLabel(I18N.gettext("main.connect.proxy.Authentication_for") + " " + tunnelHost + " :");
578            infoLabel.setFont(new Font("SansSerif",Font.BOLD, 14));
579            infoLabel.setBorder(new EmptyBorder(0, 0, 5, 0));
580            panelMain.add(infoLabel, gbc);
581
582            // Label Username
583            gbc.gridy = 1; // row
584            gbc.gridx = 0; // col
585            gbc.gridwidth = 1;
586            lblUsername = new JLabel(I18N.gettext("main.connect.proxy.Username")+":");
587            panelMain.add(lblUsername, gbc);
588
589            // JTextField do Username
590            gbc.gridy = 1; // row
591            gbc.gridx = 1; // col
592            txtUsername = new JTextField(20);
593            panelMain.add(txtUsername, gbc);
594
595            // Label Password
596            gbc.gridy = 2; // row
597            gbc.gridx = 0; // col
598            lblPassword = new JLabel(I18N.gettext("main.connect.proxy.Password")+":");
599            panelMain.add(lblPassword, gbc);   
600
601            // JPasswordField               
602            gbc.gridy = 2; // row
603            gbc.gridx = 1; // col
604            txtPassword = new JPasswordField(20);
605            panelMain.add(txtPassword, gbc);
606
607            // Buttons
608            gbc.gridy = 3; // linha
609            gbc.gridx = 1; // coluna
610            gbc.gridwidth = 2; // duas células na linha
611            gbc.anchor = GridBagConstraints.WEST;
612            buttonPanel = new JPanel();
613            buttonCancel = new JButton(I18N.gettext("main.connect.proxy.Cancel"));
614            buttonOk = new JButton(I18N.gettext("main.connect.proxy.Ok"));
615           
616            // Event click Ok
617                buttonOk.addActionListener(new java.awt.event.ActionListener()
618                {
619            public void actionPerformed(ActionEvent e)
620            {
621                String Username = txtUsername.getText().toString();
622                String Password = txtPassword.getText().toString();
623               
624                if( !Username.trim().equals("") && !Password.trim().equals("") )
625                {       
626                        loginInfo.setProxyUsername(Username);
627                        loginInfo.setProxyPassword(Password);
628                        dialog.setVisible(false);
629                }
630            }
631                });
632
633            // Event click Cancel
634                buttonCancel.addActionListener(new java.awt.event.ActionListener()
635                {
636            public void actionPerformed(ActionEvent e)
637            {
638                        loginInfo.setProxyUsername(null);
639                        loginInfo.setProxyPassword(null);
640                dialog.setVisible(false);
641            }
642                });
643               
644                buttonPanel.setBackground(Color.ORANGE);
645                buttonPanel.add(buttonOk);
646                buttonPanel.add(buttonCancel);
647            panelMain.add(buttonPanel, gbc);
648               
649            optionPane = new JOptionPane();
650            optionPane.setMessage(I18N.gettext("main.connect.proxy.The_proxy_is_requesting_a_username_and_password") + "!");
651            optionPane.setMessageType(JOptionPane.INFORMATION_MESSAGE);
652            optionPane.setOptions(new Object[] {panelMain});
653            dialog = optionPane.createDialog(null, I18N.gettext("main.connect.proxy.Authentication_required"));
654            dialog.setVisible(true);
655        }
656       
657        private String typeProxy(String proxyServer, int proxyPort, String host, int port) throws IOException
658        {
659                Socket connection = new Socket(proxyServer, proxyPort);
660                PrintWriter writeConnection = new PrintWriter( connection.getOutputStream(), true );
661                BufferedReader readConnection = new BufferedReader(new InputStreamReader(connection.getInputStream()));
662                String _return = "";
663                String line = "";
664                int count = 0;
665               
666                String msg = "CONNECT " + host + ":" + port + " HTTP/1.1\r\n" +
667                                         "User-Agent: " + sun.net.www.protocol.http.HttpURLConnection.userAgent + "\r\n" +
668                                         "Proxy-Connection: Keep-Alive\r\n";
669
670                writeConnection.println(msg);
671               
672                while((line = readConnection.readLine()) != null )
673                {
674                        if( line.indexOf("Proxy") != -1 )
675                                _return += line + "\n";
676                       
677                        if( line.indexOf("Proxy-Connection: close") != -1 || count == 12 )
678                                break;
679
680                        if( line.indexOf("HTTP/1.0 200") != -1 )
681                        {
682                                _return += line + "\n";
683                                break;
684                        }
685                        count++;
686                }
687               
688               
689                writeConnection.close();
690                readConnection.close();
691                connection.close();
692
693                return _return;
694        }
695
696        // Proxy Authorization: Basic   
697        private void doTunnelHandshake(Socket tunnel, String host, int port) throws IOException
698        {
699                OutputStream out = tunnel.getOutputStream();
700               
701                String msg = "CONNECT " + host + ":" + port + " HTTP/1.0\n"
702                                + "User-Agent: "
703                                + sun.net.www.protocol.http.HttpURLConnection.userAgent;
704               
705                if ( loginInfo.getProxyUsername() != null && loginInfo.getProxyPassword() != null )
706                {
707                        //add basic authentication header for the proxy
708                        sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
709                        String encodedPassword = enc.encode((loginInfo.getProxyUsername() + ":" + loginInfo.getProxyPassword()).getBytes());
710                        msg = msg + "\nProxy-Authorization: Basic " + encodedPassword;
711            }
712               
713                msg = msg + "\nContent-Length: 0"
714                                  + "\nPragma: no-cache"
715                          + "\r\n\r\n";
716
717                byte b[];
718                try
719                {
720                        /*
721                         * We really do want ASCII7 -- the http protocol doesn't change
722                         * with locale.
723                         */
724                        b = msg.getBytes("ASCII7");
725                }
726                catch (UnsupportedEncodingException ignored)
727                {
728                        /*
729                         * If ASCII7 isn't there, something serious is wrong, but
730                         * Paranoia Is Good (tm)
731                         */
732                        b = msg.getBytes();
733                }
734                out.write(b);
735                out.flush();
736
737                /*
738                 * We need to store the reply so we can create a detailed error
739                 * message to the user.
740                 */
741                byte reply[] = new byte[200];
742                int replyLen = 0;
743                int newlinesSeen = 0;
744                boolean headerDone = false; /* Done on first newline */
745                InputStream in = tunnel.getInputStream();
746
747                while ( newlinesSeen < 2 )
748                {
749                        int i = in.read();
750                        if (i < 0) { throw new IOException("Unexpected EOF from proxy"); }
751                        if (i == '\n')
752                        {
753                                headerDone = true;
754                                ++newlinesSeen;
755                        } else if (i != '\r')
756                        {
757                                newlinesSeen = 0;
758                                if (!headerDone && replyLen < reply.length)
759                                {
760                                        reply[replyLen++] = (byte) i;
761                                }
762                        }
763                }
764
765                /*
766                 * Converting the byte array to a string is slightly wasteful in the
767                 * case where the connection was successful, but it's insignificant
768                 * compared to the network overhead.
769                 */
770                String replyStr;
771                try
772                {
773                        replyStr = new String(reply, 0, replyLen, "ASCII7");
774                }
775                catch (UnsupportedEncodingException ignored)
776                {
777                        replyStr = new String(reply, 0, replyLen);
778                }
779
780                /*
781                 * We check for Connection Established because our proxy returns
782                 * HTTP/1.1 instead of 1.0
783                 */
784               
785                // if (!replyStr.startsWith("HTTP/1.0 200")) {
786                if (replyStr.toLowerCase().indexOf("200 connection established") == -1)
787                {
788                        String tunnelHost = System.getProperty("http.proxyHost");
789                        String tunnelPort = System.getProperty("http.proxyPort");
790                        throw new IOException("Unable to tunnel through " + tunnelHost
791                                        + ":" + tunnelPort + ".  Proxy returns \"" + replyStr + "\"");
792                }
793               
794                /* tunneling Handshake was successful! */
795        }
796
797        //Proxy-Authenticate Digest
798        private Socket doTunnelHandshakeDigest(String host, int port) throws IOException
799        {
800                Digest hashProxy        = new Digest();
801                String response         = "";
802                String nonce            = "";
803                String cnonce           = "ALEC290908" + String.valueOf(System.currentTimeMillis());
804                String qop                      = "";
805                String uri                      = "/";
806                String username         = loginInfo.getProxyUsername();
807                String password         = loginInfo.getProxyPassword();
808                String realm            = "";
809                String line                     = "";
810
811                // Dados Proxy
812                String proxyServer = loginInfo.getProxyServer();
813                int proxyPort = Integer.valueOf(loginInfo.getProxyPort()).intValue();
814
815                // PRIMEIRA PARTE
816                Socket tunnel = new Socket(proxyServer, proxyPort);
817                PrintWriter writeTunnel = new PrintWriter(tunnel.getOutputStream(), true);
818                BufferedReader readTunnel = new BufferedReader(new InputStreamReader(tunnel.getInputStream()));         
819
820                String msg = "CONNECT " + host + ":" + port + " HTTP/1.1\r\n" +
821                                         "User-Agent: " + sun.net.www.protocol.http.HttpURLConnection.userAgent + "\r\n" +
822                                         "Proxy-Connection: Keep-Alive\r\n";
823
824                writeTunnel.println(msg);
825               
826                while((line = readTunnel.readLine()) != null )
827                {
828                        // Get nonce;
829                        if ( line.indexOf("nonce=\"") != -1 )
830                        {
831                        nonce = line.substring(line.indexOf("nonce=\"") + 7);
832                        nonce = nonce.substring(0,nonce.indexOf("\","));
833                        }       
834
835                        // Get realm;
836                        if ( line.indexOf("realm=\"") != -1 )
837                        {
838                        realm = line.substring(line.indexOf("realm=\"") + 7);
839                        realm = realm.substring(0,realm.indexOf("\","));
840                        }
841                       
842                        // Get qop;
843                        if ( line.indexOf("qop=\"") != -1 )
844                        {
845                                qop = line.substring(line.indexOf("qop=\"") + 5);
846                                qop = qop.substring(0,qop.indexOf("\","));
847                        }
848                }
849
850                writeTunnel.close();
851                readTunnel.close();
852                tunnel.close();
853               
854                response = hashProxy.hashMD5(nonce, cnonce, qop, "CONNECT:"+uri, username, password, realm);
855                line = "";
856               
857                // SEGUNDA PARTE
858                tunnel          = new Socket(proxyServer, proxyPort);
859                writeTunnel     = new PrintWriter(tunnel.getOutputStream(), true);
860                readTunnel      = new BufferedReader(new InputStreamReader(tunnel.getInputStream()));           
861
862                msg = "CONNECT " + host + ":" + port + " HTTP/1.1\r\n" +
863                          "Proxy-Authorization: Digest username=\""+username+"\", "+
864                      "realm=\""+realm+"\", nonce=\""+nonce+"\", uri=\""+uri+"\", " +
865                      "cnonce=\""+cnonce+"\", nc=00000001, qop=\""+qop+"\", response=\""+response+"\"\r\n" +
866                          "User-Agent: " + sun.net.www.protocol.http.HttpURLConnection.userAgent + "\r\n" +
867                      "Proxy-Connection: Keep-Alive\r\n";
868
869                int count = 0;
870                writeTunnel.println(msg);
871               
872                while((line = readTunnel.readLine().trim()) != null )
873                {
874                        if( line.indexOf("HTTP/1.0 200 OK") != -1 )
875                                break;
876                       
877                        if( line.indexOf("HTTP/1.0 503") != -1 )
878                                break;
879                       
880                        if( count == 1 )
881                                break;
882                       
883                        count++;
884                }
885               
886                /* tunneling Handshake was successful! */               
887                return tunnel;
888        }
889       
890        private void sendLoginMessage(String message)
891        {
892                for(Iterator j = backend.getListeners(LoginListener.class);j.hasNext();)
893                {
894                        ((LoginListener)j.next()).loginMessage(message);
895                }
896        }
897       
898        private void sendLoginStatus(int count)
899        {
900                /*for(Iterator j = backend.getListeners(LoginListener.class);j.hasNext();)
901                {
902                        ((LoginListener)j.next()).loginStatus(count);
903                }*/
904        }
905       
906        public void sendLoginError(String message)
907        {
908                for(Iterator j = backend.getListeners(LoginListener.class);j.hasNext();)
909                {
910                        ((LoginListener)j.next()).loginError(message);
911                }
912        }
913       
914        public void sendUnauthorized()
915        {
916                for(Iterator j = backend.getListeners(LoginListener.class);j.hasNext();)
917                {
918                        ((LoginListener)j.next()).unauthorized();
919                }
920        }
921
922        synchronized public void connected(String connectionID,String xmppVersion)
923        {
924                if(!abort)
925                {
926                        if(xmppVersion!=null && PluginsInfo.isPluginLoaded("xmpp"))
927                        {
928                                ConnectionPacketReceiver cpr = xmpp.getConnectionPacketReceiver(loginInfo,this);
929                                jabberHandler.changePacketReceiver(cpr);
930                                cpr.connected(connectionID, xmppVersion);
931                        }
932                        else
933                        {
934                                jabberHandler.changePacketReceiver(this);
935                                // Este atributo é usado na transferência de arquivos
936                                // socket = null; //clear socket reference
937                                this.connectionID = connectionID;
938                                // TODO remove lowercase if filetransfer bug fixed
939                                output.send(new InfoQuery(null,"get",new IQAuth(loginInfo.getUsername().toLowerCase(),null,null)));
940                        }
941                }
942               
943        }
944
945        public void authenticate(IQAuth iqAuth)
946        {
947                if(!abort)
948                {
949                        authenticationId = "Jeti_Auth_" + new java.util.Date().getTime();
950                       
951                        if(iqAuth.hasDigest())
952                        {
953                                MessageDigest sha = null;
954                                try {
955                                  sha = MessageDigest.getInstance("SHA");
956                                } catch (Exception ex){
957                                  Log.error(I18N.gettext("main.loginstatus.Could_not_login_with_SHA"));
958                                  // TODO remove lowercase if filetransfer bug fixed
959                                  output.send(new InfoQuery(null,"set",authenticationId,new IQAuth(loginInfo.getUsername().toLowerCase(),loginInfo.getPassword() ,loginInfo.getResource())));
960                                  return;
961                                }
962
963                                sha.update(connectionID.getBytes());
964                                String digest = Utils.toString(sha.digest(loginInfo.getPassword().getBytes()));
965                                IQAuthBuilder iqab =  new IQAuthBuilder();
966                                iqab.digest = digest;
967                                // TODO remove lowercase if filetransfer bug fixed
968                                iqab.username = loginInfo.getUsername().toLowerCase();
969                                iqab.resource = loginInfo.getResource();
970                                output.send(new InfoQuery(null,"set",authenticationId,(IQExtension)iqab.build()));
971                        }
972                        else
973                        {
974                                if(!loginInfo.isSSl())
975                                {
976                                        int option = JOptionPane.showConfirmDialog(null,
977                                                        I18N.gettext("main.loginstatus.Sending_password_as_plain_text_over_an_unencrypted_connection,_continue?"),"Plain text",JOptionPane.YES_NO_OPTION);
978                                        if (option == JOptionPane.NO_OPTION)
979                                        {
980                                                sendLoginError("Sending password in plain not allowed");
981                                                return;
982                                        }
983                                }
984//                              TODO remove lowercase if filetransfer bug fixed
985                                output.send(new InfoQuery(null,"set",authenticationId,new IQAuth(loginInfo.getUsername().toLowerCase(),loginInfo.getPassword() ,loginInfo.getResource())));
986                        }
987                }
988        }
989
990        public void authenticated(InfoQuery infoQuery)
991        {
992                if(!abort)
993                {
994                        if(infoQuery.getType().equals("error"))
995                        {
996                                if(infoQuery.getErrorCode() == 401)
997                                {
998                                        sendUnauthorized();             
999                                }
1000                                else
1001                                {
1002                                        sendLoginError(I18N.gettext("main.loginstatus.Not_logged_in_because") + " " + infoQuery.getErrorDescription());
1003                                }       
1004                                return;
1005                        }
1006                        //TODO remove lowercase if filetransfer bug fixed
1007                        JID jid = new JID(loginInfo.getUsername().toLowerCase(),loginInfo.getServer() ,loginInfo.getResource());
1008                        authenticated(jid);
1009                }
1010        }
1011
1012        public void authenticated(JID jid)
1013        {
1014                myJID = jid;
1015                iqTimerQueue.clear();//remove iqs from previous connections
1016                jabberHandler.changePacketReceiver(new Jabber(backend,capabilities,discovery,iqTimerQueue));
1017                authenticated = true;
1018        reconnecting = false;
1019                output.setAuthenticated();
1020
1021                //TODO increase timeout
1022                getItems(new JID(loginInfo.getServer()), new DiscoveryListener()
1023                {
1024                        public void discoveryItemResult(JID jid, DiscoveryItem item)
1025                        {
1026                                //cache disco items for this server
1027                                if (item.hasItems())
1028                                {
1029                                        for(Iterator i = item.getItems();i.hasNext();)
1030                                        {
1031                                                DiscoveryItem di = (DiscoveryItem)i.next();
1032                                                backend.getInfo(di.getJID(),null);
1033                                        }
1034                                }
1035                        }
1036                        public void discoveryInfoResult(JID jid, DiscoveryInfo info) {}
1037                });
1038                output.send(new InfoQuery("get",new IQPrivate(new JetiPrivateExtension())));
1039                output.send(new InfoQuery("get",new IQXRoster()));
1040                if(show == Presence.NONE)
1041                {
1042                        show = Presence.AVAILABLE;
1043                }
1044                latestConnected = System.currentTimeMillis();
1045               
1046        }
1047       
1048        public void connected()
1049        {
1050                sendStatus();
1051                send(new InfoQuery("get",new IQPrivate(new JetiPrivateRosterExtension())));
1052                for( Iterator j = backend.getListeners(nu.fw.jeti.events.StatusChangeListener.class) ; j.hasNext(); )
1053                {
1054                        //online
1055                        ((nu.fw.jeti.events.StatusChangeListener)j.next()).connectionChanged(true);
1056                }
1057        }
1058
1059        public void receivePackets(Packet packet)
1060        {
1061                if (packet instanceof StreamError) streamError((StreamError)packet);
1062                else if(authenticationId.equals(packet.getID())) authenticated((InfoQuery)packet);
1063                else if(packet instanceof InfoQuery)
1064                {
1065                    IQExtension extension = packet.getIQExtension();
1066                        if(extension instanceof IQAuth)
1067                        {
1068                                if(((InfoQuery)packet).getType().equals("error"))
1069                                {
1070                                        sendLoginError(packet.getErrorDescription());
1071                                }
1072                                else authenticate((IQAuth) extension);
1073                        }
1074                }
1075        }
1076
1077        public void inputDeath()
1078        {
1079                try
1080                {
1081                        if( socket != null ) socket.close();
1082                }
1083                catch (IOException e)
1084                {
1085                        e.printStackTrace();
1086                }
1087               
1088                if((authenticated || reconnecting))
1089                {
1090                        authenticated = false;
1091            if (reconnecting) {
1092                try {
1093                    Thread.sleep(10000);
1094                } catch (InterruptedException e) {};
1095            }
1096            reconnecting = true;
1097                        output.disconnect(true);
1098                        for(Iterator j = backend.getListeners(nu.fw.jeti.events.StatusChangeListener.class);j.hasNext();)
1099                        {
1100                                //offline
1101                                ((nu.fw.jeti.events.StatusChangeListener)j.next()).connectionChanged(false);
1102                        }
1103                }
1104               
1105        }
1106
1107        public void streamError(StreamError error)
1108        {
1109                //only when logging in
1110                if(authenticated)
1111                {
1112                        authenticated = false;
1113                        output.disconnect(true);
1114                        for(Iterator j = backend.getListeners(nu.fw.jeti.events.StatusChangeListener.class);j.hasNext();)
1115                        {
1116                                //offline
1117                                ((nu.fw.jeti.events.StatusChangeListener)j.next()).connectionChanged(false);
1118                        }
1119                }
1120                sendLoginError(error.getErrorDescription());
1121        }
1122
1123        public void outputDeath()
1124        {
1125                authenticated = false;
1126                for(Iterator j = backend.getListeners(nu.fw.jeti.events.StatusChangeListener.class);j.hasNext();)
1127                {
1128                        //offline
1129                        ((nu.fw.jeti.events.StatusChangeListener)j.next()).connectionChanged(false);
1130                }
1131        }
1132
1133        public static JID getMyJID()
1134        {
1135            return myJID;
1136        }
1137
1138        public boolean getOnline()
1139        {
1140            return authenticated;
1141        }
1142
1143        public void disconnect()
1144        {
1145                if( authenticated )
1146                {
1147                        send(new Presence(myJID, "unavailable"));
1148                        authenticated = false;
1149                        output.disconnect(true);
1150                }
1151                output = null;
1152                for(Iterator j = backend.getListeners(nu.fw.jeti.events.StatusChangeListener.class);j.hasNext();)
1153                {
1154                        //offline
1155                        ((nu.fw.jeti.events.StatusChangeListener)j.next()).connectionChanged(false);
1156                }
1157        }
1158
1159        public void exit()
1160        {
1161                if(authenticated)
1162                {
1163                        send(new nu.fw.jeti.jabber.elements.Presence(myJID,"unavailable"));
1164                        authenticated = false;
1165                        output.disconnect(true);
1166                }
1167                output = null;
1168                for(Iterator j = backend.getListeners(nu.fw.jeti.events.StatusChangeListener.class);j.hasNext();)
1169                {//exit
1170                        ((nu.fw.jeti.events.StatusChangeListener)j.next()).exit();
1171                }
1172        }
1173
1174        public void send(Packet packet)
1175        {
1176                if(authenticated) output.send(packet);
1177                else nu.fw.jeti.util.Log.notSend(packet.toString());
1178        }
1179       
1180        public void sendWhileConnecting(Packet packet)
1181        {
1182                output.send(packet);
1183        }
1184
1185        public String getAccountInfo()
1186        {
1187                return MessageFormat.format(I18N.gettext("main.popup.logged_in_as_{0}_on_server_{1}_with_resource_{2}"),new Object[]{loginInfo.getUsername(),loginInfo.getServer(),loginInfo.getResource()});
1188        }
1189
1190        public void sendStatus()
1191        {
1192                if( authenticated )
1193                {
1194                        PresenceBuilder pb = new PresenceBuilder();
1195                        pb.show = show;
1196                        pb.status = status;
1197                        pb.priority = loginInfo.getPriority();
1198                        pb.addExtension(capabilities.getCaps());
1199
1200                        try
1201                        {
1202                                send(pb.build());
1203                        } catch (InstantiationException e)
1204                        {
1205                                e.printStackTrace();
1206                        }
1207                        for(Iterator j = backend.getListeners(nu.fw.jeti.events.StatusChangeListener.class);j.hasNext();)
1208                        {
1209                                ((nu.fw.jeti.events.StatusChangeListener)j.next()).ownPresenceChanged(show,status);
1210                        }
1211                }
1212        }
1213       
1214        public void changeStatus(int show,String status)
1215        {
1216                this.show = show;
1217                this.status = status;
1218                sendStatus();
1219        }
1220
1221        public static class DummySSLSocketFactory extends SSLSocketFactory
1222        {
1223                private SSLSocketFactory factory;
1224               
1225                public DummySSLSocketFactory()
1226                {
1227                        try
1228                        {
1229                                SSLContext sslcontent = SSLContext.getInstance("TLS");
1230                                sslcontent.init(null, // KeyManager not required
1231                                                                new TrustManager[] {new DummyTrustManager()},
1232                                                                new java.security.SecureRandom());
1233                                factory = sslcontent.getSocketFactory();
1234                        }
1235                        catch (NoSuchAlgorithmException e)
1236                        {
1237                                e.printStackTrace();
1238                        }
1239                        catch (KeyManagementException e)
1240                        {
1241                                e.printStackTrace();
1242                        }
1243                }
1244       
1245                public Socket createSocket(Socket socket, String s, int i,boolean flag) throws IOException
1246                {
1247                        return factory.createSocket(socket, s, i, flag);
1248                }
1249
1250                public Socket createSocket(InetAddress inaddr, int i,InetAddress inaddr2, int j) throws IOException
1251                {
1252                        return factory.createSocket(inaddr, i, inaddr2, j);
1253                }
1254
1255                public Socket createSocket(InetAddress inaddr, int i) throws IOException
1256                {
1257                        return factory.createSocket(inaddr, i);
1258                }
1259
1260                public Socket createSocket(String s, int i, InetAddress inaddr, int j)  throws IOException
1261                {
1262                        return factory.createSocket(s, i, inaddr, j);
1263                }
1264
1265                public Socket createSocket(String s, int i)     throws IOException
1266                {
1267                 
1268                  /**
1269               * register a callback for handshaking completion event
1270               */
1271                       
1272                        Socket so = factory.createSocket(s, i);
1273                ((SSLSocket)so).addHandshakeCompletedListener(new HandshakeCompletedListener()
1274                                {
1275                                        public void handshakeCompleted(HandshakeCompletedEvent event)
1276                                        {
1277                                                System.out.println("** Handshake finished! **");
1278                                                //System.out.println("\t CipherSuite:" + event.getCipherSuite());
1279                                                //System.out.println("\t SessionId " + event.getSession());
1280                                                //System.out.println("\t PeerHost " + event.getSession().getPeerHost());
1281                                        }
1282                                }
1283                );
1284               
1285                return so;
1286                }
1287               
1288                public String[] getDefaultCipherSuites()
1289                {
1290                        return factory.getSupportedCipherSuites();
1291                }
1292
1293                public String[] getSupportedCipherSuites()
1294                {
1295                        return factory.getSupportedCipherSuites();
1296                }
1297        }
1298
1299        /**
1300         * Trust manager which accepts certificates without any validation
1301         * except date validation.
1302         */
1303        private static class DummyTrustManager implements X509TrustManager
1304        {
1305
1306                public void checkClientTrusted(X509Certificate[] chain, String authType) {      }
1307
1308                public void checkServerTrusted(X509Certificate[] chain, String authType)
1309                {
1310                        try
1311                        {
1312                                chain[0].checkValidity();
1313                        }
1314                        catch (CertificateExpiredException e){}
1315                        catch (CertificateNotYetValidException e){}
1316                }
1317
1318                public X509Certificate[] getAcceptedIssuers()
1319                {
1320                        return new X509Certificate[0];
1321                }
1322        }
1323 }
1324
1325
1326/*
1327 * Overrides for emacs
1328 * Local variables:
1329 * tab-width: 4
1330 * End:
1331 */
Note: See TracBrowser for help on using the repository browser.