Skip to content

Commit

Permalink
Initial
Browse files Browse the repository at this point in the history
  • Loading branch information
shimaore committed Jul 17, 2015
0 parents commit 782996c
Show file tree
Hide file tree
Showing 12 changed files with 425 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
FreeSwitch CCNQ4 middlewares
34 changes: 34 additions & 0 deletions middleware/cdr.coffee.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
pkg = require '../package.json'
@name = "#{pkg.name}:middleware:cdr"
debug = (require 'debug') @name
@include = ->
@call.once 'CHANNEL_HANGUP_COMPLETE'
.then (res) =>
debug "CDR: Channel Hangup Complete"
data = res.body
debug "CDR: Channel Hangup Complete", billmsec: data.variable_billmsec
data =
duration: data.variable_mduration
billable: data.variable_billmsec
progress: data.variable_progressmsec
answer: data.variable_answermsec
wait: data.variable_waitmsec
progress_media: data.variable_progress_mediamsec
flow_bill: data.variable_flow_billmsec
The `statistics` object is provided by `thinkable-ducks`.

for own k,v of data
@statistics.add k, v
@statistics.emit 'call',
state: 'end'
call: @call.uuid
source: @source
destination: @destination
data: data
return
12 changes: 12 additions & 0 deletions middleware/client/egress/france-3651.coffee.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@include = ->
return unless @session.direction is 'egress'
return unless @session.dialplan is 'national'
return unless @session.country is 'fr'
if m = @res.destination.match /^3651(\d+)$/
@destination = m[1]
Add a `Privacy: id` header.

@action 'privacy', 'number'
130 changes: 130 additions & 0 deletions middleware/client/egress/france.coffee.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
Internally we route french numbers like any international number,
e.g. 33+national number (without the "0" or "E" prefix)
however in France the dialing plan cannot be readily mapped into
the international numbering plan because special codes, etc. in the
national dialing plan do interfere with national prefixes.
(For example, 112 and 3615 are prefixes for geographic numbers.)

On the other hand, in order to be routable all output numbers must
contain digits. However digit 0 cannot be used as the first digit
for a national number, so we use it to prefix special numbers.

For example:
* 3615 (french national dialing plan) is mapped to 3303615 (international numbering plan)
* 112 (french national dialing plan) is mapped to 330112 (international numbering plan)

See http://www.arcep.fr/index.php?id=interactivenumeros

@name = 'france-egress'
@include = ->
return unless @session.direction is 'egress'
return unless @session.dialplan is 'national'
return unless @session.country is 'fr'
Verify that the caller-id follows the proper format
---------------------------------------------------

switch
when $ = @source.match /^(0|\+33)([123456789].{8})$/
@session.ccnq_from_e164 = "33#{$[2]}"
from: international number

when $ = @source.match /^(00|\+)([2-9][0-9]*)$/
@session.ccnq_from_e164 = $[2]
else
return
Verify that the called number follows the proper format
-------------------------------------------------------

International numbers embedded inside the National numbering plan:
decision ARCEP 06-0720

patterns = [
fixes mayotte
match: /^(0|\+33)(26[29].*)$/, now: ($) -> "262#{$[2]}"
mobiles mayotte
match: /^(0|\+33)(639.*)$/, now: ($) -> "262#{$[2]}"
decision ARCEP 06-0535 + 00-0536
mobiles-guadeloupe
match: /^(0|\+33)(690.*)$/, now: ($) -> "590#{$[2]}"
mobiles-reunion
match: /^(0|\+33)(692.*)$/, now: ($) -> "262#{$[2]}"
mobiles-guyane
match: /^(0|\+33)(694.*)$/, now: ($) -> "594#{$[2]}"
mobiles-martinique
match: /^(0|\+33)(696.*)$/, now: ($) -> "596#{$[2]}"
other, fixes
fixes-guadeloupe
match: /^(0|\+33)(590.*)$/, now: ($) -> "590#{$[2]}"
fixes-reunion
match: /^(0|\+33)(262.*)$/, now: ($) -> "262#{$[2]}"
fixes-guyane
match: /^(0|\+33)(594.*)$/, now: ($) -> "594#{$[2]}"
fixes-martinique
match: /^(0|\+33)(596.*)$/, now: ($) -> "596#{$[2]}"
actually fixes and mobiles are mixed. Also the international dialplan is different, see http://www.itu.int/oth/T02020000B2/en
fixes-stpierre
match: /^(0|\+33)(508.*)$/, now: ($) -> $[2]
ARCEP 04-0847
nongeo-guadeloupe
match: /^(0|\+33)(876[01].*)$/, now: ($) -> "590#{$[2]}"
nongeo-reunion
match: /^(0|\+33)(876[23].*)$/, now: ($) -> "262#{$2}"
nongeo-guyane
match: /^(0|\+33)(876[4].*)$/, now: ($) -> "594#{$[2]}"
nongeo-martinique
match: /^(0|\+33)(876[67].*)$/, now: ($) -> "596#{$[2]}"
geographic, non-geographic, mobile, or service
match: /^(0|\+33)([123456789][0-9]{8})$/, now: ($) -> "33#{$[2]}"
special services
match: /^(1[0-9]{1,5}|3[0-9]{3})$/, now: ($) -> "330#{$[1]}"
international call
match: /^(00|\+)([0-9]*)$/, now: ($) -> $[2]
]
for entry in patterns
m = @destination.match entry.match
if m?
@session.ccnq_to_e164 = entry.now m
return
48 changes: 48 additions & 0 deletions middleware/client/egress/post.coffee.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
pkg = require '../../../package.json'
seem = require 'seem'
url = require 'url'
@name = "#{pkg.name}/middleware/client/egress/post"
debug = (require 'debug') @name
assert = require 'assert'
@include = seem ->
return unless @session.direction is 'egress'
assert @cfg.profile_name, 'Missing profile_name'
unless ccnq_from_e164? and ccnq_to_e164?
return @respond 'INVALID_NUMBER_FORMAT'
The URL module parses the SIP username as `auth`.

pci = @req.header 'p-charge-info'
unless pci?
return @respond '403 No Charge-Info'
@session.ccnq_account = (url.parse pci).auth
unless @session.ccnq_account?
return @respond '403 Invalid Charge-Info'
yield @set
These are injected so that they may eventually show up in CDRs.

ccnq_direction: @session.direction
ccnq_account: @session.ccnq_account
ccnq_profile: @cfg.profile_name
ccnq_from_e164: @session.ccnq_from_e164
ccnq_to_e164: @session.ccnq_to_e164
SIP parameters

progress_timeout: 18
call_timeout: 300
effective_caller_id_number: @session.ccnq_from_e164
sip_contact_user: @session.ccnq_from_e164
sip_cid: 'pid'
@export
t38_passthru:true
sip_wait_for_aleg_ack:true
28 changes: 28 additions & 0 deletions middleware/client/egress/pre.coffee.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
First-line handler for outbound calls
-------------------------------------
pkg = require '../package.json'
@name = "#{pkg.name}/middleware/client/egress/pre"
debug = (require 'debug') @name
seem = require 'seem'
@include = seem ->
return unless @session.direction is 'egress'
number_domain = @req.header 'X-CCNQ3-Number-Domain'
unless number_domain?
return @respond '480 Missing X-CCNQ3-Number-Domain'
@session.number_domain = number_domain
endpoint = @req.header 'X-CCNQ3-Endpoint'
unless endpoint?
return @respond '480 Missing X-CCNQ3-Endpoint'
@session.endpoint = endpoint
doc = yield @prov.get "endpoint:#{endpoint}"
@session.endpoint_data = doc
@session.outbound_route = doc.outbound_route
unless @session.outbound_route?
return @respond '500 Endpoint has no outbound_route'
return
11 changes: 11 additions & 0 deletions middleware/client/force-codecs.coffee.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
seem = require 'seem'
@name = 'carrier-egress'
@include = seem ->
m = @data.switch_r_sdp?.match /(.*m=audio \d+ RTP\/AVP)[\d ]*(.*)/
if m?
yield @export
'nolocal:codec_string': 'PCMA@8000h@20i,GSM@8000h@20i'
@set
absolute_codec_string: 'PCMA@8000h@20i,GSM@8000h@20i'
inherit_codec:false
switch_r_sdp: "#{m[1]} 8 101#{m[2]}"
61 changes: 61 additions & 0 deletions middleware/client/ingress/france.coffee.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
seem = require 'seem'
@name = 'france-ingress'
@include = seem ->
return unless @session.direction is 'ingress'
return unless @session.dialplan is 'e164'
Rewrite destination
===================

switch
to: french number

when $ = @destination.match /^33([1-9][0-9]+)$/
@session.ccnq_to_e164 = @destination
@destination = "0#{$[1]}"
@session.country = 'fr'
else
return
Rewrite source
==============

switch
from: national number

when $ = @source.match /^33([0-9]+)$/
@session.ccnq_from_e164 = @source
@source = "0#{$[1]}"
from: international number

when $ = @source.match /^([1-9][0-9]+)$/
@session.ccnq_from_e164 = @source
@source = "00#{$[1]}"
else
return @respond 'INVALID_NUMBER_FORMAT'
Update the dialplan
===================

@session.dialplan = 'national'
Handle privacy request
======================

Privacy: id or other requested privacy

TODO: populate `@session.privacy_hide_number`

if @session.privacy_hide_number
@source = 'anonymous'
yield @action 'privacy', 'full'
yield @set
effective_caller_id_name: '_undef_'
effective_caller_id_number: 'anonymous'
origination_privacy: 'screen+hide_name+hide_number'
45 changes: 45 additions & 0 deletions middleware/client/ingress/post.coffee.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
seem = require 'seem'
@name = 'ingress (client)'
@include = seem ->
return unless @session.direction is 'ingress'
unless @session.dialplan is 'national'
return @respond 'INVALID_NUMBER_FORMAT'
yield @set
These are injected so that they may eventually show up in CDRs.

ccnq_direction: @session.direction
ccnq_account: @session.ccnq_account
ccnq_profile: @cfg.profile_name
ccnq_from_e164: @session.ccnq_from_e164
ccnq_to_e164: @session.ccnq_to_e164
Transfers execute in the context defined in ../conf/refer.

force_transfer_context: 'refer'
Other SIP parameters

progress_timeout:18
call_timeout:300
sip_contact_user: @session.ccnq_from_e164
effective_caller_id_number: @source
sip_cid_type: 'pid'
'sip_h_X-CCNQ3-Number-Domain': @session.number_domain
These should not be forwarded towards customers.

'sip_h_X-CCNQ3-Attrs': null
'sip_h_X-CCNQ3-Endpoint': null
'sip_h_X-CCNQ3-Extra': null
'sip_h_X-CCNQ3-Location': null
'sip_h_X-CCNQ3-Registrant-Password': null
'sip_h_X-CCNQ3-Registrant-Realm': null
'sip_h_X-CCNQ3-Registrant-Target': null
'sip_h_X-CCNQ3-Routing': null
@export
t38_passthru:true
sip_wait_for_aleg_ack:true
7 changes: 7 additions & 0 deletions middleware/client/ingress/pre.coffee.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
This module should be called before 'local/carrier-ingress' and before 'client-sbc/$${profile_type}-ingress'

@name = 'ingress pre (client)'
@include = ->
return unless @session.direction is 'ingress'
@session.ccnq_from_e164 = @source
@session.ccnq_to_e164 = @destination
Loading

0 comments on commit 782996c

Please sign in to comment.