blob: 1bc91b4f3a450a74f321bfd5c4e383484cabe9b9 [file] [log] [blame]
# $Id: account.py 4704 2014-01-16 05:30:46Z ming $
#
# pjsua Python GUI Demo
#
# Copyright (C)2013 Teluu Inc. (http://www.teluu.com)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
import sys
if sys.version_info[0] >= 3: # Python 3
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox as msgbox
else:
import Tkinter as tk
import tkMessageBox as msgbox
import ttk
import random
import pjsua2 as pj
import _pjsua2
import accountsetting
import application
import call
import chat as ch
# Account class
class Account(pj.Account):
"""
High level Python Account object, derived from pjsua2's Account object.
"""
def __init__(self, app):
pj.Account.__init__(self)
self.app = app
self.randId = random.randint(1, 9999)
self.cfg = pj.AccountConfig()
self.cfgChanged = False
self.buddyList = []
self.chatList = []
self.deleting = False
def findChat(self, uri_str):
uri = ch.ParseSipUri(uri_str)
if not uri: return None
for chat in self.chatList:
if chat.isUriParticipant(uri) and chat.isPrivate():
return chat
return None
def newChat(self, uri_str):
uri = ch.ParseSipUri(uri_str)
if not uri: return None
chat = ch.Chat(self.app, self, uri)
self.chatList.append(chat)
self.app.updateWindowMenu()
return chat
def statusText(self):
status = '?'
if self.isValid():
ai = self.getInfo()
if ai.regLastErr:
status = self.app.ep.utilStrError(ai.regLastErr)
elif ai.regIsActive:
if ai.onlineStatus:
if len(ai.onlineStatusText):
status = ai.onlineStatusText
else:
status = "Online"
else:
status = "Registered"
else:
if ai.regIsConfigured:
if ai.regStatus/100 == 2:
status = "Unregistered"
else:
status = ai.regStatusText
else:
status = "Doesn't register"
else:
status = '- not created -'
return status
def onRegState(self, prm):
self.app.updateAccount(self)
def onIncomingCall(self, prm):
c = call.Call(self, call_id=prm.callId)
call_prm = pj.CallOpParam()
call_prm.statusCode = 180
c.answer(call_prm)
ci = c.getInfo()
msg = "Incoming call for account '%s'" % self.cfg.idUri
if msgbox.askquestion(msg, "Accept call from '%s'?" % (ci.remoteUri), default=msgbox.YES) == u'yes':
call_prm.statusCode = 200
c.answer(call_prm)
# find/create chat instance
chat = self.findChat(ci.remoteUri)
if not chat: chat = self.newChat(ci.remoteUri)
chat.showWindow()
chat.registerCall(ci.remoteUri, c)
chat.updateCallState(c, ci)
else:
c.hangup(call_prm)
def onInstantMessage(self, prm):
chat = self.findChat(prm.fromUri)
if not chat: chat = self.newChat(prm.fromUri)
chat.showWindow()
chat.addMessage(prm.fromUri, prm.msgBody)
def onInstantMessageStatus(self, prm):
if prm.code/100 == 2: return
chat = self.findChat(prm.toUri)
if not chat:
print "=== IM status to '%s' cannot find chat" % prm.toUri
return
chat.addMessage(None, "Failed sending message to '%s': %s" % (prm.toUri, prm.reason))
def onTypingIndication(self, prm):
chat = self.findChat(prm.fromUri)
if not chat:
print "=== Incoming typing indication from '%s' cannot find chat" % prm.fromUri
return
chat.setTypingIndication(prm.fromUri, prm.isTyping)
# Account frame, to list accounts
class AccountListFrame(ttk.Frame):
"""
This implements a Frame which contains account list and buttons to operate
on them (Add, Modify, Delete, etc.).
"""
def __init__(self, parent, app, acc_list = []):
ttk.Frame.__init__(self, parent, name='acclist')
self.app = app
self.accList = acc_list
self.accDeletedList = []
self.pack(expand='yes', fill='both')
self._createWidgets()
for acc in self.accList:
self._showAcc(acc)
def _createWidgets(self):
self.tv = ttk.Treeview(self, columns=('ID', 'Registrar', 'Default'), selectmode='browse')
self.tv.heading('#0', text='Priority')
self.tv.heading(0, text='ID')
self.tv.heading(1, text='Registrar')
self.tv.heading(2, text='Default?')
self.tv.column('#0', width=60)
self.tv.column(0, width=300)
self.tv.column(1, width=200)
self.tv.column(2, width=60)
self.tv.grid(column=0, row=0, rowspan=4, padx=5, pady=5)
ttk.Button(self, text='Add..', command=self._onBtnAdd).grid(column=1, row=0, padx=5)
ttk.Button(self, text='Settings..', command=self._onBtnSettings).grid(column=1, row=1)
ttk.Button(self, text='Set Default', command=self._onBtnSetDefault).grid(column=1, row=2)
ttk.Button(self, text='Delete..', command=self._onBtnDelete).grid(column=1, row=3)
def _showAcc(self, acc):
is_default = 'Yes' if acc.isValid() and acc.isDefault() else ''
values = (acc.cfg.idUri, acc.cfg.regConfig.registrarUri, is_default)
self.tv.insert('', 0, str(acc.randId), open=True, text=str(acc.cfg.priority), values=values)
def updateAccount(self, acc):
is_default = 'Yes' if acc.isValid() and acc.isDefault() else ''
values = (acc.cfg.idUri, acc.cfg.regConfig.registrarUri, is_default)
self.tv.item(str(acc.randId), text=str(acc.cfg.priority), values=values)
def _getSelectedAcc(self):
items = self.tv.selection()
if not items:
return None
iid = int(items[0])
return [acc for acc in self.accList if acc.randId==iid][0]
def _onBtnAdd(self):
cfg = pj.AccountConfig()
dlg = accountsetting.Dialog(self.master, cfg)
if dlg.doModal():
acc = Account(self.app)
acc.cfg = cfg
self._showAcc(acc)
self.accList.append(acc)
self.cfgChanged = True
def _onBtnSettings(self):
acc = self._getSelectedAcc()
if not acc:
return
dlg = accountsetting.Dialog(self.master, acc.cfg)
if dlg.doModal():
self.updateAccount(acc)
self.cfgChanged = True
def _onBtnDelete(self):
acc = self._getSelectedAcc()
if not acc:
return
msg = "Do you really want to delete account '%s'" % acc.cfg.idUri
if msgbox.askquestion('Delete account?', msg, default=msgbox.NO) != u'yes':
return
self.accList.remove(acc)
self.accDeletedList.append(acc)
self.tv.delete( (str(acc.randId),) )
def _onBtnSetDefault(self):
acc = self._getSelectedAcc()
if not acc:
return
if acc.isValid():
acc.setDefault()
for acc in self.accList:
self.updateAccount(acc)
if __name__ == '__main__':
application.main()