1 import java.awt.*; 2 import java.awt.event.*; 3 import java.awt.image.ImageObserver ; 4 import java.io.*; 5 import javax.swing.*; 6 import javax.accessibility.Accessible ; 7 import java.util.*; 8 import org.jivesoftware.smack.*; 9 import org.jivesoftware.smack.packet.*; 10 import org.jivesoftware.smack.util.StringUtils; 11 import org.jivesoftware.smackx.muc.*; 12 import org.jivesoftware.smackx.packet.MUCUser; 13 import whisper.*; 14 15 16 public final class SecureChannelPanel extends JPanel implements Accessible , ImageObserver , MenuContainer, Serializable, WMP{ 17 18 private static final int GAP=10; 19 private final Vector occupants=new Vector(); 21 final JPanel wherePanel=new JPanel(new GridLayout(2,1,0,0)); 22 final JLabel whereLbl=new JLabel(); 23 final JLabel statLbl=new JLabel(Lang.gs("chat encrypted"),Icons.PADLOCK,SwingConstants.LEFT); 24 25 final JSplitPane splitpane=new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,false); 26 final JEditorPane chatTextPane=new JEditorPane(); 27 final JScrollPane chatTextPaneSP=new JScrollPane(chatTextPane); 28 final JScrollBar sb=chatTextPaneSP.getVerticalScrollBar(); 29 final JList occupantsList=new JList(occupants); 30 final JScrollPane occupantsSP=new JScrollPane(occupantsList); 31 32 final JPanel bottomPanel=new JPanel(new BorderLayout(0,0)); 33 final Box writePanel=Box.createHorizontalBox(); 34 final JTextField text=new JTextField(20); 35 final JButton sendBtn=new JButton(Lang.gs("send"),Icons.SEND); 36 37 final JPanel btnPanel=new JPanel(new FlowLayout(FlowLayout.RIGHT,0,0)); 38 final JButton closeBtn=new JButton(Lang.gs("close"),Icons.CLOSE); 39 40 final BtnClick click=new BtnClick(); 41 JPanel thisPanel=this; 42 43 private final String Me=Lang.gs("me"); 44 private String ChatText=""; 45 private String myNickname; 46 private String HEADER=GUI.getHeader(); 47 48 public boolean amProviding=false; private SessionKey encryptChannelKey=null; 50 private SessionKey decryptChannelKey=null; 51 private String providerJID=null; private Chat chat=null; private PublicKey channelPublicKey=null; private boolean hasJoined=false; private SessionKey myKey=null; private Hashtable occupantsChats=null; private Hashtable jid2nick=null; private boolean autoallow=false; 59 private boolean autoallowcontacts=true; 60 private final ThreadGroup threads=new ThreadGroup ("Secure Channel Threads"); 61 public final MessageListener messageListener=new MessageListener(); 62 private Hashtable listeners=null; private final int SK_USE_LIMIT=17; 64 private int sk_use=0; 65 66 private SecureChannelPanel(){ 67 super(new BorderLayout(GAP,GAP)); 68 wherePanel.add(whereLbl); 69 wherePanel.add(statLbl); 70 add(wherePanel,BorderLayout.NORTH); 71 chatTextPane.setEditable(false); 73 chatTextPane.setMinimumSize(new Dimension(0,0)); 74 chatTextPane.setContentType("text/html"); 75 java.net.URL base=null; 76 try{ 77 base=(new File(".")).toURL(); 78 ((javax.swing.text.html.HTMLDocument )chatTextPane.getDocument()).setBase(base); 79 } 80 catch (Exception e){ 81 } 83 GUI.setScrollBars(chatTextPaneSP); 84 GUI.setScrollBars(occupantsSP); 86 occupantsList.setPrototypeCellValue("abcdefghij"); 87 occupantsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 88 occupantsList.setLayoutOrientation(JList.VERTICAL); 89 occupantsList.setVisibleRowCount(8); 90 occupantsList.setMinimumSize(occupantsList.getPreferredSize()); 91 if(WhisperIM.UserPref.getProperty("muc_list_location").equals("left")){ 93 splitpane.setResizeWeight(0.0); 94 splitpane.setRightComponent(chatTextPaneSP); 95 splitpane.setLeftComponent(occupantsSP); 96 } 98 else{ 99 splitpane.setResizeWeight(1.0); 100 splitpane.setRightComponent(occupantsSP); 101 splitpane.setLeftComponent(chatTextPaneSP); 102 } 104 add(splitpane,BorderLayout.CENTER); 105 sendBtn.setDefaultCapable(true); 107 sendBtn.addActionListener(click); 108 sendBtn.setMnemonic(Lang.s2k("send_mn")); 109 sendBtn.setToolTipText(Lang.gs("chat send_tt")); 110 writePanel.add(text); 111 writePanel.add(writePanel.createGlue()); 112 writePanel.add(Box.createHorizontalStrut(GAP)); 113 writePanel.add(sendBtn); 114 115 closeBtn.addActionListener(click); 116 closeBtn.setMnemonic(Lang.s2k("leave_mn")); 117 closeBtn.setToolTipText(Lang.gs("leave_tt")); 118 btnPanel.add(closeBtn); 119 120 bottomPanel.add(writePanel,BorderLayout.NORTH); 121 bottomPanel.add(Box.createVerticalStrut(GAP),BorderLayout.CENTER); 122 bottomPanel.add(btnPanel,BorderLayout.SOUTH); 123 add(bottomPanel,BorderLayout.SOUTH); 124 125 getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(WhisperIM.HELP_KEY,0),"help"); getActionMap().put("help",new HelpAction(this,"schannel.html#using")); 128 text.getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0),"send_messge"); 130 text.getActionMap().put("send_messge", new EnterAction()); 131 } 132 133 134 public SecureChannelPanel(String jid,String providername,String nick){ 135 this(); 136 providerJID=jid; 137 myNickname=nick; 138 whereLbl.setText(Lang.gs("provided by")+" "+jid+" "+providername); 139 chat=new Chat(WhisperIM.MainWindow.Conn,providerJID); 140 chat.addMessageListener(messageListener); 141 myKey=new SessionKey(WhisperIM.SR); 142 } 143 144 145 public SecureChannelPanel(String nick, boolean autoallowcontacts, boolean autoallow){ 146 this(); 147 amProviding=true; 148 myNickname=nick; 149 this.autoallowcontacts=autoallowcontacts; 150 this.autoallow=autoallow; 151 whereLbl.setText(Lang.gs("you are providing")); 152 encryptChannelKey=new SessionKey(WhisperIM.SR); 153 decryptChannelKey=Channel.createPair(encryptChannelKey,WhisperIM.SR); 154 occupantsChats=new Hashtable(); 155 jid2nick=new Hashtable(); 156 listeners=new Hashtable(); 157 } 158 160 161 public void go(){ 162 if(amProviding){ 163 announce(Lang.gs("opening channel")); 164 occupants.add(myNickname); 165 occupantsList.repaint(); 166 sendBtn.requestFocusInWindow(); 167 return; 168 } 169 sendBtn.setEnabled(false); 170 text.setEnabled(false); 171 announce(Lang.gs("joining channel")); 172 (new JoinChannelThread()).start(); 173 } 174 175 176 public void doSend(){ 177 if(text.getText().equals("")){ 178 text.requestFocusInWindow(); 179 return; 180 } 181 if(amProviding){ 182 (new SendMessageThread(myNickname+":"+text.getText())).start(); 183 } 184 else{ 185 (new SendMessageThread(text.getText())).start(); 186 } 187 text.setText(""); 188 text.requestFocusInWindow(); 189 } 190 191 192 private void print(String txt){ 193 ChatText=ChatText+txt+"<br>"; 194 chatTextPane.setText(HEADER+ChatText+GUI.FOOTER); 195 sb.setValue(sb.getMaximum()); 196 } 197 198 199 private void announce(String text){ 200 print("<font color='"+MUCPanel.announceColour+"'>"+GUI.getTime()+" "+text+"</font>"); 201 } 202 203 204 private void announceFromThread(final String text){ 205 javax.swing.SwingUtilities.invokeLater(new Runnable (){ 206 public void run(){ 207 print("<font color='"+MUCPanel.announceColour+"'>"+GUI.getTime()+" "+text+"</font>"); 208 } 209 }); 210 } 211 212 213 private void updateListFromThread(){ 214 SwingUtilities.invokeLater(new Runnable (){ 215 public void run(){ 216 occupantsList.repaint(); 217 } 218 }); 219 } 220 221 227 public void allow(String JID, String requestednickname, String threadID,String time){ 228 synchronized(occupantsChats){ 230 if(occupantsChats.get(JID)!=null){ 231 String nick=(String ) jid2nick.get(JID); 236 if(nick!=null){ 237 MessageListener ml=(MessageListener) listeners.get(JID); 238 if(ml!=null){ 239 WhisperIM.MainWindow.Conn.removePacketListener(ml); 240 } 241 listeners.remove(JID); 242 occupants.remove((String ) jid2nick.get(JID)); 243 (new SendMessageThread(nick+":"+Channel.LEAVING)).start(); 244 jid2nick.remove(JID); 245 } 246 occupantsChats.remove(JID); 248 return; 249 } 250 } 251 Object o=WhisperIM.MainWindow.Contacts.get("jabber"+JID); 252 if(autoallow || (o!=null && autoallowcontacts)){ 253 approved(JID,requestednickname,threadID,time); 254 return; 255 } 256 String who=""; 258 if(o!=null){ 259 ContactListItem cli=(ContactListItem) o; 260 who=" ("+cli.toString()+")"; 261 } 262 if(JOptionPane.showConfirmDialog(this,JID+who+"\r\n"+Lang.gs("is requesting join"),Lang.gs("secure channel"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE)==JOptionPane.YES_OPTION){ 263 approved(JID,requestednickname,threadID,GUI.getTime()); 264 } 265 } 266 267 private synchronized void approved(String JID, String requestednickname, String threadID,String time){ 268 String nick=requestednickname.trim().toLowerCase(); 270 Chat c; 271 nick=nick.replace(' ','_'); 273 nick=nick.replace(':','_'); 274 Random r=new Random(); 275 while(occupants.contains(nick)){ 276 nick=nick+r.nextInt(99); 277 } 278 if(threadID!=null){ 279 c=new Chat(WhisperIM.MainWindow.Conn,JID,threadID); 280 } 281 else{ 282 c=new Chat(WhisperIM.MainWindow.Conn,JID); 283 } 284 MessageListener ml=new MessageListener(); 285 listeners.put(JID,ml); 286 c.addMessageListener(ml); 287 (new SendJoinedThread(c,nick)).start(); 289 occupantsChats.put(JID,c); 290 announce(nick+": "+JID); 292 (new SendMessageThread(nick+":"+Channel.ENTERED)).start(); 294 occupants.add(nick); 295 occupantsList.repaint(); 296 jid2nick.put(JID,nick); 297 } 298 299 public void doClose(){ 300 threads.interrupt(); 301 if(!amProviding){ 302 try{ 303 WhisperIM.MainWindow.Conn.removePacketListener(messageListener); 304 (new SendMessageThread(Channel.LEAVING)).start(); 305 } 306 catch(Exception e){ 307 } 310 } 311 else{ 312 try{ 313 Enumeration mls=listeners.elements(); 314 MessageListener ml; 315 while(mls.hasMoreElements()){ 316 ml=(MessageListener)mls.nextElement(); 317 WhisperIM.MainWindow.Conn.removePacketListener(ml); 318 } 319 Enumeration e=occupantsChats.elements(); 320 Chat c; 321 Channel channel=new Channel(new whisper.Message(myNickname+":"+Channel.LEAVING,encryptChannelKey,WhisperIM.KEYPAIR,WhisperIM.SR)); 322 while(e.hasMoreElements()){ 323 c=(Chat) e.nextElement(); 324 if(WhisperIM.MainWindow.Conn.isConnected()){ 325 c.sendMessage(channel.getText()); 326 } 327 } 328 } 329 catch(Exception e2){ 330 } 333 } 334 if(decryptChannelKey!=null){ 335 decryptChannelKey.wipe(); 336 decryptChannelKey=null; 337 } 338 text.setText(""); 339 chatTextPane.setText("<html></html>"); 340 ChatText=""; 341 ChatText=null; 342 WhisperIM.MainWindow.secureChannelPanel=null; 343 WhisperIM.MainWindow.chatPane.remove(thisPanel); 344 } 345 346 public void goneOffline(){ 348 threads.interrupt(); 349 announce(" * "+Lang.gs("disconnected")+" *"); 350 sendBtn.setEnabled(false); 351 text.setEnabled(false); 352 } 353 354 public void goneOnline(){ 355 } 357 358 public void doFocus(){ 359 sendBtn.requestFocusInWindow(); 360 } 361 362 public JButton getDefaultButton(){ 363 if(sendBtn.isEnabled()){ 364 return sendBtn; 365 } 366 return closeBtn; 367 } 368 369 371 final class BtnClick implements ActionListener{ 372 public void actionPerformed(ActionEvent ae){ 373 String b=ae.getActionCommand(); 375 if(b.equals(closeBtn.getText())){ 377 doClose(); 378 return; 379 } 380 if(b.equals(sendBtn.getText())){ 381 if(text.getText().equals("")){ 382 text.requestFocus(); 383 return; 384 } 385 doSend(); 386 return; 387 } 388 } 389 } 390 391 final class MessageListener implements PacketListener{ 392 public void processPacket(Packet packet){ 393 final org.jivesoftware.smack.packet.Message m; 394 try{ 396 m=(org.jivesoftware.smack.packet.Message) packet; 397 } 398 catch(ClassCastException cce){ 399 cce.printStackTrace(); 401 return; 402 } 403 String from=StringUtils.parseBareAddress(m.getFrom()); 404 if(!amProviding){ 405 if(!from.equals(providerJID)){ 406 return; } 408 } 409 Channel c; 410 try{ 411 c=new Channel(m.getBody()); 412 } 413 catch(WhisperException we){ 414 return; } 417 if(!amProviding){ 418 (new ProcessMessageThread(c)).start(); 419 return; 420 } 421 if(c.getChannelMsgType()==Channel.JOIN_REQUEST){ 422 (new JoinRequestThread(c,StringUtils.parseBareAddress(m.getFrom()),m.getThread())).start(); 423 return; 424 } 425 if(c.getChannelMsgType()==Channel.MESSAGE){ 426 String nick=(String ) jid2nick.get(from); 427 if(nick==null){return;} (new RelayMessageThread(c.getMessage(),nick,from)).start(); 429 return; 430 } 431 } 435 436 438 public void incoming(org.jivesoftware.smack.packet.Message m){ 439 if(!amProviding){ 440 return; 441 } 442 Channel c; 443 try{ 444 c=new Channel(m.getBody()); 445 } 446 catch(WhisperException we){ 447 return; } 450 if(c.getChannelMsgType()==Channel.JOIN_REQUEST){ 451 (new JoinRequestThread(c,StringUtils.parseBareAddress(m.getFrom()),m.getThread())).start(); 452 } 453 } 454 } 455 456 final class EnterAction extends AbstractAction{ 457 public void actionPerformed(ActionEvent e) { 458 if(text.getText().equals("")){ 459 text.requestFocus(); 460 return; 461 } 462 doSend(); 463 } 464 } 465 final class JoinChannelThread extends Thread { 467 public JoinChannelThread(){ 468 super(threads,"Join Channel Thread"); 469 setDaemon(true); 470 setPriority(Thread.MIN_PRIORITY); 471 } 472 public void run(){ 473 try{ 474 PublicKey pk=(PublicKey)WhisperIM.MainWindow.Keys.get("jabber"+providerJID); 476 if(isInterrupted()){return;} 477 if(pk==null){ 478 try{ 479 pk=WhisperIM.MainWindow.getKey("jabber",providerJID); 480 } 481 catch(Exception e1){ 482 announceFromThread(Lang.gs("could not open channel")+Lang.gs("no public key")+e1.getMessage()); 483 return; 484 } 485 } 486 if(pk==null){ 487 announceFromThread(Lang.gs("could not open channel")+Lang.gs("no public key")); 488 return; 489 } 490 if(isInterrupted()){return;} 491 channelPublicKey=pk; 492 org.jivesoftware.smack.packet.Message m=chat.createMessage(); 493 m.setTo(providerJID); 494 Channel c=new Channel(myNickname,channelPublicKey,myKey,WhisperIM.KEYPAIR,WhisperIM.SR); 495 myKey.wipe(); 496 myKey=null; 497 m.setBody(c.getText()); 498 if(isInterrupted()){return;} 499 try{ 500 chat.sendMessage(m); 501 } 502 catch(XMPPException xe){ 503 announceFromThread(Lang.gs("could not open channel")+xe.getMessage()); 504 return; 505 } 506 } 508 catch(Exception e){ 509 e.printStackTrace(); 510 } 511 } 512 } 513 514 final class ProcessMessageThread extends Thread { 515 private final Channel c; 516 517 public ProcessMessageThread(Channel c){ 518 super(threads,"Process Message Thread"); 519 this.c=c; 520 setDaemon(true); 521 setPriority(Thread.MIN_PRIORITY); 522 } 523 public void run(){ 524 try{ 525 whisper.Message m=c.getMessage(); 527 if(m!=null && (!m.isValid(channelPublicKey))){ 529 announceFromThread(Lang.gs("bad message received")+". "+Lang.gs("invalid signature")); 530 return; 531 } 532 if(c.getChannelMsgType()==Channel.JOINED){ 533 if(hasJoined){ 535 return; } 537 announceFromThread(Lang.gs("joining response")); 538 if(isInterrupted()){return;} 539 try{ 541 decryptChannelKey=m.getESK().decrypt(WhisperIM.KEYPAIR); 542 encryptChannelKey=Channel.createPair(decryptChannelKey,WhisperIM.SR); 543 } 544 catch(Exception e1){ 545 546 announceFromThread(Lang.gs("could not open channel")+e1.getMessage()); 547 return; 548 } 549 hasJoined=true; 551 String occlist; 552 if(isInterrupted()){return;} 553 try{ 554 occlist=m.decrypt(decryptChannelKey); 555 } 556 catch(Exception e2){ 557 m.wipe(); 558 m=null; 559 announceFromThread(Lang.gs("could not open channel")+e2.getMessage()); 560 return; 561 } 562 m.wipe(); 563 m=null; 564 String occs[]=occlist.split(","); 565 if(occs==null || occs.length<2){ 566 announceFromThread(Lang.gs("could not open channel")); 567 return; 568 } 569 myNickname=occs[0]; 570 occupants.clear(); 571 for(int i=0;i<occs.length;i++){ 572 if(!occupants.contains(occs[i])){ 573 occupants.add(occs[i]); 574 } 575 } 576 updateListFromThread(); 577 if(isInterrupted()){return;} 578 announceFromThread(Lang.gs("joined as")+myNickname); 579 SwingUtilities.invokeLater(new Runnable (){ 580 public void run(){ 581 sendBtn.setEnabled(true); 582 text.setEnabled(true); 583 text.requestFocusInWindow(); 584 } 585 }); 586 return; 588 } if(c.getChannelMsgType()==Channel.NEW_SESSION_KEY){ 590 synchronized(decryptChannelKey){ 592 try{ 593 SessionKey newChannelKey=c.getNewSessionKey(decryptChannelKey); 594 decryptChannelKey.wipe(); 595 synchronized(encryptChannelKey){ 596 encryptChannelKey.wipe(); 597 encryptChannelKey=Channel.createPair(newChannelKey,WhisperIM.SR); 598 } 599 decryptChannelKey=newChannelKey; 600 } 601 catch(Exception e4){ 602 announceFromThread("New Session Key: "+Lang.gs("bad message received")+". "+Lang.gs("could not decrypt")+e4.getMessage()); 605 return; 606 } 607 608 } 609 610 return; 612 } 613 if(c.getChannelMsgType()!=Channel.MESSAGE){return;} 614 if(isInterrupted()){return;} 615 if(decryptChannelKey==null){ 616 return; 618 } 619 String plaintext; 620 synchronized(decryptChannelKey){ 621 try{ 622 plaintext=m.decrypt(decryptChannelKey); 623 } 624 catch(Exception e5){ 625 announceFromThread(Lang.gs("bad message received")+". "+Lang.gs("could not decrypt")+". "+e5.getMessage()); 626 decryptChannelKey.notify(); 627 return; 629 } 630 decryptChannelKey.notify(); 631 } 632 final String time=GUI.getTime(m); 633 m.wipe(); 634 m=null; 635 final String parts[]=plaintext.split(":",2); 636 plaintext=null; 637 if(parts.length!=2){ 638 announceFromThread(Lang.gs("bad message received")); 639 System.err.println("message format not name:message "); 640 return; 641 } 642 if(isInterrupted()){return;} 643 if(parts[1].equals(Channel.ENTERED)){ 645 if(!occupants.contains(parts[0])){ 646 occupants.add(parts[0]); 647 updateListFromThread(); 648 } 649 announceFromThread(parts[0]+" "+Lang.gs("has entered room")); 650 parts[0]=null; 651 parts[1]=null; 652 return; 653 } 654 if(parts[1].equals(Channel.LEAVING)){ 655 occupants.remove(parts[0]); 656 updateListFromThread(); 657 announceFromThread(parts[0]+" "+Lang.gs("has left room")); 658 parts[0]=null; 659 parts[1]=null; 660 return; 661 } 662 final String colour; 663 if(parts[0].toLowerCase().equals(myNickname)){ 664 colour=MUCPanel.myColour; 665 } 666 else{ 667 colour=MUCPanel.theirColours[0]; 668 } 669 SwingUtilities.invokeLater(new Runnable (){ 670 public void run(){ 671 print("<font color='"+colour+"'>"+time+" "+parts[0]+"</font>"+" "+parts[1]); 672 } 673 }); 674 } 675 catch(Exception e){ 676 e.printStackTrace(); 677 } 678 } 679 } 680 681 final class JoinRequestThread extends Thread { 682 private final Channel c; 683 private final String fromJID; 684 private final String threadID; 685 public JoinRequestThread(Channel c,String fromJID,String threadID){ 686 super(threads,"Join Request Thread"); 687 this.c=c; 688 this.fromJID=fromJID; 689 this.threadID=threadID; 690 setDaemon(true); 691 setPriority(Thread.MIN_PRIORITY); 692 } 693 public void run(){ 694 try{ 695 PublicKey pk=(PublicKey)WhisperIM.MainWindow.Keys.get("jabber"+fromJID); 698 if(isInterrupted()){return;} 699 if(pk==null){ 700 try{ 701 pk=WhisperIM.MainWindow.getKey("jabber",fromJID); 702 } 703 catch(Exception e1){ 704 announceFromThread(fromJID+" "+Lang.gs("attempted to join")+". "+Lang.gs("no public key")+e1.getMessage()); 705 return; 706 } 707 } 708 if(pk==null){ 709 announceFromThread(fromJID+" "+Lang.gs("attempted to join")+". "+Lang.gs("no public key")); 710 return; 711 } 712 if(isInterrupted()){return;} 713 final String requestedNick; 714 SessionKey tmpKey; 715 final whisper.Message m=c.getMessage(); 716 if(!m.isValid(pk)){ 717 announceFromThread(fromJID+" "+Lang.gs("attempted to join")+" ."+Lang.gs("invalid signature")); 718 return; 719 } 720 if(isInterrupted()){return;} 721 if(m.getESK()==null){ 722 announceFromThread(fromJID+" "+Lang.gs("attempted to join")+" ."+Lang.gs("could not decrypt")); 723 return; 724 } 725 if(isInterrupted()){return;} 726 try{ 727 tmpKey=m.getESK().decrypt(WhisperIM.KEYPAIR); 728 } 729 catch(Exception e2){ 730 announceFromThread(fromJID+" "+Lang.gs("attempted to join")+". "+Lang.gs("could not decrypt")+" ."+e2.getMessage()); 731 return; 732 } 733 if(isInterrupted()){return;} 734 try{ 735 requestedNick=m.decrypt(tmpKey); 736 } 737 catch(Exception e3){ 738 announceFromThread(fromJID+" "+Lang.gs("attempted to join")+". "+Lang.gs("could not decrypt")+" ."+e3.getMessage()); 739 return; 740 } 741 tmpKey.wipe(); 742 tmpKey=null; 743 SwingUtilities.invokeLater(new Runnable (){ 744 public void run(){ 745 allow(fromJID,requestedNick,threadID,GUI.getTime(m)); 746 } 747 }); 748 m.wipe(); 749 } 750 catch(Exception e){ 751 e.printStackTrace(); 752 } 753 } 754 } 755 756 final class BroadCastThread extends Thread { 757 private final whisper.Message m; 758 759 public BroadCastThread(whisper.Message m){ 760 super(threads,"BroadCast Thread"); 761 this.m=m; 762 setDaemon(true); 763 setPriority(Thread.MIN_PRIORITY); 764 } 765 766 public void run(){ 767 Enumeration e=occupantsChats.elements(); 768 Chat c; 769 while(e.hasMoreElements()){ 770 if(isInterrupted()){return;} 771 c=(Chat) e.nextElement(); 772 try{ 773 c.sendMessage((new Channel(m)).getText()); 774 } 775 catch(Exception e1){ 776 announceFromThread(Lang.gs("message failed")+" "+e1.getMessage()); 777 } 778 } 779 } 780 } 781 782 final class SendMessageThread extends Thread { 783 private final String text; 784 785 public SendMessageThread(String text){ 786 super(threads,"Send Message Thread"); 787 this.text=text; 788 setDaemon(true); 789 setPriority(Thread.MIN_PRIORITY); 790 } 791 792 public void run(){ 793 try{ 794 if(amProviding){ 795 sk_use++; 796 } 797 whisper.Message m; 798 synchronized(encryptChannelKey){ 799 m=new whisper.Message(text,encryptChannelKey,WhisperIM.KEYPAIR,WhisperIM.SR); 800 encryptChannelKey.notify(); 801 } 802 if(isInterrupted()){return;} 803 if(amProviding){ 804 (new BroadCastThread(m)).start(); 805 final String parts[]=text.split(":",2); 806 if(parts.length!=2){ 807 announceFromThread(text); 808 return; 809 } 810 final String colour; 811 if(parts[0].equals(myNickname)){ 812 colour=MUCPanel.myColour; 813 } 814 else{ 815 colour=MUCPanel.theirColours[0]; 816 } 817 if(parts[1].equals(Channel.ENTERED)){ 818 announceFromThread(parts[0]+" "+Lang.gs("has entered room")); 819 parts[0]=null; 820 parts[1]=null; 821 return; 822 } 823 if(parts[1].equals(Channel.LEAVING)){ 824 announceFromThread(parts[0]+" "+Lang.gs("has left room")); 825 parts[0]=null; 826 parts[1]=null; 827 return; 828 } 829 SwingUtilities.invokeLater(new Runnable (){ 830 public void run(){ 831 print("<font color='"+colour+"'>"+GUI.getTime()+" "+parts[0]+"</font>"+" "+parts[1]); 832 } 833 }); 834 parts[0]=null; 835 parts[1]=null; 836 return; 837 } 838 else{ 839 chat.sendMessage( (new Channel(m)).getText()); 840 if(text.equals(Channel.LEAVING)){ 841 chat=null; 842 if(encryptChannelKey!=null){ 843 encryptChannelKey.wipe(); 844 encryptChannelKey=null; 845 } 846 } 847 } 848 } 849 catch(Exception e){ 850 announceFromThread(Lang.gs("message failed")+" "+e.getMessage()); 851 } 852 } 853 } 854 855 856 final class RelayMessageThread extends Thread { 857 private final whisper.Message m; 858 private final String nick; 859 private final String JID; 860 861 public RelayMessageThread(whisper.Message m, String nick, String JID){ 862 super(threads,"Relay Message Thread"); 863 this.m=m; 864 this.nick=nick; 865 this.JID=JID; 866 setDaemon(true); 867 setPriority(Thread.MIN_PRIORITY); 868 } 869 870 public void run(){ 871 try{ 872 PublicKey pk=(PublicKey)WhisperIM.MainWindow.Keys.get("jabber"+JID); 874 if(isInterrupted()){return;} 875 if(pk==null){ announceFromThread(Lang.gs("error")+" "+Lang.gs("no public key")); 877 return; 878 } 879 if(!m.isValid(pk)){ 880 announceFromThread(Lang.gs("message failed")+" "+Lang.gs("invalid signature")); 881 return; 882 } 883 if(isInterrupted()){return;} 884 String plaintext; 885 synchronized(decryptChannelKey){ 886 try{ 887 plaintext=m.decrypt(decryptChannelKey); 888 } 889 catch(Exception e1){ 890 decryptChannelKey.notify(); 891 announceFromThread(Lang.gs("message failed")+" "+Lang.gs("could not decrypt")+" "+e1.getMessage()); 892 return; 893 } 894 decryptChannelKey.notify(); 895 } 896 if(isInterrupted()){return;} 897 String transmitplaintext=nick+":"+plaintext; 898 899 if(amProviding){ 900 sk_use++; 901 if(sk_use>=SK_USE_LIMIT){ 902 sk_use=1; 903 (new SendNewSessionKeyThread()).run(); } 906 } 907 synchronized(encryptChannelKey){ 908 whisper.Message mout=new whisper.Message(transmitplaintext,encryptChannelKey,WhisperIM.KEYPAIR,WhisperIM.SR); 909 transmitplaintext=null; 910 if(isInterrupted()){return;} 911 (new BroadCastThread(mout)).start(); 912 encryptChannelKey.notify(); 913 } 914 if(plaintext.equals(Channel.LEAVING)){ 915 occupants.remove(nick); 916 WhisperIM.MainWindow.Conn.removePacketListener((MessageListener)listeners.get(JID) ); 917 jid2nick.remove(JID); 918 occupantsChats.remove(JID); 919 updateListFromThread(); 920 announceFromThread(nick+" "+Lang.gs("has left room")); 921 plaintext=null; 922 return; 923 } 924 final String finalplaintext=plaintext; 925 SwingUtilities.invokeLater(new Runnable (){ 926 public void run(){ 927 print("<font color='"+MUCPanel.theirColours[0]+"'>"+GUI.getTime(m)+" "+nick+" </font>"+" "+finalplaintext); 928 } 929 }); 930 m.wipe(); 931 plaintext=null; 932 } 933 catch(Exception e){ 934 announceFromThread(Lang.gs("error")+" "+e.getMessage()); 935 } 936 } 937 } 938 939 final class SendJoinedThread extends Thread { 940 private final String nick; 941 private final Chat chat; 942 943 public SendJoinedThread(Chat chat,String nick){ 944 super(threads,"Send Joined Thread"); 945 this.nick=nick; 946 this.chat=chat; 947 setDaemon(true); 948 setPriority(Thread.MIN_PRIORITY); 949 } 950 951 public void run(){ 952 try{ 953 String list=nick; 954 String item; 955 for(int i=0;i<occupants.size();i++){ 956 item=(String ) occupants.elementAt(i); 957 if(item.equals(nick)){ 958 } 960 else{ 961 list=list+","+item; 962 } 963 } 964 PublicKey pk=(PublicKey)WhisperIM.MainWindow.Keys.get("jabber"+chat.getParticipant()); 965 if(isInterrupted()){return;} 966 if(pk==null){ announceFromThread(Lang.gs("error")+" "+Lang.gs("no public key")); 968 return; 969 } 970 Channel c; 971 synchronized(encryptChannelKey){ 972 c=new Channel(WhisperIM.KEYPAIR,list,pk,encryptChannelKey,WhisperIM.SR); 973 encryptChannelKey.notify(); 974 } 975 if(isInterrupted()){return;} 976 chat.sendMessage(c.getText()); 977 } 978 catch(Exception e){ 979 announceFromThread(Lang.gs("error")+" "+e.getMessage()); 980 } 981 } 982 } 983 984 986 final class SendNewSessionKeyThread extends Thread { 987 988 public SendNewSessionKeyThread(){ 989 super(threads,"Send New SessionKey Thread"); 990 setDaemon(true); 991 setPriority(Thread.MIN_PRIORITY); 992 } 993 994 public void run(){ 995 try{ 997 synchronized(encryptChannelKey){ 998 SessionKey newChannelKey=new SessionKey(WhisperIM.SR); 999 Enumeration e=occupantsChats.elements(); 1000 Chat c; 1001 Channel channel; 1002 try{ 1003 channel=new Channel(encryptChannelKey,newChannelKey,WhisperIM.SR); 1004 } 1005 catch(whisper.CryptoException ce){ 1006 announceFromThread("new session key:"+Lang.gs("message failed")+" "+ce.getMessage()); 1007 return; 1008 } 1009 while(e.hasMoreElements()){ 1010 if(isInterrupted()){return;} 1011 c=(Chat) e.nextElement(); 1012 try{ 1013 c.sendMessage(channel.getText()); 1014 } 1015 catch(Exception e1){ 1016 announceFromThread("new session key:"+Lang.gs("message failed")+" "+e1.getMessage()); 1017 } 1018 } 1019 encryptChannelKey.wipe(); 1020 encryptChannelKey=newChannelKey; 1021 newChannelKey=null; 1022 synchronized(decryptChannelKey){ 1023 decryptChannelKey.wipe(); 1024 decryptChannelKey=Channel.createPair(encryptChannelKey,WhisperIM.SR); 1025 } 1027 } 1029 } catch (Exception e){ 1031 e.printStackTrace(); 1032 } 1033 } 1035 } 1036} 1037 | Popular Tags |