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 whisper.*; 12 13 14 15 public final class ChatPanel extends JPanel implements Accessible , ImageObserver , MenuContainer, Serializable, WMP{ 16 17 private static final int GAP=10; 18 19 final JPanel withPanel=new JPanel(new GridLayout(2,1,GAP,GAP)); 20 final JLabel withLbl=new JLabel(); 21 final JLabel statLbl=new JLabel(Lang.gs("chat encrypted"),Icons.PADLOCK,SwingConstants.LEFT); 22 23 final JEditorPane chatTextPane=new JEditorPane(); 24 final JScrollPane chatTextPaneSP=new JScrollPane(chatTextPane); 25 final JScrollBar sb=chatTextPaneSP.getVerticalScrollBar(); 26 27 final JPanel bottomPanel=new JPanel(new GridLayout(2,1,GAP,GAP)); 28 final JPanel writePanel=new JPanel(new BorderLayout(GAP,GAP)); 29 final JTextArea text=new JTextArea(1,25); 30 final JScrollPane textSP=new JScrollPane(text); 31 final JButton sendBtn=new JButton(Lang.gs("send"),Icons.SEND); 32 33 final JPanel btnPanel=new JPanel(new FlowLayout(FlowLayout.RIGHT,0,0)); 34 final JButton saveBtn=new JButton(Lang.gs("save"),Icons.SAVE); 35 final JButton closeBtn=new JButton(Lang.gs("close"),Icons.CLOSE); 36 37 final BtnClick click=new BtnClick(); 38 39 final JPanel thisPanel=this; 40 41 private String ChatText=""; 42 private final String Me=Lang.gs("me"); 43 private Chat chat=null; 44 private boolean isEncrypting=true; 45 private SessionKey mySK=null; 46 private SessionKey theirSK=null; 47 private PublicKey theirKey=null; 48 private int messageCount=0; 49 private final int SK_USE_LIMIT=17; 50 public final String Name; 51 private String ID; 52 53 private final String HEADER=GUI.getHeader(); 54 55 public ChatPanel(String name, String id, Chat chat, boolean isencrypting, String date){ 56 super(new BorderLayout(GAP,GAP)); 57 this.chat=chat; 58 this.isEncrypting=isencrypting; 59 this.Name=name; 60 this.ID=id; 61 62 withLbl.setText(Lang.gs("chatting with")+name); 63 withLbl.setToolTipText(Lang.gs("chatting with")+id); 64 if(!isEncrypting){ 65 statLbl.setText(Lang.gs("chat not encrypted")); 66 statLbl.setIcon(Icons.WARNING); 67 statLbl.setToolTipText(Lang.gs("chat no key")); 68 } 69 else{ 70 theirKey=(PublicKey) WhisperIM.MainWindow.Keys.get("jabber"+StringUtils.parseBareAddress(id)); 71 if(theirKey==null){ 72 if(WhisperIM.MainWindow.hasNoKey("jabber",StringUtils.parseBareAddress(id))){ 74 isEncrypting=false; 75 } 76 else{ 77 try{ 78 theirKey=WhisperIM.MainWindow.getKey("jabber",StringUtils.parseBareAddress(id)); 79 } 80 catch(Exception e){ 81 isEncrypting=false; 82 } 83 } 84 } 85 if(theirKey==null){ isEncrypting=false; 87 statLbl.setText(Lang.gs("chat not encrypted")); 88 statLbl.setIcon(Icons.WARNING); 89 statLbl.setToolTipText(Lang.gs("chat no key")); 90 } 91 else{ 92 mySK=new SessionKey(WhisperIM.SR); 93 } 94 } 95 withPanel.add(withLbl); 96 withPanel.add(statLbl); 97 add(withPanel,BorderLayout.NORTH); 98 99 chatTextPane.setEditable(false); 101 chatTextPane.setContentType("text/html"); 102 java.net.URL base=null; 103 try{ 104 base=(new File(".")).toURL(); 105 ((javax.swing.text.html.HTMLDocument )chatTextPane.getDocument()).setBase(base); 106 } 107 catch (Exception e){ 108 } 110 announce(Lang.gs("chat started"),date); 111 GUI.setScrollBars(chatTextPaneSP); 112 add(chatTextPaneSP,BorderLayout.CENTER); 113 text.setLineWrap(true); 115 text.setWrapStyleWord(true); 116 textSP.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 117 if(WhisperIM.isMac){ 118 textSP.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 119 } 120 else{ 121 textSP.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); 122 } 123 124 sendBtn.addActionListener(click); 128 sendBtn.setMnemonic(Lang.s2k("send_mn")); 129 sendBtn.setToolTipText(Lang.gs("chat send_tt")); 130 writePanel.add(textSP,BorderLayout.CENTER); 131 writePanel.add(sendBtn,BorderLayout.EAST); 132 133 saveBtn.addActionListener(click); 134 saveBtn.setToolTipText(Lang.gs("chat save_tt")); 135 btnPanel.add(saveBtn); 136 btnPanel.add(Box.createHorizontalStrut(GAP)); 137 138 closeBtn.addActionListener(click); 139 closeBtn.setMnemonic(Lang.s2k("close_mn")); 140 closeBtn.setToolTipText(Lang.gs("chat close_tt")); 141 btnPanel.add(closeBtn); 142 143 bottomPanel.add(writePanel); 144 bottomPanel.add(btnPanel); 145 add(bottomPanel,BorderLayout.SOUTH); 146 147 sendBtn.setDefaultCapable(true); 148 chat.addMessageListener(new newMsgListener()); 149 getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(WhisperIM.HELP_KEY,0),"help"); getActionMap().put("help",new HelpAction(this,"messages.html#chat")); 152 text.getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0),"send_messge"); 154 text.getActionMap().put("send_messge", new EnterAction()); 155 saveBtn.setVisible(false); } 157 158 159 public void process(String msg, String time){ 160 if(!isEncrypting){ 161 ChatText=ChatText+"<font color='"+MUCPanel.theirColours[0]+"'>"+time+" "+Name+"</font> "+Convert.text(msg)+"<br>"; 162 chatTextPane.setText(HEADER+ChatText+GUI.FOOTER); 163 sb.setValue(sb.getMaximum()); 164 return; 165 } 166 (new ProcessEncryptedMessage(msg)).start(); 167 } 168 169 public void doSend(){ 170 if(!isEncrypting){ 171 try{ 172 chat.sendMessage(text.getText()); 173 } 174 catch(XMPPException xe){ 175 GUI.showError(this,"error","error",null,xe); 176 return; 177 } 178 ChatText=ChatText+"<font color='"+MUCPanel.myColour+"'>"+GUI.getTime()+" "+Me+"</font> "+Convert.text(text.getText())+"<br>"; 179 text.setText(""); 180 text.requestFocus(); 181 chatTextPane.setText(HEADER+ChatText+GUI.FOOTER); 182 sb.setValue(sb.getMaximum()); 183 return; 184 } 185 text.setEditable(false); 186 sendBtn.setEnabled(false); 187 (new SendEncryptedMessage()).start(); 188 } 189 190 public void doSentEncryptedMessage(){ 191 ChatText=ChatText+"<font color='"+MUCPanel.myColour+"'>"+GUI.getTime()+" "+Me+"</font> "+Convert.text(text.getText())+"<br>"; 192 text.setText(""); 193 sendBtn.setEnabled(true); 194 text.setEditable(true); 195 text.requestFocus(); 196 chatTextPane.setText(HEADER+ChatText+GUI.FOOTER); 197 sb.setValue(sb.getMaximum()); 198 } 199 200 public void doClose(){ 201 text.setText(""); 202 chatTextPane.setText("<html></html>"); 203 ChatText=""; 204 ChatText=null; 205 WhisperIM.MainWindow.Chats.remove("jabber"+StringUtils.parseBareAddress(ID)); 206 WhisperIM.MainWindow.chatPane.remove(thisPanel); 207 chat=null; 208 } 209 210 public void announce(String txt, String time){ 211 ChatText=ChatText+"<font color='"+MUCPanel.announceColour+"'>"+time+" "+txt+"</font><br>"; 212 chatTextPane.setText(HEADER+ChatText+GUI.FOOTER); 213 sb.setValue(sb.getMaximum()); 214 } 215 216 public void goneOffline(){ 217 sendBtn.setEnabled(false); 218 announce("* "+Lang.gs("disconnected")+" *",GUI.getTime()); 219 if(isEncrypting){ 220 mySK.wipe(); 221 } 222 } 223 224 public void goneOnline(){ 225 chat=new Chat(WhisperIM.MainWindow.Conn,ID); 226 if(isEncrypting){ 227 mySK=new SessionKey(WhisperIM.SR); 228 messageCount=0; 229 } 230 announce("* "+Lang.gs("reconnected")+" *",GUI.getTime()); 231 chat.addMessageListener(new newMsgListener()); 232 sendBtn.setEnabled(true); 233 } 234 235 public void doFocus(){ 236 text.requestFocusInWindow(); 237 } 238 239 public JButton getDefaultButton(){ 240 return sendBtn; 241 } 242 243 final class BtnClick implements ActionListener{ 244 public void actionPerformed(ActionEvent ae){ 245 String b=ae.getActionCommand(); 247 if(b.equals(closeBtn.getText())){ 249 doClose(); 250 return; 251 } 252 if(b.equals(sendBtn.getText())){ 253 if(text.getText().equals("")){ 254 text.requestFocus(); 255 return; 256 } 257 doSend(); 258 return; 259 } 260 } 261 } 262 263 final class newMsgListener implements PacketListener{ 264 public void processPacket(Packet packet){ 265 org.jivesoftware.smack.packet.Message m; 266 try{ 267 m=(org.jivesoftware.smack.packet.Message) packet; 268 } 269 catch(Exception e){ 270 return; 271 } 272 final String t=m.getBody(); 273 final String time=GUI.getTime(m); 274 javax.swing.SwingUtilities.invokeLater(new Runnable (){ 275 public void run(){ 276 process(t,time); 277 } 278 }); 279 } 280 } 281 282 283 final class ProcessEncryptedMessage extends Thread { 284 final String msg; 285 286 public ProcessEncryptedMessage(String m){ 287 super("Process Encrypted Message"); 288 setDaemon(true); 289 setPriority(Thread.MIN_PRIORITY); 290 this.msg=m; 291 } 292 293 public void run(){ 294 try{ 295 final whisper.Message wm=new whisper.Message(msg); 296 if(!wm.isValid(theirKey)){ 297 javax.swing.SwingUtilities.invokeLater(new Runnable (){ 298 public void run(){ 299 announce(Lang.gs("bad message received")+" - "+Lang.gs("invalid signature"),GUI.getTime()); 300 } 301 }); 302 return; 303 } 304 EncryptedSessionKey esk=wm.getESK(); 305 if(theirSK==null && esk==null){ 306 try{ 307 sleep(3000); if(theirSK==null){ 309 return; 310 } 311 } 312 catch(Exception se){ 313 return; 314 } 315 } 316 if(esk!=null){ 317 theirSK=null; 318 while(WhisperIM.KEYPAIR==null){ 319 try{ 320 sleep(3000); 321 } 322 catch(InterruptedException ie){ 323 return; 324 } 325 } 326 theirSK=esk.decrypt(WhisperIM.KEYPAIR); 327 } 328 final String plaintext=wm.decrypt(theirSK); 329 javax.swing.SwingUtilities.invokeLater(new Runnable (){ 330 public void run(){ 331 ChatText=ChatText+"<font color='"+MUCPanel.theirColours[0]+"'>"+GUI.getTime(wm)+" "+Name+"</font> "+Convert.text(plaintext)+"<br>"; 332 chatTextPane.setText(HEADER+ChatText+GUI.FOOTER); 333 sb.setValue(sb.getMaximum()); 334 } 335 }); 336 } 337 catch (Exception e){ 338 javax.swing.SwingUtilities.invokeLater(new Runnable (){ 339 public void run(){ 340 announce(Lang.gs("bad message received")+" - "+Lang.gs("could not decrypt"),GUI.getTime()); 341 } 342 }); 343 System.err.println("Debug: ProcessEncryptedMessage thread - "+e.getMessage()); 344 return; 345 } 346 } 347 } 348 349 final class SendEncryptedMessage extends Thread { 350 351 public SendEncryptedMessage(){ 352 super("Send Encrypted Message"); 353 setDaemon(true); 354 setPriority(Thread.MIN_PRIORITY); 355 } 356 357 public void run(){ 358 try{ 359 if(messageCount==SK_USE_LIMIT){ 360 mySK=new SessionKey(WhisperIM.SR); 361 messageCount=0; 362 } 363 whisper.Message wm; 364 while(WhisperIM.KEYPAIR==null){ 365 try{ 366 sleep(3000); 367 } 368 catch(InterruptedException ie){ 369 return; 370 } 371 } 372 if(messageCount==0){ 373 wm=new whisper.Message(text.getText(),theirKey,mySK,WhisperIM.KEYPAIR,WhisperIM.SR); 374 } 375 else{ 376 wm=new whisper.Message(text.getText(),mySK,WhisperIM.KEYPAIR,WhisperIM.SR); 377 } 378 messageCount++; 379 chat.sendMessage(wm.getText()); 380 javax.swing.SwingUtilities.invokeLater(new Runnable (){ 381 public void run(){ 382 doSentEncryptedMessage(); 383 } 384 }); 385 } 386 catch(final Exception e){ 387 e.printStackTrace(); 388 javax.swing.SwingUtilities.invokeLater(new Runnable (){ 389 public void run(){ 390 GUI.showError(thisPanel,"error","error",e.getMessage()); 391 } 392 }); 393 } 394 } 395 } 396 397 final class EnterAction extends AbstractAction{ 398 public void actionPerformed(ActionEvent e) { 399 if(text.getText().equals("")){ 400 text.requestFocus(); 401 return; 402 } 403 doSend(); 404 } 405 } 406 } | Popular Tags |