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