SHARE
TWEET

Untitled

a guest Jun 15th, 2017 60 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/local/bin/python
  2. # -*- coding: utf-8 -*-
  3.  
  4. from asterisk import manager
  5. from twisted.internet import reactor
  6. from twisted.internet.protocol import DatagramProtocol
  7. import time, logging
  8. from threading import Thread, Lock
  9.  
  10. logging.basicConfig()
  11.  
  12. class TAPI(DatagramProtocol):
  13.     def __init__( self, logfile ):
  14.         self.commandCallbacks = {}
  15.         self.defferedCallbacks = {}
  16.         self.users = {}
  17.         self.lock = Lock()
  18.         self.logfile = logfile
  19.         self.log('TAPI socket started.')
  20.    
  21.     def log( self, message ):
  22.         try:
  23.             #logger = open(self.logfile,'a')
  24.             #logger.write('[ %s ] %s\n' % (time.strftime('%Y-%m-%d %H:%M:%S'), message))
  25.             print message
  26.             #logger.close()
  27.         except Exception, error:
  28.             print "Exception on logger caught // message %s" % str(error)
  29.  
  30.     def RegisterCallback( self, command, function ):
  31.         if not self.commandCallbacks.has_key( command ):
  32.             self.commandCallbacks[ command ] = function
  33.             self.log('Registering callback for "%s".' % command )
  34.         else:
  35.             self.log('Callback for %s already registered.' % command )
  36.    
  37.     def datagramReceived(self, data, (host, port)):
  38.    
  39.         options = self.getData(data)
  40.         message = {'event':options[:1][0],'host':host,'port':port,'body':options[1:]}
  41.        
  42.         self.dispatch( message )
  43.    
  44.     def dispatch(self, message ):
  45.     # Main handler for received message
  46.         if message.has_key('event'):
  47.             key = message['event']
  48.             callback = self.commandCallbacks.get( key )
  49.            
  50.             if callback:
  51.                 try:
  52.                     callback(self, message)
  53.                 except Exception, e:
  54.                     self.log('Could\'t dispatch command, data dump: %s, callback address: %s, error: %s' % (message, callback, str(e)))
  55.            
  56.             else:
  57.                 self.log('Unknown packet received. Dump data: %s' % message)
  58.    
  59.     def sendMessage(self, host, port, message):
  60.     # Simple function for writing to socket
  61.         self.transport.write(message,(host,port))
  62.  
  63.     def getData(self, data):
  64.     # Parsing received message
  65.         try:
  66.             result = data.split('|')
  67.         except Exception, error:
  68.             self.log("Some error occured, while processing a message: %s" % error)
  69.         return result
  70.  
  71.  
  72. class t_node(Thread):
  73.    
  74.     def __init__(self, node):
  75.         Thread.__init__(self)
  76.         self.node = node
  77.         self.id = node['id']
  78.         self.channels = {}
  79.        
  80.     def run( self ):
  81.  
  82.         f = manager.AMIFactory(self.node['user'],self.node['password'])
  83.         f.onFailConnection( self.AMIConnectionFail )
  84.  
  85.    
  86.         df = f.login(ip = self.node['host'], port = self.node['port'])
  87.         df.addCallback(self.onLogin)
  88.    
  89.     def AMIConnectionFail(self, connector, reason):
  90.  
  91.         with n_mtx:
  92.             nodes[self.node['id']]['status'] = 'offline'
  93.             nodes[self.node['id']]['protocol'] = None
  94.        
  95.         try:
  96.             reactor.callLater(5, self.run)
  97.         except Exception, error:
  98.             print error
  99.             pass
  100.    
  101.     def onLogin( self, p ):
  102.    
  103.         self.channels = {}
  104.        
  105.         with n_mtx:
  106.             nodes[self.node['id']]['status'] = 'online'
  107.             nodes[self.node['id']]['protocol'] = p
  108.          
  109.         p.registerEvent('Newchannel',self.newchannel)
  110.         p.registerEvent('Hangup',self.hangup)
  111.         p.registerEvent('Dial',self.dial)
  112.         p.registerEvent('Newstate',self.newstate)
  113.         p.registerEvent('NewAccountCode',self.newacct)
  114.  
  115.     def newchannel ( self, p, m ):
  116.    
  117.         chan = m['channel']
  118.         exten = None
  119.         if m['exten'] and not m['exten'] == "s":
  120.             exten = m['exten']
  121.  
  122.         cid_name = m['calleridname']
  123.         cid_num = m['calleridnum']
  124.    
  125.         if not self.channels.has_key( chan ):
  126.             self.channels[chan] = {'name' : chan, 'exten' : exten, 'cid_name' : cid_name, 'cid_num' : cid_num, 'direction' : None, 'state' : None }
  127.    
  128.  
  129.     def dial ( self, p, m ):
  130.    
  131.         if m['subevent'] == "Begin":
  132.             dst = m['destination']
  133.            
  134.             if self.channels.has_key(dst):
  135.                 chan = self.channels[dst]
  136.                 pa = self.channels[m['channel']]
  137.        
  138.                 chan['cid_name'] = pa['cid_name']
  139.                 chan['cid_num'] = pa['cid_num']
  140.                 chan['direction'] = "INPUT"
  141.        
  142.                 # Exten ? for input call we used it!
  143.                 if not chan['exten']:
  144.                     chan['exten'] = pa['exten']
  145.            
  146.                 self.send_stat( p, chan )
  147.            
  148.                 # Transfer
  149.                 if not chan['cid_name'] and not chan['cid_num']:
  150.                     chan['cid_num'] = m['calleridnum']
  151.                     chan['cid_name'] = m['calleridname']
  152.                
  153.                     self.send_stat( p, chan )
  154.    
  155.     def hangup ( self, p, m ):
  156.        
  157.         print nodes[self.node['id']]['thread'].channels
  158.        
  159.         if m['channel'].endswith('<ZOMBIE>'):
  160.             m['channel'] = m['channel'][:len(m['channel'])-len('<ZOMBIE>')]
  161.         chan = m['channel']
  162.         if self.channels.has_key(chan):
  163.             self.channels[chan]['state'] = "Hangup"
  164.             self.send_stat( p, self.channels[chan] )
  165.             del self.channels[chan]
  166.         #print "Removing channel:",chan," from store"
  167.    
  168.     def newstate ( self, p, m ):
  169.        
  170.         if self.channels.has_key( m['channel'] ):
  171.             chan = self.channels[m['channel']]
  172.             chan['state'] = m['channelstatedesc']
  173.  
  174.             if (not chan['exten'] or chan['exten'] == "s") and not chan['cid_num'] and m['calleridnum'] and m['calleridname'] and not chan['direction']:
  175.                 chan['cid_name'] = m['calleridname']
  176.                 chan['cid_num'] = m['calleridnum']
  177.                 chan['direction'] = "INPUT"
  178.            
  179.                 c = m['channel']
  180.                 member = c[c.find('SIP/'):c.find('-')]
  181.                 if member.replace('SIP/','').isdigit():
  182.                     chan['exten'] = member.replace('SIP/','')
  183.  
  184.             if chan['direction']:
  185.                 self.send_stat( p, chan )
  186.                
  187.                
  188.  
  189.     def newacct ( self, p, m ):
  190.         global directions
  191.        
  192.         chan = m['channel']
  193.         if self.channels.has_key(chan) and directions.has_key(m['accountcode']):
  194.        
  195.             if not self.channels[chan]['direction']:
  196.                 self.channels[chan]['direction'] = directions[m['accountcode']]
  197.        
  198.                 chan = self.channels[chan]
  199.                 self.send_stat( p, chan )
  200.  
  201.  
  202.     def send_stat( self, p, m ):
  203.         print m
  204.         if m['exten'] and m['cid_num'] and m['direction'] and m['state']:
  205.             if m['direction'] == "OUTPUT":
  206.                 sendto = m['cid_num']
  207.                 phone = m['exten']
  208.             else:
  209.                 sendto = m['exten']
  210.                 phone = m['cid_num']
  211.                    
  212.             if tapi.users.has_key(sendto):
  213.                 packet = "%s|%s|%s|%s|%s" % ( m['direction'], m['state'].upper(), m['name'], phone,m['cid_name'])
  214.                 with tapi.lock:
  215.                     host = tapi.users[sendto]['host']
  216.                     port = tapi.users[sendto]['port']
  217.                     tapi.sendMessage(host, port, packet)
  218.                 tapi.log('Presence: sendto: %s, call direction: %s, status: %s' % (tapi.users[sendto]['interface'],m['direction'],m['state'].upper()))
  219.                 tapi.log('        channel: %s, Phone: %s, callerID: %s' % (m['name'], phone, m['cid_name']))
  220.  
  221.  
  222. def tapi_reg ( self, msg ):
  223.     options = msg['body']
  224.     try:
  225.         password = options[0]
  226.         interface = options[1]
  227.         phone = interface[interface.find('/')+1:]
  228.         opername = options[2]
  229.     except Exception, error:
  230.         self.log("Unknown packet received, data dump: %s" % error)
  231.  
  232.     if password == tapi_password:  
  233.         with self.lock:
  234.             self.users[phone] = { 'host': msg['host'], 'port' : msg['port'],'opername': opername, 'interface': interface, 'uptime': int(time.time()) }
  235.             self.log("Received new registration from: %s with interface: %s, port: %s" % (msg['host'], interface, msg['port']))
  236.     else:
  237.             tapi.log('Unauthorized access detected for host: %s' % msg['host'])
  238.  
  239. def tapi_qadd ( self, msg ):
  240.     try:
  241.         password = msg['body'][0]
  242.         interface = msg['body'][1]
  243.         queue = msg['body'][2]
  244.         penalty = msg['body'][3]
  245.    
  246.         if password == manager_password:
  247.             node = select_node()
  248.             with node['lock']:
  249.                 self.log('Request for adding to queue: %s interface: %s with penalty: %s // selected node: %s' % (queue, interface, penalty, node['host']))
  250.                 node['protocol'].queueAdd(queue, interface, penalty=penalty, paused=False )
  251.         else:
  252.             self.log('Unauthorized access detected for host: %s' % msg['host'])
  253.     except:
  254.         pass
  255.  
  256. def tapi_qpause( self, msg ):
  257.     try:
  258.         password = msg['body'][0]
  259.         action = msg['body'][1]
  260.         interface = msg['body'][2]
  261.         queue = msg['body'][3]
  262.        
  263.         if action == '0':
  264.             action = False
  265.             ph = 'Unpausing'
  266.         if action == '1':
  267.             action = True
  268.             ph = 'Pausing'
  269.         if password == manager_password:
  270.             node = select_node()
  271.             with node['lock']:    
  272.                 node['protocol'].queuePause(queue,interface, paused = action)
  273.                 self.log('%s interface %s in queue %s // selected node: %s' % (ph, interface, queue, node['host']))
  274.         else:
  275.             self.log('Unauthorized access detected for host: %s' % msg['host'])
  276.     except:
  277.         pass
  278.  
  279. def tapi_qdel ( self, msg ):
  280.     try:
  281.         password = msg['body'][0]
  282.         interface = msg['body'][1]
  283.         queue = msg['body'][2]
  284.        
  285.         if password == manager_password:
  286.             node = select_node()
  287.             with node['lock']:
  288.                 node['protocol'].queueRemove(queue, interface)
  289.                 self.log('Request for deleting interface: %s from queue: %s // selected node: %s' % (interface, queue, node['host']))
  290.         else:
  291.             self.log('Unauthorized access detected for host: %s' % msg['host'])
  292.     except:
  293.         pass
  294.  
  295. def tapi_dial( self, msg ):
  296.     try:
  297.         #print msg
  298.         host = msg['host']
  299.         port = msg['port']
  300.  
  301.         password = msg['body'][0]
  302.         type = msg['body'][1]
  303.         channel = msg['body'][2]
  304.         context = msg['body'][3]
  305.         exten = msg['body'][4]
  306.         priority = '1'
  307.         caller = msg['body'][5]
  308.  
  309.         if type == '0':
  310.             pass
  311.         if type == '1':
  312.             channel = "%sd" % channel
  313.  
  314.         if context == '0':
  315.             context = 'office'
  316.         elif context == '1':
  317.             context = 'operators'
  318.    
  319.         callerid = "%s dialer <%s>" % (caller,exten)
  320.         variable = "SIPADDHEADER=Call-info:\;answer-after=0"
  321.         timeout = "20000"
  322.         async = "n"
  323.        
  324.        
  325.              
  326.        
  327.         if password == manager_password:
  328.             node = select_node()
  329.             with node['lock']:
  330.                 node['protocol'].originate(channel, context=context, exten=exten, priority=priority, timeout=timeout, callerid=callerid, variable=variable, async=async)
  331.                 self.log('Origination %s <%s> context: <%s> from %s (%s:%s) // selected node: %s' % (exten, caller, context, channel, host, port, node['host']))
  332.         else:
  333.             self.log('Unauthorized access detected for host: %s' % msg['host'])
  334.        
  335.     except Exception, error:
  336.         self.log('Unauthorized access to dial command or message looks like shit! %s' % error)
  337.  
  338. def tapi_unreg( self, msg ):
  339.    
  340.     host = msg['host']
  341.     port = msg['port']
  342.     with self.lock:
  343.         for user in self.users:
  344.             try:
  345.                 if self.users[user]['host'] == host and self.users[user]['port'] == port:
  346.                     self.log("Unregistering user:%s with host: %s and port: %s" % (self.users[user]['interface'], host, self.users[user]['port']))
  347.                     del self.users[user]
  348.                     break
  349.             except Exception, error:
  350.                 self.log(error)
  351.  
  352. def tapi_status( self, msg ):
  353.    
  354.     self.log("Status notification received")
  355.     try:
  356.         channel = msg['body'][0]
  357.         for id in nodes:
  358.             if nodes[id]['thread'].channels.has_key(channel):
  359.                 nodes[id]['thread'].send_stat(nodes[id]['protocol'], nodes[id]['thread'].channels[channel])
  360.     except:
  361.         pass
  362.  
  363. def select_node():
  364.     node = None
  365.     while not node:
  366.         with rr['lock']:
  367.             if len(rr['store']) == 0:
  368.                 rr['pool'].reverse()
  369.                 rr['store'] = rr['pool']
  370.                 rr['pool'] = []
  371.             id = rr['store'].pop()
  372.             rr['pool'].append(id)
  373.  
  374.  
  375.         if nodes[id]['status'] == 'online' and nodes[id]['protocol']:
  376.             node = nodes[id]
  377.             return node
  378.    
  379.  
  380. nodes = {}
  381. nodes[1] = {'id' : 1, 'host' : '10.1.3.10', 'port' : 5038, 'user' : 'manager', 'password' : 'klopokakikus', 'status' : 'offline', 'protocol' : None, 'thread' : None}
  382. nodes[2] = {'id' : 2, 'host' : '10.1.3.11', 'port' : 5038, 'user' : 'manager', 'password' : 'klopokakikus', 'status' : 'offline', 'protocol' : None, 'thread' : None}
  383. n_mtx = Lock()
  384.  
  385. rr = {'store' : nodes.keys(), 'pool' : [], 'lock' : Lock() }
  386.  
  387. logfile='/var/log/tapi_tapi.log'
  388. pidfile='/var/run/tapi.pid'
  389. tapi_password = "12345678"
  390. manager_password = "12345678"
  391.  
  392. tapi = TAPI(logfile)
  393. tapi.RegisterCallback('REG',tapi_reg)
  394. tapi.RegisterCallback('UNREG',tapi_unreg)
  395. tapi.RegisterCallback('QADD',tapi_qadd)
  396. tapi.RegisterCallback('QDEL',tapi_qdel)
  397. tapi.RegisterCallback('QPAUSE',tapi_qpause)
  398. tapi.RegisterCallback('DIAL',tapi_dial)
  399. tapi.RegisterCallback('STATUS',tapi_status)
  400.  
  401.  
  402. directions = {'incoming_queue' : 'INPUT', 'incoming_operators' : 'INPUT', 'local_operators' : 'OUTPUT', 'outgoing_operators' : 'OUTPUT' }
  403.  
  404. for id in nodes:
  405.     nodes[id]['thread'] = t_node(nodes[id])
  406.     nodes[id]['lock'] = Lock()
  407.     print dir(nodes[id]['thread'])
  408.     nodes[id]['thread'].start()
  409.  
  410. reactor.listenUDP(5041, tapi)
  411. reactor.run()
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top