source: branches/2.2/jabberit_messenger/java_source/src/nu/fw/jeti/backend/Connect.java @ 3102

Revision 3102, 35.0 KB checked in by amuller, 14 years ago (diff)

Ticket #986 - Efetuado merge para o Branch 2.2( atualizacao do modulo)

  • 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                                socket = null; //clear socket reference
936                                this.connectionID = connectionID;
937                                // TODO remove lowercase if filetransfer bug fixed
938                                output.send(new InfoQuery(null,"get",new IQAuth(loginInfo.getUsername().toLowerCase(),null,null)));
939                        }
940                }
941               
942        }
943
944        public void authenticate(IQAuth iqAuth)
945        {
946                if(!abort)
947                {
948                        authenticationId = "Jeti_Auth_" + new java.util.Date().getTime();
949                       
950                        if(iqAuth.hasDigest())
951                        {
952                                MessageDigest sha = null;
953                                try {
954                                  sha = MessageDigest.getInstance("SHA");
955                                } catch (Exception ex){
956                                  Log.error(I18N.gettext("main.loginstatus.Could_not_login_with_SHA"));
957                                  // TODO remove lowercase if filetransfer bug fixed
958                                  output.send(new InfoQuery(null,"set",authenticationId,new IQAuth(loginInfo.getUsername().toLowerCase(),loginInfo.getPassword() ,loginInfo.getResource())));
959                                  return;
960                                }
961
962                                sha.update(connectionID.getBytes());
963                                String digest = Utils.toString(sha.digest(loginInfo.getPassword().getBytes()));
964                                IQAuthBuilder iqab =  new IQAuthBuilder();
965                                iqab.digest = digest;
966                                // TODO remove lowercase if filetransfer bug fixed
967                                iqab.username = loginInfo.getUsername().toLowerCase();
968                                iqab.resource = loginInfo.getResource();
969                                output.send(new InfoQuery(null,"set",authenticationId,(IQExtension)iqab.build()));
970                        }
971                        else
972                        {
973                                if(!loginInfo.isSSl())
974                                {
975                                        int option = JOptionPane.showConfirmDialog(null,
976                                                        I18N.gettext("main.loginstatus.Sending_password_as_plain_text_over_an_unencrypted_connection,_continue?"),"Plain text",JOptionPane.YES_NO_OPTION);
977                                        if (option == JOptionPane.NO_OPTION)
978                                        {
979                                                sendLoginError("Sending password in plain not allowed");
980                                                return;
981                                        }
982                                }
983//                              TODO remove lowercase if filetransfer bug fixed
984                                output.send(new InfoQuery(null,"set",authenticationId,new IQAuth(loginInfo.getUsername().toLowerCase(),loginInfo.getPassword() ,loginInfo.getResource())));
985                        }
986                }
987        }
988
989        public void authenticated(InfoQuery infoQuery)
990        {
991                if(!abort)
992                {
993                        if(infoQuery.getType().equals("error"))
994                        {
995                                if(infoQuery.getErrorCode() == 401)
996                                {
997                                        sendUnauthorized();             
998                                }
999                                else
1000                                {
1001                                        sendLoginError(I18N.gettext("main.loginstatus.Not_logged_in_because") + " " + infoQuery.getErrorDescription());
1002                                }       
1003                                return;
1004                        }
1005                        //TODO remove lowercase if filetransfer bug fixed
1006                        JID jid = new JID(loginInfo.getUsername().toLowerCase(),loginInfo.getServer() ,loginInfo.getResource());
1007                        authenticated(jid);
1008                }
1009        }
1010
1011        public void authenticated(JID jid)
1012        {
1013                myJID = jid;
1014                iqTimerQueue.clear();//remove iqs from previous connections
1015                jabberHandler.changePacketReceiver(new Jabber(backend,capabilities,discovery,iqTimerQueue));
1016                authenticated = true;
1017        reconnecting = false;
1018                output.setAuthenticated();
1019
1020                //TODO increase timeout
1021                getItems(new JID(loginInfo.getServer()), new DiscoveryListener()
1022                {
1023                        public void discoveryItemResult(JID jid, DiscoveryItem item)
1024                        {
1025                                //cache disco items for this server
1026                                if (item.hasItems())
1027                                {
1028                                        for(Iterator i = item.getItems();i.hasNext();)
1029                                        {
1030                                                DiscoveryItem di = (DiscoveryItem)i.next();
1031                                                backend.getInfo(di.getJID(),null);
1032                                        }
1033                                }
1034                        }
1035                        public void discoveryInfoResult(JID jid, DiscoveryInfo info) {}
1036                });
1037                output.send(new InfoQuery("get",new IQPrivate(new JetiPrivateExtension())));
1038                output.send(new InfoQuery("get",new IQXRoster()));
1039                if(show == Presence.NONE)
1040                {
1041                        show = Presence.AVAILABLE;
1042                }
1043                latestConnected = System.currentTimeMillis();
1044               
1045        }
1046       
1047        public void connected()
1048        {
1049                sendStatus();
1050                send(new InfoQuery("get",new IQPrivate(new JetiPrivateRosterExtension())));
1051                for( Iterator j = backend.getListeners(nu.fw.jeti.events.StatusChangeListener.class) ; j.hasNext(); )
1052                {
1053                        //online
1054                        ((nu.fw.jeti.events.StatusChangeListener)j.next()).connectionChanged(true);
1055                }
1056        }
1057
1058        public void receivePackets(Packet packet)
1059        {
1060                if (packet instanceof StreamError) streamError((StreamError)packet);
1061                else if(authenticationId.equals(packet.getID())) authenticated((InfoQuery)packet);
1062                else if(packet instanceof InfoQuery)
1063                {
1064                    IQExtension extension = packet.getIQExtension();
1065                        if(extension instanceof IQAuth)
1066                        {
1067                                if(((InfoQuery)packet).getType().equals("error"))
1068                                {
1069                                        sendLoginError(packet.getErrorDescription());
1070                                }
1071                                else authenticate((IQAuth) extension);
1072                        }
1073                }
1074        }
1075
1076        public void inputDeath()
1077        {
1078                try
1079                {
1080                        if( socket != null ) socket.close();
1081                }
1082                catch (IOException e)
1083                {
1084                        e.printStackTrace();
1085                }
1086               
1087                if((authenticated || reconnecting))
1088                {
1089                        authenticated = false;
1090            if (reconnecting) {
1091                try {
1092                    Thread.sleep(10000);
1093                } catch (InterruptedException e) {};
1094            }
1095            reconnecting = true;
1096                        output.disconnect(true);
1097                        for(Iterator j = backend.getListeners(nu.fw.jeti.events.StatusChangeListener.class);j.hasNext();)
1098                        {
1099                                //offline
1100                                ((nu.fw.jeti.events.StatusChangeListener)j.next()).connectionChanged(false);
1101                        }
1102                }
1103               
1104        }
1105
1106        public void streamError(StreamError error)
1107        {
1108                //only when logging in
1109                if(authenticated)
1110                {
1111                        authenticated = false;
1112                        output.disconnect(true);
1113                        for(Iterator j = backend.getListeners(nu.fw.jeti.events.StatusChangeListener.class);j.hasNext();)
1114                        {
1115                                //offline
1116                                ((nu.fw.jeti.events.StatusChangeListener)j.next()).connectionChanged(false);
1117                        }
1118                }
1119                sendLoginError(error.getErrorDescription());
1120        }
1121
1122        public void outputDeath()
1123        {
1124                authenticated = false;
1125                for(Iterator j = backend.getListeners(nu.fw.jeti.events.StatusChangeListener.class);j.hasNext();)
1126                {
1127                        //offline
1128                        ((nu.fw.jeti.events.StatusChangeListener)j.next()).connectionChanged(false);
1129                }
1130        }
1131
1132        public static JID getMyJID()
1133        {
1134            return myJID;
1135        }
1136
1137        public boolean getOnline()
1138        {
1139            return authenticated;
1140        }
1141
1142        public void disconnect()
1143        {
1144                if( authenticated )
1145                {
1146                        send(new Presence(myJID, "unavailable"));
1147                        authenticated = false;
1148                        output.disconnect(true);
1149                }
1150                output = null;
1151                for(Iterator j = backend.getListeners(nu.fw.jeti.events.StatusChangeListener.class);j.hasNext();)
1152                {
1153                        //offline
1154                        ((nu.fw.jeti.events.StatusChangeListener)j.next()).connectionChanged(false);
1155                }
1156        }
1157
1158        public void exit()
1159        {
1160                if(authenticated)
1161                {
1162                        send(new nu.fw.jeti.jabber.elements.Presence(myJID,"unavailable"));
1163                        authenticated = false;
1164                        output.disconnect(true);
1165                }
1166                output = null;
1167                for(Iterator j = backend.getListeners(nu.fw.jeti.events.StatusChangeListener.class);j.hasNext();)
1168                {//exit
1169                        ((nu.fw.jeti.events.StatusChangeListener)j.next()).exit();
1170                }
1171        }
1172
1173        public void send(Packet packet)
1174        {
1175                if(authenticated) output.send(packet);
1176                else nu.fw.jeti.util.Log.notSend(packet.toString());
1177        }
1178       
1179        public void sendWhileConnecting(Packet packet)
1180        {
1181                output.send(packet);
1182        }
1183
1184        public String getAccountInfo()
1185        {
1186                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()});
1187        }
1188
1189        public void sendStatus()
1190        {
1191                if( authenticated )
1192                {
1193                        PresenceBuilder pb = new PresenceBuilder();
1194                        pb.show = show;
1195                        pb.status = status;
1196                        pb.priority = loginInfo.getPriority();
1197                        pb.addExtension(capabilities.getCaps());
1198
1199                        try
1200                        {
1201                                send(pb.build());
1202                        } catch (InstantiationException e)
1203                        {
1204                                e.printStackTrace();
1205                        }
1206                        for(Iterator j = backend.getListeners(nu.fw.jeti.events.StatusChangeListener.class);j.hasNext();)
1207                        {
1208                                ((nu.fw.jeti.events.StatusChangeListener)j.next()).ownPresenceChanged(show,status);
1209                        }
1210                }
1211        }
1212       
1213        public void changeStatus(int show,String status)
1214        {
1215                this.show = show;
1216                this.status = status;
1217                sendStatus();
1218        }
1219
1220        public static class DummySSLSocketFactory extends SSLSocketFactory
1221        {
1222                private SSLSocketFactory factory;
1223               
1224                public DummySSLSocketFactory()
1225                {
1226                        try
1227                        {
1228                                SSLContext sslcontent = SSLContext.getInstance("TLS");
1229                                sslcontent.init(null, // KeyManager not required
1230                                                                new TrustManager[] {new DummyTrustManager()},
1231                                                                new java.security.SecureRandom());
1232                                factory = sslcontent.getSocketFactory();
1233                        }
1234                        catch (NoSuchAlgorithmException e)
1235                        {
1236                                e.printStackTrace();
1237                        }
1238                        catch (KeyManagementException e)
1239                        {
1240                                e.printStackTrace();
1241                        }
1242                }
1243       
1244                public Socket createSocket(Socket socket, String s, int i,boolean flag) throws IOException
1245                {
1246                        return factory.createSocket(socket, s, i, flag);
1247                }
1248
1249                public Socket createSocket(InetAddress inaddr, int i,InetAddress inaddr2, int j) throws IOException
1250                {
1251                        return factory.createSocket(inaddr, i, inaddr2, j);
1252                }
1253
1254                public Socket createSocket(InetAddress inaddr, int i) throws IOException
1255                {
1256                        return factory.createSocket(inaddr, i);
1257                }
1258
1259                public Socket createSocket(String s, int i, InetAddress inaddr, int j)  throws IOException
1260                {
1261                        return factory.createSocket(s, i, inaddr, j);
1262                }
1263
1264                public Socket createSocket(String s, int i)     throws IOException
1265                {
1266                 
1267                  /**
1268               * register a callback for handshaking completion event
1269               */
1270                       
1271                        Socket so = factory.createSocket(s, i);
1272                ((SSLSocket)so).addHandshakeCompletedListener(new HandshakeCompletedListener()
1273                                {
1274                                        public void handshakeCompleted(HandshakeCompletedEvent event)
1275                                        {
1276                                                System.out.println("** Handshake finished! **");
1277                                                //System.out.println("\t CipherSuite:" + event.getCipherSuite());
1278                                                //System.out.println("\t SessionId " + event.getSession());
1279                                                //System.out.println("\t PeerHost " + event.getSession().getPeerHost());
1280                                        }
1281                                }
1282                );
1283               
1284                return so;
1285                }
1286               
1287                public String[] getDefaultCipherSuites()
1288                {
1289                        return factory.getSupportedCipherSuites();
1290                }
1291
1292                public String[] getSupportedCipherSuites()
1293                {
1294                        return factory.getSupportedCipherSuites();
1295                }
1296        }
1297
1298        /**
1299         * Trust manager which accepts certificates without any validation
1300         * except date validation.
1301         */
1302        private static class DummyTrustManager implements X509TrustManager
1303        {
1304
1305                public void checkClientTrusted(X509Certificate[] chain, String authType) {      }
1306
1307                public void checkServerTrusted(X509Certificate[] chain, String authType)
1308                {
1309                        try
1310                        {
1311                                chain[0].checkValidity();
1312                        }
1313                        catch (CertificateExpiredException e){}
1314                        catch (CertificateNotYetValidException e){}
1315                }
1316
1317                public X509Certificate[] getAcceptedIssuers()
1318                {
1319                        return new X509Certificate[0];
1320                }
1321        }
1322 }
1323
1324
1325/*
1326 * Overrides for emacs
1327 * Local variables:
1328 * tab-width: 4
1329 * End:
1330 */
Note: See TracBrowser for help on using the repository browser.