001 /*
002 * Copyright (C) 2003 Adam Olsen
003 * This program is free software; you can redistribute it and/or modify
004 * it under the terms of the GNU General Public License as published by
005 * the Free Software Foundation; either version 1, or (at your option)
006 * any later version.
007 * This program is distributed in the hope that it will be useful,
008 * but WITHOUT ANY WARRANTY; without even the implied warranty of
009 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
010 * GNU General Public License for more details.
011 * You should have received a copy of the GNU General Public License
012 * along with this program; if not, write to the Free Software
013 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
014 */
015 package com.valhalla.jbother.menus;
016
017 import java.awt.*;
018 import java.awt.event.*;
019 import java.net.URL;
020 import java.io.*;
021 import java.util.*;
022
023 import javax.swing.*;
024
025 import org.jivesoftware.smack.*;
026 import org.jivesoftware.smackx.*;
027 import org.jivesoftware.smackx.packet.*;
028 import org.jivesoftware.smack.filter.PacketFilter;
029 import org.jivesoftware.smack.filter.OrFilter;
030 import org.jivesoftware.smack.filter.PacketTypeFilter;
031 import org.jivesoftware.smack.packet.*;
032 import net.infonode.tabbedpanel.*;
033 import com.valhalla.jbother.groupchat.*;
034 import com.valhalla.gui.*;
035 import com.valhalla.jbother.*;
036 import com.valhalla.jbother.BuddyList;
037 import com.valhalla.jbother.jabber.*;
038 import com.valhalla.jbother.jabber.smack.*;
039
040 /**
041 * The menu that pops up when you right click on a user in your roster
042 *
043 *@author Adam Olsen
044 *@author Andrey Zakirov
045 *@created June 23, 2005
046 *@version 1.1
047 */
048 public class BuddyListPopupMenu extends JPopupMenu implements UserChooserListener {
049 /**
050 * Description of the Field
051 */
052 protected ResourceBundle resources = ResourceBundle.getBundle("JBotherBundle", Locale.getDefault());
053 /**
054 * Description of the Field
055 */
056 protected JMenuItem removeBuddyItem = new JMenuItem(resources.getString("removeFromRoster"));
057 /**
058 * Description of the Field
059 */
060 protected JMenuItem modifyBuddyItem = new JMenuItem(resources.getString("modify"));
061 /**
062 * Description of the Field
063 */
064 protected JMenu resourceMenu = new JMenu(resources.getString("resources"));
065 /**
066 * Description of the Field
067 */
068 protected JMenu authMenu = new JMenu(resources.getString("authorization"));
069
070 /**
071 * Description of the Field
072 */
073 protected JMenu infoMenu = new JMenu(resources.getString("informationMenu"));
074 /**
075 * Description of the Field
076 */
077 protected JMenu editMenu = new JMenu(resources.getString("editMenu"));
078
079 /**
080 * Description of the Field
081 */
082 protected JMenuItem requestSubscription = new JMenuItem(resources.getString("requestNotification"));
083 /**
084 * Description of the Field
085 */
086 protected JMenuItem resendSubscription = new JMenuItem(resources.getString("resendNotification"));
087 /**
088 * Description of the Field
089 */
090 protected JMenuItem removeSubscription = new JMenuItem(resources.getString("removeNotification"));
091
092 /**
093 * Description of the Field
094 */
095 protected JMenuItem chatItem = new JMenuItem(resources.getString("openChatDialog"));
096 /**
097 * Description of the Field
098 */
099 protected JMenuItem messageItem = new JMenuItem(resources.getString("messageWindow"));
100 /**
101 * Description of the Field
102 */
103 protected JMenuItem logItem = new JMenuItem(resources.getString("viewLog"));
104 /**
105 * Description of the Field
106 */
107 protected JMenuItem infoItem = new JMenuItem(resources.getString("getInfo"));
108 /**
109 * Description of the Field
110 */
111 protected JMenuItem blockItem = new JMenuItem(resources.getString("blockUser"));
112
113 /**
114 * Description of the Field
115 */
116 protected JMenuItem bindPubKeyItem = new JMenuItem(resources.getString("gnupgBindPublicKey"));
117 /**
118 * Description of the Field
119 */
120 protected JMenuItem unbindPubKeyItem = new JMenuItem(resources.getString("gnupgUnbindPublicKey"));
121
122 protected JMenu misc = new JMenu(resources.getString("misc"));
123 protected JMenu invite = new JMenu(resources.getString("inviteToMuc"));
124 protected JMenuItem noItem = new JMenuItem(resources.getString("noMucs"));
125 protected JMenu rosterExchange = new JMenu(resources.getString("sendRosterItems"));
126 protected JMenuItem individualItems = new JMenuItem(resources.getString("individualItems"));
127 protected JMenuItem entireRoster = new JMenuItem(resources.getString("entireRoster"));
128
129 /**
130 * Description of the Field
131 */
132 protected BuddyStatus buddy;
133 private JTree tree;
134 /**
135 * Description of the Field
136 */
137 protected JMenuItem sendFileItem = new JMenuItem(resources.getString("sendFile"));
138 protected JMenu sendFileMenu = new JMenu(resources.getString("sendFile"));
139
140
141 /**
142 * Creates the menu
143 */
144 public BuddyListPopupMenu() {
145 MenuActionListener listener = new MenuActionListener();
146
147 noItem.setEnabled(false);
148 infoItem.addActionListener(listener);
149 removeBuddyItem.addActionListener(listener);
150 chatItem.addActionListener(listener);
151 messageItem.addActionListener(listener);
152 modifyBuddyItem.addActionListener(listener);
153 requestSubscription.addActionListener(listener);
154 logItem.addActionListener(listener);
155 resendSubscription.addActionListener(listener);
156 removeSubscription.addActionListener(listener);
157 blockItem.addActionListener(listener);
158 sendFileItem.addActionListener(listener);
159 bindPubKeyItem.addActionListener(listener);
160 unbindPubKeyItem.addActionListener(listener);
161 entireRoster.addActionListener(listener);
162 individualItems.addActionListener(listener);
163
164 authMenu.add(requestSubscription);
165 authMenu.add(resendSubscription);
166 authMenu.add(removeSubscription);
167 authMenu.add(blockItem);
168
169 infoMenu.add(infoItem);
170 infoMenu.add(logItem);
171
172 editMenu.add(modifyBuddyItem);
173 editMenu.add(removeBuddyItem);
174
175 misc.add(invite);
176 misc.add(rosterExchange);
177
178 add(chatItem);
179 add(messageItem);
180 addSeparator();
181 add(infoMenu);
182 add(editMenu);
183 addSeparator();
184 add(resourceMenu);
185 add(authMenu);
186 add(misc);
187 addSeparator();
188 add(sendFileItem);
189 }
190
191 /**
192 * Gets the from attribute of the BuddyListPopupMenu object
193 *
194 *@return The from value
195 */
196 protected String getFrom() {
197 if (BuddyList.getInstance().checkConnection()) {
198 return BuddyList.getInstance().getConnection().getUser();
199 }
200
201 return "";
202 }
203
204
205 /**
206 * Requests subscription to a user
207 *
208 *@param type the type of subscription to send
209 */
210 private void subscriptionHandler(Presence.Type type) {
211 Presence presence = new Presence(type);
212
213 presence.setTo(buddy.getUser());
214 if (BuddyList.getInstance().checkConnection()) {
215 BuddyList.getInstance().getConnection().sendPacket(presence);
216 } else {
217 BuddyList.getInstance().connectionError();
218 }
219 }
220
221
222 /**
223 * Listens for different items to get clicked on in the popup menu
224 *
225 *@author Adam Olsen
226 *@created June 23, 2005
227 *@version 1.0
228 */
229 class MenuActionListener implements ActionListener {
230 /**
231 * Description of the Method
232 *
233 *@param e Description of the Parameter
234 */
235 public void actionPerformed(ActionEvent e) {
236 if (e.getSource() == removeBuddyItem) {
237 removeBuddyHandler();
238 } else if (e.getSource() == chatItem) {
239 BuddyList.getInstance().getBuddyListTree().initiateConversation(buddy);
240 } else if (e.getSource() == messageItem) {
241 MessagePanel panel = new MessagePanel();
242 panel.setBuddy(buddy);
243
244 if (!(buddy instanceof MUCBuddyStatus)) {
245 String to = buddy.getUser();
246 if (buddy.size() > 0) {
247 to += "/" + buddy.getHighestResource();
248 }
249 panel.setTo(to);
250 } else {
251 panel.setTo(buddy.getUser());
252 }
253
254 panel.setFrom(getFrom());
255 MessageDelegator.getInstance().showPanel(panel);
256 MessageDelegator.getInstance().frontFrame(panel);
257 panel.getSubjectField().grabFocus();
258 } else if (e.getSource() == modifyBuddyItem) {
259 modifyBuddyHandler();
260 } else if (e.getSource() == requestSubscription) {
261 subscriptionHandler(Presence.Type.SUBSCRIBE);
262 } else if (e.getSource() == removeSubscription) {
263 subscriptionHandler(Presence.Type.UNSUBSCRIBED);
264 } else if (e.getSource() == resendSubscription) {
265 subscriptionHandler(Presence.Type.SUBSCRIBED);
266 } else if (e.getSource() == infoItem) {
267 if (!(buddy instanceof MUCBuddyStatus)) {
268 new InformationViewerDialog(buddy.getAddress());
269 } else {
270 new InformationViewerDialog(buddy.getUser());
271 }
272 } else if (e.getSource() == logItem) {
273 new LogViewerDialog(buddy.getConversation(), buddy.getUser());
274 } else if (e.getSource() == blockItem) {
275 blockHandler();
276 } else if (e.getSource() == sendFileItem) {
277 sendFileHandler();
278 } else if (e.getSource() == bindPubKeyItem) {
279 bindPubKeyHandler();
280 } else if (e.getSource() == unbindPubKeyItem) {
281 unbindPubKeyHandler();
282 }
283 else if (e.getSource() == individualItems)
284 {
285 UserChooser chooser = new UserChooser(BuddyList.getInstance().getContainerFrame(),
286 resources.getString("sendRosterItems"), resources.getString("selectSendItems"), true);
287 chooser.addListener(BuddyListPopupMenu.this);
288 chooser.setVisible(true);
289 }
290 else if(e.getSource() == entireRoster)
291 {
292 int result = JOptionPane.showConfirmDialog(BuddyList.getInstance().getContainerFrame(),
293 resources.getString("sureSendEntireRoster"), resources.getString("sendRosterItems"),
294 JOptionPane.YES_NO_OPTION);
295
296 if(result != JOptionPane.YES_OPTION) return;
297
298 RosterExchangeManager manager = ConnectorThread.getInstance().getExchangeManager();
299 Roster roster = BuddyList.getInstance().getConnection().getRoster();
300 manager.send(roster, buddy.getUser());
301 }
302 }
303 }
304
305 public void usersChosen(UserChooser.Item[] items)
306 {
307 Message message = new Message(buddy.getUser());
308 RosterExchange r = new RosterExchange();
309
310 message.addExtension(r);
311
312 Roster roster = BuddyList.getInstance().getConnection().getRoster();
313 for(int i = 0; i < items.length; i++)
314 {
315 RosterEntry entry = roster.getEntry(items[i].getJID());
316 r.addRosterEntry(entry);
317 }
318
319 BuddyList.getInstance().getConnection().sendPacket(message);
320 }
321
322
323 /**
324 * Blocks the user
325 */
326 protected void blockHandler() {
327 // just adds the user to the blocked list in buddy list
328 File blockedFile = new File(JBother.profileDir + File.separator + "blocked");
329 BuddyList.getInstance().getBlockedUsers().put(buddy.getUser(), "blocked");
330
331 // and then writes all of them to the blocked users file
332 try {
333 FileWriter fw = new FileWriter(blockedFile);
334 PrintWriter out = new PrintWriter(fw);
335
336 Iterator i = BuddyList.getInstance().getBlockedUsers().keySet().iterator();
337 while (i.hasNext()) {
338 out.println((String) i.next());
339 }
340
341 fw.close();
342 } catch (IOException ex) {
343 Standard.warningMessage(null, resources.getString("blockUser"),
344 resources.getString("problemWritingBlockedFile"));
345 return;
346 }
347 BuddyList.getInstance().getBuddyListTree().removeBuddy(buddy, buddy.getGroup(), true);
348
349 Standard.noticeMessage(null, resources.getString("blockUser"), resources.getString("userHasBeenBlocked"));
350 }
351
352
353 /**
354 * Opens the AddBuddyDialog to modify a buddy
355 */
356 protected void modifyBuddyHandler() {
357 AddBuddyDialog buddyDialog = new AddBuddyDialog();
358 buddyDialog.setBuddy(buddy.getRosterEntry());
359 buddyDialog.setVisible(true);
360 }
361
362
363 /**
364 * Confirms buddy removal, and then removes the buddy
365 */
366 protected void removeBuddyHandler() {
367 if (!BuddyList.getInstance().checkConnection()) {
368 BuddyList.getInstance().connectionError();
369 return;
370 }
371
372 int result = 1;
373
374 result = JOptionPane.showConfirmDialog(null, resources.getString("sureRemoveContact"), resources.getString("removeFromRoster"),
375 JOptionPane.YES_NO_OPTION);
376
377 if (result != 0) {
378 return;
379 }
380
381 RosterEntry entry = buddy.getRosterEntry();
382 buddy.setRemoved(true);
383 String gp = buddy.getGroup();
384
385 if (entry != null) {
386 com.valhalla.Logger.debug("Remove entry user: " + entry.getUser());
387 BuddyList.getInstance().getBuddyListTree().removeBuddy(buddy, gp, true);
388
389 try {
390 BuddyList.getInstance().getConnection().getRoster().removeEntry(entry);
391 }
392 catch(XMPPException ex) { }
393
394 RosterPacket packet = new RosterPacket();
395 packet.setType(IQ.Type.SET);
396 RosterPacket.Item item = new RosterPacket.Item(entry.getUser(), entry.getName());
397 item.setItemType(RosterPacket.ItemType.REMOVE);
398 packet.addRosterItem(item);
399
400 // if this buddy is a transport, unregister from it
401 if(entry.getUser().indexOf("@") == -1 )
402 {
403 Registration r = new Registration();
404 r.setTo(entry.getUser());
405 r.setFrom(BuddyList.getInstance().getConnection().getUser());
406 r.setType(IQ.Type.SET);
407
408 HashMap map = new HashMap();
409 map.put("remove", "");
410 r.setAttributes(map);
411 BuddyList.getInstance().getConnection().sendPacket(r);
412 }
413 BuddyList.getInstance().getConnection().sendPacket(packet);
414
415 } else {
416 BuddyList.getInstance().getBuddyListTree().removeBuddy(buddy, gp, true);
417 }
418 }
419
420
421 /**
422 * Updates the resources menu
423 */
424 private void updateResourceMenu() {
425 ResourceActionListener listener = new ResourceActionListener(buddy);
426 SendFileActionListener sendListener = new SendFileActionListener(buddy);
427 resourceMenu.removeAll();
428 sendFileMenu.removeAll();
429 Set keys = buddy.keySet();
430
431 int fileItem = getComponentIndex(sendFileItem);
432 int menu = getComponentIndex(sendFileMenu);
433
434 if(buddy.size() <= 1 && menu > -1)
435 {
436 remove(menu);
437 insert(sendFileItem, menu);
438 }
439 else if(buddy.size() > 1 && fileItem > -1)
440 {
441 remove(fileItem);
442 insert(sendFileMenu, fileItem);
443 }
444
445 Iterator i = keys.iterator();
446 while (i.hasNext()) {
447 boolean na = false;
448 String key = (String) i.next();
449
450 if (key.equals("N/A")) {
451 na = true;
452 key = "None";
453 }
454
455 JMenuItem item = new JMenuItem(key);
456 JMenuItem item2 = new JMenuItem(key);
457
458 if (!na) {
459 Presence.Mode mode;
460 if (buddy.size() == 0) {
461 mode = null;
462 item.setForeground(Color.GRAY);
463 item2.setForeground(Color.GRAY);
464 } else {
465 mode = buddy.getPresence(key);
466 }
467
468 ImageIcon icon = StatusIconCache.getStatusIcon(mode);
469 if (icon != null) {
470 item.setIcon(icon);
471 item2.setIcon(icon);
472 }
473 item.addActionListener(listener);
474 item2.addActionListener(sendListener);
475 } else {
476 item.setEnabled(false);
477 item2.setEnabled(false);
478 }
479
480 resourceMenu.add(item);
481 if(buddy.size() > 1) sendFileMenu.add(item2);
482 }
483 }
484
485 private void updateMucMenu()
486 {
487 MUCActionListener listener = new MUCActionListener(buddy);
488 invite.removeAll();
489
490 TabFrame frame = BuddyList.getInstance().getTabFrame();
491
492 if(frame == null)
493 {
494 invite.add(noItem);
495 return;
496 }
497
498 TabbedPanel pane = frame.getTabPane();
499 for( int i = 0; i < pane.getTabCount(); i++ )
500 {
501 TabFramePanel panel = (TabFramePanel)pane.getTabAt(i).getContentComponent();
502 if( panel instanceof ChatRoomPanel )
503 {
504 JMenuItem item = new JMenuItem( ((ChatRoomPanel)panel).getRoomName() );
505 item.addActionListener(listener);
506 invite.add(item);
507 }
508 }
509 }
510
511 class MUCActionListener implements ActionListener
512 {
513 BuddyStatus buddy;
514
515 public MUCActionListener(BuddyStatus b) { this.buddy = b; }
516
517 public void actionPerformed(ActionEvent e)
518 {
519 JMenuItem item = (JMenuItem)e.getSource();
520 String room = item.getText();
521
522 TabFrame frame = BuddyList.getInstance().getTabFrame();
523 if(frame == null) return;
524
525 ChatRoomPanel window = frame.getChatPanel(room);
526 if(window == null) return;
527
528 window.usersChosen(new String[] { buddy.getUser() });
529 }
530 }
531
532 /**
533 * lets user choose the file to send and send it
534 */
535 private void sendFileHandler() {
536 new FileSendDialog(buddy.getAddress());
537 }
538
539
540 /**
541 * binds Public Key to buddy
542 */
543 private void bindPubKeyHandler() {
544 KeySelectDialog dialog = new KeySelectDialog("pub");
545 dialog.showDialog();
546 if (dialog.getID() != null) {
547 buddy.setPubKey(dialog.getID());
548 }
549 }
550
551
552 /**
553 * unbinds Public Key from buddy
554 */
555 private void unbindPubKeyHandler() {
556 buddy.setPubKey(null);
557 }
558
559
560 /**
561 * Shows the popup menu
562 *
563 *@param tree the tree to show the menu on
564 *@param x the x coordinate
565 *@param y the y coordinate
566 *@param buddy the buddy that this menu should show up on
567 */
568 public void showMenu(Component tree, int x, int y, BuddyStatus buddy) {
569 this.buddy = buddy;
570 this.tree = (JTree) tree;
571
572 updateResourceMenu();
573 updateMucMenu();
574 updateRosterMenu();
575
576 validate();
577
578 if (JBotherLoader.isGPGEnabled()) {
579 remove(unbindPubKeyItem);
580 remove(bindPubKeyItem);
581
582 if (buddy.getPubKey() != null) {
583 add(unbindPubKeyItem);
584 } else {
585 add(bindPubKeyItem);
586 }
587 }
588
589 show(tree, x, y);
590 }
591
592 private void updateRosterMenu()
593 {
594 MyExchangeListener listener = new MyExchangeListener();
595 rosterExchange.removeAll();
596 rosterExchange.add(entireRoster);
597 rosterExchange.add(individualItems);
598 rosterExchange.addSeparator();
599 Roster roster = BuddyList.getInstance().getConnection().getRoster();
600 Iterator i = roster.getGroups();
601 while(i.hasNext())
602 {
603 RosterGroup group = (RosterGroup)i.next();
604 JMenuItem item = new JMenuItem(resources.getString("sendGroup") + ": " + group.getName());
605 item.addActionListener(listener);
606 rosterExchange.add(item);
607 }
608 }
609
610 class MyExchangeListener implements ActionListener
611 {
612 public void actionPerformed(ActionEvent e)
613 {
614 Roster roster = BuddyList.getInstance().getConnection().getRoster();
615 JMenuItem item = (JMenuItem)e.getSource();
616 RosterExchangeManager manager = ConnectorThread.getInstance().getExchangeManager();
617 manager.send(roster.getGroup(item.getText().replaceAll("^" + resources.getString("sendGroup") + ": ", "")), buddy.getUser());
618 }
619 }
620
621 /**
622 * Listens for a resource to get clicked in the ResourceMenu
623 *
624 *@author synic
625 *@created June 23, 2005
626 */
627 class SendFileActionListener implements ActionListener {
628 private BuddyStatus buddy;
629
630
631 /**
632 * Constructor for the ResourceActionListener object
633 *
634 *@param buddy Description of the Parameter
635 */
636 public SendFileActionListener(BuddyStatus buddy) {
637 this.buddy = buddy;
638 }
639
640
641 /**
642 * Description of the Method
643 *
644 *@param e Description of the Parameter
645 */
646 public void actionPerformed(ActionEvent e) {
647 JMenuItem item = (JMenuItem) e.getSource();
648 new FileSendDialog(buddy.getUser() + "/" + item.getText());
649 }
650 }
651
652 /**
653 * Listens for a resource to get clicked in the ResourceMenu
654 *
655 *@author synic
656 *@created June 23, 2005
657 */
658 class ResourceActionListener implements ActionListener {
659 private BuddyStatus buddy;
660
661
662 /**
663 * Constructor for the ResourceActionListener object
664 *
665 *@param buddy Description of the Parameter
666 */
667 public ResourceActionListener(BuddyStatus buddy) {
668 this.buddy = buddy;
669 }
670
671
672 /**
673 * Description of the Method
674 *
675 *@param e Description of the Parameter
676 */
677 public void actionPerformed(ActionEvent e) {
678 JMenuItem item = (JMenuItem) e.getSource();
679 BuddyList.getInstance().getBuddyListTree().initiateConversation(buddy);
680 ChatPanel window = (ChatPanel) buddy.getConversation();
681 window.getResourceBox().setSelectedItem(item.getText());
682 window.getResourceBox().validate();
683 }
684 }
685 }
686