You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

202 lines
7.7 KiB

  1. #! /usr/bin/python
  2. # -*- encoding: utf-8 -*-
  3. # (c) 2010-2015 Alexis de Lattre <alexis.delattre@akretion.com>
  4. # (c) 2016 credativ Ltd (<http://credativ.co.uk>).
  5. # (c) 2016 Trever L. Adams
  6. # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
  7. # flake8: noqa: E501
  8. """
  9. Log a call and recording within Asterisk
  10. This is intended to be called by a hangup handler:
  11. Please, note the start is seconds since EPOCH in UTC, it must be UTC.
  12. Example:
  13. [from-pstn-custom]
  14. ...
  15. exten => _X!,n,Set(CHANNEL(hangup_handler_push)=from-pstn-hdlr,s,1(args))
  16. [from-pstn-hdlr]
  17. exten => s,1,Verbose(0, from-pstn-hdlr called)
  18. same => n,Set(odoo_type=incoming)
  19. same => n,Set(odoo_src=${CDR(src)})
  20. same => n,Set(odoo_dst=${CDR(dst)})
  21. same => n,Set(odoo_duration=${CDR(duration)})
  22. same => n,Set(odoo_start=${CDR(start)})
  23. same => n,Set(odoo_filename=${CDR(recordingfile)})
  24. same => n,Set(odoo_uniqueid=${UNIQUEID})
  25. same => n,AGI(/usr/local/bin/asterisk_logcall.sh,${odoo_type},${odoo_src},${odoo_dst},${odoo_duration},${odoo_start},${odoo_filename},${odoo_uniqueid})
  26. same => n,Return()
  27. To test from the CLI:
  28. ./asterisk_logcall.sh << EOF
  29. agi_arg_1: outgoing
  30. agi_arg_2: 875
  31. agi_arg_3: 01234567890
  32. agi_arg_4: 345
  33. agi_arg_5: 1234567890
  34. agi_arg_6: out-875-unknown-20160216-154438-1455637478.61.wav
  35. agi_arg_7: 1455637478.61
  36. agi_arg_8: Description may include things like hangup cause, transfer, automated notes
  37. EOF
  38. """
  39. __author__ = """Craig Gowing <craig.gowing@credativ.co.uk> &
  40. Alexis de Lattre <alexis.delattre@akretion.com>"""
  41. __date__ = "February 2016"
  42. __version__ = "0.2"
  43. import xmlrpclib
  44. import sys
  45. from optparse import OptionParser
  46. # Define command line options
  47. options = [
  48. {'names': ('-s', '--server'), 'dest': 'server', 'type': 'string',
  49. 'action': 'store', 'default': False,
  50. 'help': 'DNS or IP address of the OpenERP server. Default = none '
  51. '(will not try to connect to OpenERP)'},
  52. {'names': ('-p', '--port'), 'dest': 'port', 'type': 'int',
  53. 'action': 'store', 'default': 8069,
  54. 'help': "Port of OpenERP's XML-RPC interface. Default = 8069"},
  55. {'names': ('-e', '--ssl'), 'dest': 'ssl',
  56. 'help': "Use SSL connections instead of clear connections. "
  57. "Default = no, use clear XML-RPC or JSON-RPC",
  58. 'action': 'store_true', 'default': False},
  59. {'names': ('-j', '--jsonrpc'), 'dest': 'jsonrpc',
  60. 'help': "Use JSON-RPC instead of the default protocol XML-RPC. "
  61. "Default = no, use XML-RPC",
  62. 'action': 'store_true', 'default': False},
  63. {'names': ('-d', '--database'), 'dest': 'database', 'type': 'string',
  64. 'action': 'store', 'default': 'openerp',
  65. 'help': "OpenERP database name. Default = 'openerp'"},
  66. {'names': ('-u', '--user-id'), 'dest': 'userid', 'type': 'int',
  67. 'action': 'store', 'default': 2,
  68. 'help': "OpenERP user ID to use when connecting to OpenERP in "
  69. "XML-RPC. Default = 2"},
  70. {'names': ('-t', '--username'), 'dest': 'username', 'type': 'string',
  71. 'action': 'store', 'default': 'demo',
  72. 'help': "OpenERP username to use when connecting to OpenERP in "
  73. "JSON-RPC. Default = demo"},
  74. {'names': ('-w', '--password'), 'dest': 'password', 'type': 'string',
  75. 'action': 'store', 'default': 'demo',
  76. 'help': "Password of the OpenERP user. Default = 'demo'"},
  77. ]
  78. def stdout_write(string):
  79. '''Wrapper on sys.stdout.write'''
  80. sys.stdout.write(string.encode(sys.stdout.encoding or 'utf-8', 'replace'))
  81. sys.stdout.flush()
  82. # When we output a command, we get an answer "200 result=1" on stdin
  83. # Purge stdin to avoid these Asterisk error messages :
  84. # utils.c ast_carefulwrite: write() returned error: Broken pipe
  85. sys.stdin.readline()
  86. return True
  87. def stderr_write(string):
  88. '''Wrapper on sys.stderr.write'''
  89. sys.stderr.write(string.encode(sys.stdout.encoding or 'utf-8', 'replace'))
  90. sys.stdout.flush()
  91. return True
  92. def main(options, arguments):
  93. # AGI passes parameters to the script on standard input
  94. stdinput = {}
  95. while 1:
  96. input_line = sys.stdin.readline()
  97. if not input_line:
  98. break
  99. line = input_line.strip()
  100. try:
  101. variable, value = line.split(':', 1)
  102. except:
  103. break
  104. if variable[:4] != 'agi_': # All AGI parameters start with 'agi_'
  105. stderr_write("bad stdin variable : %s\n" % variable)
  106. continue
  107. variable = variable.strip()
  108. value = value.strip()
  109. if variable and value:
  110. stdinput[variable] = value
  111. stderr_write("full AGI environnement :\n")
  112. for variable in stdinput.keys():
  113. stderr_write("%s = %s\n" % (variable, stdinput.get(variable)))
  114. odoo_type = stdinput.get('agi_arg_1', '')
  115. odoo_src = stdinput.get('agi_arg_2', '')
  116. odoo_dst = stdinput.get('agi_arg_3', '')
  117. odoo_duration = stdinput.get('agi_arg_4', '')
  118. odoo_start = stdinput.get('agi_arg_5', '')
  119. odoo_filename = stdinput.get('agi_arg_6', '')
  120. odoo_uniqueid = stdinput.get('agi_arg_7', '')
  121. odoo_description = stdinput.get('agi_arg_8', '')
  122. method = 'log_call_and_recording'
  123. res = False
  124. # Yes, this script can be used without "-s openerp_server" !
  125. if options.server and options.jsonrpc:
  126. import odoorpc
  127. proto = options.ssl and 'jsonrpc+ssl' or 'jsonrpc'
  128. stdout_write(
  129. 'VERBOSE "Starting %s request on OpenERP %s:%d database '
  130. '%s username %s"\n' % (
  131. proto.upper(), options.server, options.port, options.database,
  132. options.username))
  133. try:
  134. odoo = odoorpc.ODOO(options.server, proto, options.port)
  135. odoo.login(options.database, options.username, options.password)
  136. res = odoo.execute(
  137. 'phone.common', 'log_call_and_recording', odoo_type, odoo_src,
  138. odoo_dst, odoo_duration, odoo_start, odoo_filename,
  139. odoo_uniqueid, odoo_description)
  140. stdout_write('VERBOSE "Called method %s, returned %s"\n' %
  141. (method, res))
  142. except:
  143. stdout_write(
  144. 'VERBOSE "Could not connect to OpenERP in JSON-RPC"\n')
  145. elif options.server:
  146. proto = options.ssl and 'https' or 'http'
  147. stdout_write(
  148. 'VERBOSE "Starting %s XML-RPC request on OpenERP %s:%d '
  149. 'database %s user ID %d"\n' % (
  150. proto, options.server, options.port, options.database,
  151. options.userid))
  152. sock = xmlrpclib.ServerProxy(
  153. '%s://%s:%d/xmlrpc/object'
  154. % (proto, options.server, options.port))
  155. try:
  156. res = sock.execute(
  157. options.database, options.userid, options.password,
  158. 'phone.common', 'log_call_and_recording', odoo_type, odoo_src,
  159. odoo_dst, odoo_duration, odoo_start, odoo_filename,
  160. odoo_uniqueid, odoo_description)
  161. stdout_write('VERBOSE "Called method %s, returned %s"\n' %
  162. (method, res))
  163. except:
  164. stdout_write('VERBOSE "Could not connect to OpenERP in XML-RPC"\n')
  165. return True
  166. if __name__ == '__main__':
  167. usage = "Usage: asterisk_logcall.py [options] login1 login2 login3 ..."
  168. epilog = "Script written by Craig Gowing based on work by Alexis de "
  169. "Lattre. Published under the GNU AGPL licence."
  170. description = "This is an AGI script that sends a query to OpenERP. "
  171. parser = OptionParser(usage=usage, epilog=epilog, description=description)
  172. for option in options:
  173. param = option['names']
  174. del option['names']
  175. parser.add_option(*param, **option)
  176. options, arguments = parser.parse_args()
  177. sys.argv[:] = arguments
  178. main(options, arguments)