#!/usr/bin/env python

#
# TODO:
#   -- fix mass transport subscribe crash ??
#   -- implement group chat
#   -- catch errors better with dialog to show em.
#

import sys,string,os,re,time
import gtk, _gtk, GDK

# Change path so we find jabber libs strait from tarball
sys.path.insert(1, os.path.join(sys.path[0], '..'))
sys.path.insert(1, os.path.join(sys.path[0], '../util'))

import jabber
import sleepy

TRUE = 1
FALSE = 0
OK = 1
CANCEL = 2

## add a server name entry to the below ## 
Known = {
          'yahoo':
             { 'xpm' : 'an xpm path' },
          'msn':
             { 'xpm' : 'info....'},
          'icq':
             { 'xpm' : 'info....'},
        }

def makeKnownNice(jid):
    for known in Known.keys():
        if re.match("^"+known+".*", jid.getDomain()):
            if jid.getNode():
                return jid.getNode()
            else:
                return known + " transport"
    return str(jid)

def sort_jids(a,b):
    if string.lower(str(a)) < string.lower(str(b)): return -1
    if string.lower(str(a)) > string.lower(str(b)): return 1
    return 0
    
class Tab:
    def __init__(self, gui, title):
        self._type = type
        self._notebook = gui.notebook
        self._title = title
        self._id = None
        self._box = gtk.GtkVBox()
        self._main_callback = None
        self._cb = None

        self.cmap = gui.get_colormap()
        self.cols={}
        self.cols['blue']  = self.cmap.alloc('blue')
        self.cols['red']   = self.cmap.alloc('red')
        self.cols['black'] = self.cmap.alloc('black')
        self.cols['green'] = self.cmap.alloc('green')

        self.gui = gui
        
    def getID(self): return self._id;
    def setID(self,val): self._id = val;

    def recieve(self,obj): pass
    def setCallBack(self,cb): self._cb = cb
    def getCallBack(self): return self._cb 
    def getData(self): pass
    def setData(self,val): pass

    def _addToNoteBook(self):
        self._tab_label = gtk.GtkLabel(self._title)
        self._tab_label.show()
        self._notebook.append_page(self._box,self._tab_label)

    def tabClicked(self, *args):
        return gtk.FALSE

    def highlight(self):
        #style = _gtk.gtk_rc_get_style() # self._tab_label)
        style = self._tab_label.get_style()
        new_style = style.copy()
        new_style.fg[0] = self.cols['blue'] 
        self._tab_label.set_style(new_style)

    def lowlight(self):
        style = self._tab_label.get_style()
        new_style = style.copy()
        new_style.fg[0] = self.cols['black'] 
        self._tab_label.set_style(new_style)

    def getJID(self):
        return None

    def destroy(self,*args):
        i = 0
        for tab in self.gui._tabs:
            if tab == self:
                self._notebook.remove_page(i)
                del(self.gui._tabs[i])
                ## self.__destroy__ ? 
            i=i+1


class Chat_Tab(Tab): ### Make bigger and Better !!!
    def __init__(self, gui, jid, title='a tab'):
        Tab.__init__(self, gui, title)

        self._id = str(jid.getStripped())
        
        self._scroll = gtk.GtkScrolledWindow()
        self._txt = gtk.GtkText()
        self._txt.set_word_wrap( gtk.TRUE )
        self._scroll.add(self._txt)
        self._scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self._box.pack_start(self._scroll, fill=gtk.TRUE, expand=gtk.TRUE)

        self._hbox = gtk.GtkHBox()
        self._entry = gtk.GtkEntry()
        self._hbox.pack_start(self._entry, fill=gtk.TRUE, expand=gtk.TRUE)
        self._send_button = gtk.GtkButton('send')
        #self._send_button.connect('clicked', self._cb, self)
        #self._entry.connect('activate', self._cb, self )
        self._hbox.pack_end(self._send_button, fill=gtk.FALSE, expand=gtk.FALSE)
        self._box.pack_end(self._hbox, fill=gtk.TRUE, expand=gtk.FALSE)

        self._box.show_all()
        self._addToNoteBook()
        self._entry.grab_focus()

        ## this_tab.event_connected = 0 ??

    def getJID(self):
        return self._id


    def recieve(self,obj):
        if obj.getFrom().getStripped() == self._id:
            if str(obj.__class__) == 'jabber.Message':
                if obj.getError():
                    err_code = ''
                    if obj.getErrorCode(): err_code = obj.getErrorCode()
                    self._txt.insert(None,self.cols['red'], None,
                                     "%s ( %s )" % (obj.getError(),
                                     err_code) )
                else:
                    self._txt.insert(None,self.cols['red'], None,
                                     "<%s> " % obj.getFrom().getStripped())
                    self._txt.insert(None,None, None, "%s\n" % obj.getBody())
                return TRUE
            if str(obj.__class__) == 'jabber.Presence':
                if obj.getType() != 'unavailable':
                    self._txt.insert(None,self.cols['green'], None,
                                     "<%s> ( %s / %s )\n" % 
                                     ( obj.getFrom().getStripped(),
                                       obj.getStatus(), obj.getShow() ) )
                else:
                    self._txt.insert(None,self.cols['green'], None,
                                     "<%s> went offline\n" % 
                                     obj.getFrom().getStripped() )
                return TRUE
        return FALSE
    
    def getData(self):
        txt = self._entry.get_text() 
        self._entry.set_text('')
        self._txt.insert(None,None,None, "<%s> %s\n" %
                         ( self.gui.jabberObj.loggedin_jid.getStripped(), txt)
                         )
        return txt

class Debug_Tab(Tab): ### Make bigger and Better !!!
    def __init__(self, gui, title='DEBUG'):
        Tab.__init__(self, gui, title)

        self._id = "DEBUG"
        
        self._scroll = gtk.GtkScrolledWindow()
        self._txt = gtk.GtkText()
        self._txt.set_word_wrap( gtk.TRUE )
        self._scroll.add(self._txt)
        self._scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self._box.pack_start(self._scroll, fill=gtk.TRUE, expand=gtk.TRUE)

        self._hbox = gtk.GtkHBox()
        self._box.show_all()
        self._addToNoteBook()

        ## this_tab.event_connected = 0 ??

    def getJID(self):
        return self._id


    def recieve(self,obj):
        return TRUE


class Url_Tab(Tab): ### Make bigger and Better !!!
    def __init__(self, gui):
        Tab.__init__(self, gui, 'URLs')

        self._id = 'URLs'
        self._regexp = re.compile('(http://[^\s]+)', re.IGNORECASE)

        self._scrolled_win = gtk.GtkScrolledWindow()
        self._scrolled_win.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self._box.pack_start(self._scrolled_win)


        self._list = gtk.GtkList()
        self._list.set_selection_mode(gtk.SELECTION_BROWSE)
        self._scrolled_win.add_with_viewport(self._list)


        self._list.connect("select-child" , self.selectCB)


        self._hbox = gtk.GtkHBox()
        self._open_button = gtk.GtkButton('open')
        self._hbox.pack_end(self._open_button, fill=gtk.FALSE,
                            expand=gtk.FALSE)
        self._box.pack_end(self._hbox, fill=gtk.TRUE, expand=gtk.FALSE)
        self._box.show_all()
        self._addToNoteBook()

        ## this_tab.event_connected = 0 ??

    def getJID(self):
        return self._id


    def recieve(self,obj):
        if str(obj.__class__) == 'jabber.Message':
            m = self._regexp.match(obj.getBody())
            if m:
                list_item = gtk.GtkListItem(m.group())
                self._list.add(list_item)
                list_item.show()
                return TRUE
        return FALSE
    
    def selectCB(self, *args): pass


class Roster_Tab(Tab): ### Make bigger and Better !!!
    def __init__(self, gui, title):
        Tab.__init__(self, gui, title)
        self._roster_selected = None
        self._online_icon, self._online_mask = \
          gtk.create_pixmap_from_xpm( gui.get_window(), None,"online.xpm" );
        self._offline_icon, self._offline_mask = \
          gtk.create_pixmap_from_xpm( gui.get_window(), None,"offline.xpm" );
        self._pending_icon, self._pending_mask = \
          gtk.create_pixmap_from_xpm( gui.get_window(), None,"pending.xpm" );

        self._rows = []

        self._scroll = gtk.GtkScrolledWindow()

        self._ctree = gtk.GtkCTree(1,0)
        self._ctree.set_column_width(0,200);
        self._ctree.set_line_style(gtk.CTREE_LINES_NONE)
        self._ctree.set_expander_style(gtk.CTREE_EXPANDER_CIRCULAR)
        self._ctree.connect("select_row" , self.rosterSelectCB)
        self.paint_tree()
        
        self._scroll.add(self._ctree)            

        self._scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.FALSE)
        self._box.pack_start(self._scroll, fill=gtk.TRUE, expand=gtk.TRUE)

        self._hbox = gtk.GtkHBox()

        self._box.pack_end(self._hbox, fill=gtk.TRUE, expand=gtk.FALSE)

        self._box.show_all()
        self._addToNoteBook()
    
    def rosterSelectCB(self, *args):
        self._roster_selected = self._ctree.get_row_data(int(args[1]))
        if args[3].type == GDK._2BUTTON_PRESS:
            self._cb()

    def get_roster_selection(self):
        return self._roster_selected

    def recieve(self,obj):
        if str(obj.__class__) != 'jabber.Message':
            if str(obj.__class__) == 'jabber.Iq':
                if obj.getQuery() == jabber.NS_ROSTER:
                    self.paint_tree() ## only paint if roster iq
            else:
                self.paint_tree() ## a presence 



    def paint_tree(self):
        self._ctree.freeze()
        self._ctree.clear()
        self._online_node = self._ctree.insert_node(
            None, None, ( 'online', ), 2,
            None, None, None, None, gtk.FALSE,
            gtk.TRUE )
        self._offline_node = self._ctree.insert_node(
            None, None, ( 'offline', ), 2,
            None, None, None, None, gtk.FALSE,
            gtk.TRUE )
        self._pending_node = self._ctree.insert_node(
            None, None, ( 'pending', ), 2,
            None, None, None, None, gtk.FALSE,
            gtk.TRUE )

        _roster = self.gui.jabberObj.getRoster()
        self._nodes = []
        jids = _roster.getJIDs()
        jids.sort(sort_jids)
        for jid in jids:
            attach_node = None
            nice_name = makeKnownNice(jid)
            show = ''
            if _roster.getShow(jid): show = _roster.getShow(jid)
            if _roster.getStatus(jid):
                if show:
                    show = " ( %s / %s )" % ( show, _roster.getStatus(jid) )
                else:
                    show = " ( %s )" % _roster.getStatus(jid) 
            nice_name = str("%s %s" % ( nice_name, show ))

            if _roster.getOnline(jid) == 'online':
                node =self._ctree.insert_node(
                                 self._online_node, None, ( nice_name, )
                                 , 2,
                                 pixmap_closed = self._online_icon,
                                 mask_closed   = self._online_mask,
                                 is_leaf=gtk.TRUE,
                                 expanded=gtk.TRUE )

            elif _roster.getOnline(jid) == 'offline':
                node =self._ctree.insert_node(
                                 self._offline_node, None, ( nice_name, )
                                 , 2,
                                 pixmap_closed = self._offline_icon,
                                 mask_closed   = self._offline_mask,
                                 is_leaf=gtk.TRUE,
                                 expanded=gtk.TRUE )

            elif _roster.getOnline(jid) == 'pending':
                node =self._ctree.insert_node(
                                 self._pending_node, None, ( nice_name, )
                                 , 2,
                                 pixmap_closed = self._pending_icon,
                                 mask_closed   = self._pending_mask,
                                 is_leaf=gtk.TRUE,
                                 expanded=gtk.TRUE )
            else:
                pass

            self._nodes.append(node)
            self._ctree.node_set_row_data(node, str(jid))
            
        self._ctree.thaw()
        if self.gui._tabs and self != self.gui.getSelectedTab():
            self.highlight()
        
class Logon_dialog(gtk.GtkWindow):                  
                                                 
    def __init__(self, master):

        gtk.GtkWindow.__init__(self)

        self.password = ''
        self.username = ''
        self.server   = 'jabber.org'
        self.done     = None

        self.connect("delete_event", self.delete_event)
        self.master = master

        self.vbox = gtk.GtkVBox(gtk.FALSE,5)
        self.add(self.vbox)

        self.frame_s = gtk.GtkFrame("Server to use")
        self.table_s = gtk.GtkTable(1,6,gtk.FALSE)
        self.server_lbl = gtk.GtkLabel('Server')
        self.server_lbl.set_alignment(1,0.5)
        self.server_entry   = gtk.GtkEntry()

        self.table_s.attach( self.server_lbl,
                             0,2,0,1,xpadding=3,ypadding=2)
        self.table_s.attach( self.server_entry,
                             2,6,0,1,xpadding=3,ypadding=2)
        self.frame_s.add(self.table_s)
        self.vbox.pack_start(self.frame_s)
        
        self.frame = gtk.GtkFrame("Have Account?")
        self.table = gtk.GtkTable(6,6,gtk.FALSE)
        self.username_lbl = gtk.GtkLabel('Username')
        self.username_lbl.set_alignment(1,0.5)
        self.password_lbl = gtk.GtkLabel('Password')
        self.password_lbl.set_alignment(1,0.5)


        self.username_entry = gtk.GtkEntry()

        self.password_entry = gtk.GtkEntry()
        self.password_entry.set_visibility(gtk.FALSE)

        self.table.attach( self.username_lbl,   0,2,1,2,xpadding=3,ypadding=2)
        self.table.attach( self.password_lbl,   0,2,2,3,xpadding=3,ypadding=2) 
        self.table.attach( self.username_entry, 2,6,1,2,xpadding=3,ypadding=2)
        self.table.attach( self.password_entry, 2,6,2,3,xpadding=3,ypadding=2)

        self.save_check = gtk.GtkCheckButton('Save Details')
        self.table.attach( self.save_check, 3,6,4,5,xpadding=3,ypadding=2)

        self.login_button = gtk.GtkButton('Login')
        self.login_button.connect('clicked', self.login)
        self.table.attach( self.login_button, 3,6,5,6,xpadding=5) 
        self.frame.add(self.table)
        
        self.vbox.pack_start(self.frame)
        
        self.frame_acc = gtk.GtkFrame("New User?")
        self.table_acc = gtk.GtkTable(1,1,gtk.FALSE)
        self.button_acc = gtk.GtkButton("Get an Account")
        self.button_acc.connect('clicked', self.new_account)
        self.table_acc.attach( self.button_acc, 0,1,0,1,xpadding=5,ypadding=5)
        
        self.frame_acc.add(self.table_acc)
        self.vbox.pack_end(self.frame_acc)

        self.readRC()
        self.username_entry.set_text(self.username)
        self.password_entry.set_text(self.password)
        self.server_entry.set_text(self.server)
        
        self.vbox.show_all()
        self.show()
        self.set_modal(gtk.TRUE)

    def login(self,*args):
        self.password = self.password_entry.get_text()
        self.username = self.username_entry.get_text()
        self.server   = self.server_entry.get_text()
        self.done = gtk.TRUE
        if self.save_check.get_active(): 
            try:
                rcfile = open(os.environ['HOME'] + "/.pyjab",'w')
            except:
                return
            rcfile.write("%s\0%s\0%s\n" % (self.server, self.username, self.password))
            rcfile.close()
        else:
            try: os.remove(os.environ['HOME'] + "/.pyjab")
            except: pass # file dont exist, or I cant delete
            
    def readRC(self):
        try:
            rcfile = open(os.environ['HOME'] + "/.pyjab",'r')
        except:
            return
        self.save_check.set_active(gtk.TRUE)
        data = (rcfile.readline().splitlines())[0]
        self.server, self.username, self.password = data.split("\0")
        rcfile.close()
        return

    def new_account(self,*args):
        self.done = 2

    def delete_event(self, *args):
        gtk.mainquit()
        sys.exit(0)

    def close(self,*args):
        self.hide()
        del self

class New_ac_dialog(gtk.GtkWindow):                  
                                                 
    def __init__(self, master, jabber, agent=None):

        gtk.GtkWindow.__init__(self)

        self.connect("delete_event", self.delete_event)
        self.master = master
        self.jabber = jabber
        self.done = None
        self.agent = agent
        self.vbox = gtk.GtkVBox(gtk.FALSE,5)
        self.add(self.vbox)

        self.frame = gtk.GtkFrame("New Account")
        self.jabber.requestRegInfo(self.agent)
        req = self.jabber.getRegInfo()

        self.table = gtk.GtkTable(6,6,gtk.FALSE)
        self.instr_lbl = gtk.GtkLabel(req[u'instructions'])
        
        self.entrys = {}
        i = 0
        for info in req.keys():
            if info != u'instructions' and \
               info != u'key':
                self.entrys[info] = {}
                self.entrys[info]['lbl'] = gtk.GtkLabel(info)
                self.entrys[info]['lbl'].set_alignment(1,0.5)
                self.entrys[info]['entry'] = gtk.GtkEntry()
                self.table.attach(
                    self.entrys[info]['lbl'], 0,2,1+i,2+i,
                    xpadding=3,ypadding=2)
                self.table.attach(
                    self.entrys[info]['entry'], 2,6,1+i,2+i,
                    xpadding=3,ypadding=2)
                i=i+1

        self.reg_button = gtk.GtkButton('Register')
        self.table.attach( self.reg_button, 2,6,0,1,xpadding=3,ypadding=2)
        self.reg_button.connect('clicked', self.register)

        self.frame.add(self.table)
        self.vbox.pack_start(self.frame)

        self.vbox.show_all()
        self.show()
        self.set_modal(gtk.TRUE)

    def register(self,*args):
        for info in self.entrys.keys():
            self.jabber.setRegInfo( info,
                                    self.entrys[info]['entry'].get_text() )
        self.username = self.entrys['username']['entry'].get_text()
        self.password = self.entrys['password']['entry'].get_text()
        self.jabber.sendRegInfo(self.agent)
        self.done = OK

    def delete_event(win, event=None):
        self.hide()
        return gtk.TRUE

    def close(self,*args):
        self.hide()
        del self

class Add_dialog(gtk.GtkDialog):                  
                                                 
    def __init__(self, master, jabberObj):

        gtk.GtkDialog.__init__(self)

        self.jid_str  = None
        self.done     = None

        self.connect("delete_event", self.delete_event)
        self.master = master
        self.jabber = jabberObj

        if self.master:
            self.set_transient_for(self.master)

        self.set_usize(200,150)

        self.table = gtk.GtkTable(5,2,gtk.FALSE)
        self.jid_lbl = gtk.GtkLabel('JID')

        self.jid_entry   = gtk.GtkEntry()

        self.table.attach( self.jid_lbl,     0,1,0,1)
        self.table.attach( self.jid_entry,   1,2,0,1)

        self.add_button = gtk.GtkButton('Add')
        self.add_button.connect('clicked', self.add)
        self.action_area.pack_start(self.add_button,expand=gtk.FALSE)
        
        self.vbox.pack_start(self.table)
             
        self.vbox.show_all()
        self.action_area.show_all()
        self.show()
        self.set_modal(gtk.TRUE)

    def add(self,*args):

        self.done = self.jid_entry.get_text()


    def delete_event(win, event=None):
        self.hide()
        self.done = 1
        return gtk.FALSE

    def close(self,*args):
        self.hide()
        del self

class Status_dialog(gtk.GtkDialog):                  
                                                 
    def __init__(self):

        gtk.GtkDialog.__init__(self)

        self.jid_str  = None
        self.done     = None
        self.type     = 'available'

        self.connect("delete_event", self.delete_event)
        #self.master = master
        #self.jabber = jabberObj
        
        self.set_usize(200,150)

        self.table = gtk.GtkTable(5,2,gtk.FALSE)
        self.jid_lbl = gtk.GtkLabel('Status')

        self.jid_entry   = gtk.GtkEntry()

        self.table.attach( self.jid_lbl,     0,1,0,1)
        self.table.attach( self.jid_entry,   1,2,0,1)

        self.add_button = gtk.GtkButton('Set')
        self.add_button.connect('clicked', self.set)
        self.action_area.pack_start(self.add_button,expand=gtk.FALSE)

        self.avail_radio   = gtk.GtkRadioButton(None, 'available')
        self.unavail_radio = gtk.GtkRadioButton(self.avail_radio, 'unavailable')
        self.avail_radio.connect('clicked', self.avail)
        self.unavail_radio.connect('clicked', self.unavail)
        self.avail_radio.set_active(gtk.TRUE)

        self.table.attach( self.avail_radio,     0,2,1,2)
        self.table.attach( self.unavail_radio,   0,2,2,3)

        self.vbox.pack_start(self.table)
             
        self.vbox.show_all()
        self.action_area.show_all()
        self.show()
        self.set_modal(gtk.TRUE)

    def avail(self, *args): self.type = None
    def unavail(self, *args): self.type = 'unavailable'

    def set(self,*args):

        self.done =  ( self.type , self.jid_entry.get_text() )
        

    def delete_event(win, event=None):
        self.hide()
        self.done = 1
        return gtk.FALSE

    def close(self,*args):
        self.hide()
        del self

MSG_DIA_TYPE_OK    = 0
MSG_DIA_TYPE_YESNO = 1
MSG_DIA_RET_OK     = 1
MSG_DIA_RET_CANCEL = 2

class Msg_dialog(gtk.GtkDialog):                  
                                                 
    def __init__(self, master, msg, type = MSG_DIA_TYPE_OK ):
        gtk.GtkDialog.__init__(self)

        self.done     = None
        self.connect("delete_event", self.delete_event)
        self.master = master
        self.set_usize(200,150)

        if self.master:
            self.set_transient_for(self.master)

        
        self.msg_lbl = gtk.GtkLabel(msg)
        
        self.ok_button = gtk.GtkButton('Ok')
        self.ok_button.connect('clicked', self.okay)
        self.action_area.pack_start(self.ok_button,expand=gtk.FALSE)

        if type == MSG_DIA_TYPE_YESNO:
            self.cancel_button = gtk.GtkButton('Cancel')
            self.cancel_button.connect('clicked', self.cancel)
            self.action_area.pack_start(self.cancel_button,expand=gtk.FALSE)
            
        self.vbox.pack_start(self.msg_lbl)
        self.vbox.show_all()
        self.action_area.show_all()
        self.show()
        self.set_modal(gtk.TRUE)

    def okay(self,*args):
        self.done = MSG_DIA_RET_OK

    def cancel(self,*args):
        self.done = MSG_DIA_RET_CANCEL

    def delete_event(win, event=None):
        self.hide()
        self.done = MSG_DIA_RET_CANCEL

    def close(self,*args):
        self.hide()
        del self

class Trans_dialog(gtk.GtkDialog):                  
                                                 
    def __init__(self, master, jabberObj ):
        gtk.GtkDialog.__init__(self)

        self.agents = jabberObj.requestAgents()

        self.done     = None
        self.connect("delete_event", self.delete_event)
        self.master = master
        self.set_usize(200,150)

        if self.master:
            self.set_transient_for(self.master)
        
        self.ok_button = gtk.GtkButton('Ok')
        self.ok_button.connect('clicked', self.okay)
        self.action_area.pack_start(self.ok_button,expand=gtk.FALSE)
        self.cancel_button = gtk.GtkButton('Cancel')
        self.cancel_button.connect('clicked', self.cancel)
        self.action_area.pack_start(self.cancel_button,expand=gtk.FALSE)

        self.scrolled_win = gtk.GtkScrolledWindow()
        self.scrolled_win.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.vbox.pack_start(self.scrolled_win)

        self.list = gtk.GtkList()
        self.list.set_selection_mode(gtk.SELECTION_BROWSE)
        self.scrolled_win.add_with_viewport(self.list)

        for i in self.agents.keys():
            if self.agents[i].has_key('transport'):
                list_item = gtk.GtkListItem(self.agents[i]['name'])
                list_item.set_data('jid', i)
                self.list.add(list_item)
                list_item.show()

        self.list.connect("select-child" , self.selectCB)
            
        self.vbox.pack_start(self.scrolled_win)
        self.vbox.show_all()
        self.action_area.show_all()
        self.show()
        self.selected = None
        self.set_modal(gtk.TRUE)

    def selectCB(self, *args):
        self.selected = args[1].get_data('jid')

    def okay(self,*args):
        self.done = OK

    def cancel(self,*args):
        self.done = CANCEL

    def delete_event(win, event=None):
        self.hide()
        self.done = MSG_DIA_RET_CANCEL

    def close(self,*args):
        self.hide()
        del self


class mainWindow(gtk.GtkWindow):         # Usual Base
    def __init__(self, title='pygtk app', jabberObj=None,
                 width=None, height=None):
        gtk.GtkWindow.__init__(self)
        self.set_title(title)
        if width is None:
            if gtk.screen_width() > 300:      ## Fit the display
                width = 320
                height = 200
            else:
                width = 240
                height = 300

        self._tabs = []
        self.cols = {};

        self.jabberObj = jabberObj
        self.roster_selected = None
        
        self.set_usize(width,height)
        self.connect("delete_event", self.quit)
        
        self.box = gtk.GtkVBox()
        self.add(self.box)
        self.box.show()
        self.tbox = gtk.GtkHBox()

        self.checkItemCalled = 0
        self.init_menu()
        self.init_status_select()

        self.close_but = gtk.GtkButton('X')
        self.close_but.connect("clicked", self.closeTabCB);
        self.close_but.show()
        self.tbox.pack_end(self.close_but, fill=gtk.FALSE, expand=gtk.FALSE)
        
        self.tbox.show()
        self.box.pack_start(self.tbox, fill=gtk.FALSE, expand=gtk.FALSE)
        
        self.notebook = gtk.GtkNotebook()
        self.notebook.set_tab_pos (gtk.POS_BOTTOM);
        self.notebook.set_scrollable( gtk.TRUE ) 
        self.notebook.connect('switch_page', self.notebook_switched)
        self.box.pack_end(self.notebook, fill=gtk.TRUE, expand=gtk.TRUE)

        self._tabs.append( Roster_Tab(self, 'roster') )

        self.notebook.show()
        self.show()


    def init_status_select(self):
        ag = gtk.GtkAccelGroup()
        self.itemsel = gtk.GtkItemFactory(gtk.GtkOptionMenu, "<select>", ag)
        self.add_accel_group(ag)
        
        self.itemsel.create_items([
            ('/Available',   None, self.statusCB, 1,     ''),
            ('/Unavailable', None, self.statusCB, 0,     ''),
            ('/Custom',      None, self.custstatusCB, 0, ''),
            ])

        self.status_select = self.itemsel.get_widget('<select>')
        self.tbox.pack_start(self.status_select,
                             fill=gtk.TRUE, expand=gtk.TRUE)
        self.status_select.show()

    def init_menu(self):
        ag = gtk.GtkAccelGroup()
        self.itemf = gtk.GtkItemFactory(gtk.GtkMenuBar, "<main>", ag)
        self.add_accel_group(ag)
        
        self.itemf.create_items([
            ('/File',             None, None, 0, '<Branch>'),
            ('/File/Exit',        None, self.quit, 0, ''),
            ('/Tools',            None, None, 0, '<Branch>'),
            ('/Tools/Chat',       None, self.jabberObj.addChatTabViaRoster,
                                  1, ''),            
            ('/Tools/sep1',       None, None, 0, '<Separator>'),            
            ('/Tools/Add',        None, self.addCB, 1, ''),
            ('/Tools/Remove',     None, self.removeCB, 0, ''),

            ('/Tools/Status/Available',   None, self.statusCB, 1, '<CheckItem>'),
            ('/Tools/Status/Unavailable', None, self.statusCB, 0, '<CheckItem>'),
            ('/Tools/Status/Custom', None, self.custstatusCB, 0, ''),
            ('/Tools/sep2',        None, None, 0, '<Separator>'),            
            ('/Tools/Transports', None, self.transCB, 0, ''),
            ('/Tools/Tabs/Rotate', None, self.rotateTabCB, 0, ''),
            ('/Tools/Tabs/Url Grabber', None, self.urlTabCB, 0, ''),
            ('/Tools/Tabs/Debug', None, self.debugTabCB, 0, ''),
            ('/Help', None, None, 0, '<Branch>') ,
            ('/Help/About', None, self.infoCB, 0, '')
            ])

        self.menubar = self.itemf.get_widget('<main>')
        self.itemf.get_widget( '/Tools/Status/Available' ).set_active(gtk.TRUE)
        self.tbox.pack_start(self.menubar, fill=gtk.TRUE, expand=gtk.TRUE)
        self.menubar.show()

    def statusCB(self,action,widget):
        if self.checkItemCalled == 1:   ## Make sure set_active does not 
            return                      ## recall the callback
        self.checkItemCalled = 1;

        ## More nasty workarounds for ItemFactory Radiobutton problems
        for path in [ '/Tools/Status/Available', '/Tools/Status/Unavailable' ]:
            if widget != self.itemf.get_widget( path ):
                self.itemf.get_widget( path ).set_active(gtk.FALSE)
        self.checkItemCalled = 0;
        
        if action == 1:
            # available
            self.jabberObj.presence_details = [ 'available', None ]
            pres = jabber.Presence()
        else:
            self.jabberObj.presence_details = [ 'unavailable', None ]
            pres = jabber.Presence(type='unavailable')

        self.jabberObj.send(pres)
            
    def custstatusCB(self, *args):
        dia = Status_dialog()
        while dia.done is None:
            self.jabberObj.process()
        type, show = dia.done
        pres = jabber.Presence(type=type)
        pres.setShow(show)
        self.jabberObj.presence_details = [ type, show ]
        self.jabberObj.send(pres)
        dia.close()
        
    def urlTabCB(self, *args):
        url_tab = self.findTab( 'URLs' )
        if url_tab:
            url_tab.destroy()            
        else:
            self._tabs.append( Url_Tab(self) )

    def debugTabCB(self, *args):
        dbg_tab = self.findTab( 'DEBUG' )
        if dbg_tab:
            dbg_tab.destroy()            
        else:
            self._tabs.append( Debug_Tab(self) )


    def rotateTabCB(self, *args):
        if self.notebook.get_tab_pos() == gtk.POS_BOTTOM:
            self.notebook.set_tab_pos( gtk.POS_LEFT )
        else:
            self.notebook.set_tab_pos( gtk.POS_BOTTOM )

    def transCB(self, *args):
        trans_dia = Trans_dialog(None, self.jabberObj)
        while (trans_dia.done is None):
            self.jabberObj.process()
        if trans_dia.done == OK and trans_dia.selected:
            names = string.split(trans_dia.selected, '.')
            agent = names[0]
            trans_dia.close()
            new_acc_dia = New_ac_dialog(None, self.jabberObj, agent=agent)
            while (new_acc_dia.done is None):
                self.jabberObj.process()
            new_acc_dia.close()
            return
        trans_dia.close()
    
    def addCB(self, *args):
        add_dia = Add_dialog(self, self.jabberObj )      
        while (add_dia.done is None):
            self.jabberObj.process()
        self.jabberObj.send(jabber.Presence(add_dia.done, 'subscribe'))
        add_dia.close()

    def removeCB(self,*args):
        who = self.getTab(0).get_roster_selection()
        if not who: return
        msg_dia = Msg_dialog(None,
                             "unsubscribe %s ?" % (who),
                             MSG_DIA_TYPE_YESNO
                             )
        while (msg_dia.done is None): self.jabberObj.process()
        if (msg_dia.done == MSG_DIA_RET_OK):
            self.jabberObj.send(jabber.Presence(to=who, type='unsubscribe'))
        msg_dia.close()

    def closeTabCB(self, *args):
        if self.notebook.get_current_page():
            self.getSelectedTab().destroy()

    def findCB(self, *args): pass
    def infoCB(self, *args): pass

    def handle_switch(self,*args):
        tab_no = self.notebook.get_current_page()
        self.getTab(tab_no).lowlight()
        
    def notebook_switched(self, *args):
        gtk.idle_add(self.handle_switch)

    def findTab(self,id):
        for tab in self._tabs:
            if tab._id == id: return tab
        return None
 
    def getTabs(self):
        return self._tabs

    def getTab(self,val):
        return self._tabs[val]

    def getSelectedTab(self):
        return self._tabs[self.notebook.get_current_page()]

    def addTab(self,tab_obj):
        self._tabs.append( tab_obj )
        return tab_obj

    def removeTab(self,tab):
        if type(tab) == type(1):
            self.notebook.remove_tab(tab)
            del self._tabs[tab]
        else:
            print "not yet implemented"
            
    def quit(self, *args):
        #gtk.mainquit()
        sys.exit(0)

class jabberClient(jabber.Client):
    def __init__(self):
        self.sleeper = None
        self.sleeper_state = None
        self.gui = None
        not_connected = 1
        while not_connected:

            login_dia = Logon_dialog(None)
            while (login_dia.done is None):
                while gtk.events_pending(): gtk.mainiteration()
            login_dia.close()

            server   = login_dia.server

            jabber.Client.__init__(self,host=server,debug=0)
            try:
                self.connect()
            except:
                msg_dia = Msg_dialog(None, "Couldnt connect to "+server)
                while (msg_dia.done is None):
                    while gtk.events_pending(): gtk.mainiteration()
                msg_dia.close()
                sys.exit(0)
            else:
                print "connected!"

            if (login_dia.done == 2):
                new_acc_dia = New_ac_dialog(None, self)
                while (new_acc_dia.done is None):
                    self.process()
                new_acc_dia.close()
                username = new_acc_dia.username
                password = new_acc_dia.password

            else:
                username = login_dia.username
                password = login_dia.password
            resource = 'pygtkjab'

                
            print "logging in"
            if self.auth(username,password,resource):
                not_connected = 0
            else:
                msg_dia = Msg_dialog(None, self.lastErr)
                while (msg_dia.done is None):
                    while gtk.events_pending(): gtk.mainiteration()
                msg_dia.close()
                #print "eek -> ", self.lastErr, self.lastErrCode
                sys.exit(1)

        self.loggedin_jid     = jabber.JID( node = username, domain = server,
                                        resource = resource );
        self.presence_details = [ 'available', None ]
        
        Known[server] = { 'xpm':'something' }
        
        ## Build the roster Tab ##
        self.roster = []
        r = self.requestRoster()
        self.gui = mainWindow("jabber app",jabberObj=self)
        self.gui.getTab(0)._cb = self.addChatTabViaRoster;
        self.sendInitPresence()                                  
        self._unsub_lock = 0 ## hack to fix unsubscribe wierdo bug
        self._pres_queue  = []
        self.sleeper = sleepy.Sleepy()


    def addToRoster(self, *args): pass
              
    def dispatch_to_gui(self,obj):
        recieved = None
        for t in self.gui.getTabs():
            if t.recieve(obj): recieved = t
        return recieved

    def addChatTabViaRoster(self, *args):
        jid_raw = self.gui.getTab(0).get_roster_selection()
        if jid_raw:
            jid = jabber.JID(jid_raw)
            i = 0
            for t in self.gui.getTabs():
                if t.getJID() == jid.getStripped():
                    self.gui.notebook.set_page(i)
                    return
                i=i+1
            self.gui.addTab( Chat_Tab(self.gui, jid, makeKnownNice(jid) ) )

            self.gui.getTab(-1)._send_button.connect('clicked',
                                                     self.messageSend,
                                                     self.gui.getTab(-1) )
            self.gui.getTab(-1)._entry.connect('activate',
                                                     self.messageSend,
                                                     self.gui.getTab(-1) )
            self.gui.notebook.set_page(i)
            
    def messageSend(self, *args):
        tab = args[-1]
        msg = tab.getData()
        msg_obj = jabber.Message(tab._id, msg)
        msg_obj.setType('chat')
        self.send(msg_obj)

    def messageHandler(self, msg_obj):
        tab = self.dispatch_to_gui(msg_obj)
        if tab is None:
            self.gui.addTab(
                Chat_Tab(self.gui, msg_obj.getFrom(),
                         makeKnownNice(msg_obj.getFrom()) )
                ).recieve(msg_obj)
            self.gui._tabs[-1]._send_button.connect('clicked',
                                                    self.messageSend,
                                                    self.gui._tabs[-1] )
            self.gui.getTab(-1)._entry.connect('activate',
                                                     self.messageSend,
                                                     self.gui.getTab(-1) )
            self.gui._tabs[-1].highlight()
        else:
            if tab != self.gui.getSelectedTab():
                tab.highlight()
                
    def presenceHandler(self, prs_obj):

        type = prs_obj.getType()
        who  = prs_obj.getFrom().getStripped()

        if type == 'subscribe':
            msg_dia = Msg_dialog(None,
                                 "subscribe request from %s" % (who),
                                 MSG_DIA_TYPE_YESNO
                                 )
            while (msg_dia.done is None): self.process()
            if (msg_dia.done == MSG_DIA_RET_OK):
                self.send(jabber.Presence(to=who, type='subscribed'))
                
                if who not in self.getRoster().getJIDs() or \
                   self.getRoster().getSub(who) != 'both':
                    self.send(jabber.Presence(to=who, type='subscribe'))
            msg_dia.close()

        elif type == 'unsubscribe' and not self._unsub_lock:
            self._unsub_lock = 1 ## HACK !
            msg_dia = Msg_dialog(None,
                                 "unsubscribe request from %s" % (who),
                                 MSG_DIA_TYPE_YESNO
                                 )
            while (msg_dia.done is None): self.process()
            if (msg_dia.done == MSG_DIA_RET_OK):
                self.send(jabber.Presence(to=who, type='unsubscribed'))
            msg_dia.close()


        else: pass

        self.dispatch_to_gui(prs_obj)
        self._unsub_lock = 0

    def iqHandler(self, iq_obj):
        self.dispatch_to_gui(iq_obj)

    def process(self,time=0.1):
        while gtk.events_pending(): gtk.mainiteration()
        jabber.Client.process(self,time)

        if self.sleeper:
            state_pres = None
            self.sleeper.poll()
            state = self.sleeper.getState()
            if state != self.sleeper_state:
                if state == sleepy.STATE_WOKEN:
                    state_pres = jabber.Presence(type='available')
                    state_pres.setStatus('online')
                    state_pres.setShow('')
                if state == sleepy.STATE_SLEEPING:
                    state_pres = jabber.Presence(type='available')
                    state_pres.setStatus('away')
                    state_pres.setShow('Away from computer')
                if state_pres: self.send(state_pres)
            self.sleeper_state = state

    def log(self, data, inout=''):
        ## we overide xmlstreams log method with our own
        if self.gui:
            dbg_tab = self.gui.findTab( 'DEBUG' )
            if dbg_tab:
                dbg_tab._txt.insert(None, None, None, "%s - %s - %s\n" % \
                 (time.asctime(time.localtime(time.time())), inout, data ) )


def main():

#    pass args to jabberClient object
#    if -f exists mkfifo named with f param, open for writing ( r+ )
#    launcher will open this for reading after forking the app
#    app will then pipe messages to it

    s = jabberClient()
    while(1): s.process()
    
if __name__ == "__main__":
    main()  

















