diff --git a/src/mod/languages/mod_managed/managed/examples/easyroute/App.config b/src/mod/languages/mod_managed/managed/examples/easyroute/App.config
new file mode 100644
index 0000000000..214f616f9e
--- /dev/null
+++ b/src/mod/languages/mod_managed/managed/examples/easyroute/App.config
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.fsproj b/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.fsproj
new file mode 100644
index 0000000000..3008e6f083
--- /dev/null
+++ b/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.fsproj
@@ -0,0 +1,87 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {7b5259d4-eaa0-4bcc-9eac-8dc054a4a092}
+ Library
+ fs_easyroute
+ easyroute
+ v3.5
+ EasyRoute
+
+
+ true
+ full
+ false
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ 3
+
+
+ pdbonly
+ true
+ true
+ bin\Release\
+ TRACE
+ 3
+
+
+ false
+
+
+
+
+ 4
+
+
+
+
+
+
+
+ FreeSWITCH.Managed
+ FreeSWITCH.Managed.dll
+ False
+ ..\..\FreeSWITCH.Managed.dll
+ True
+
+
+ FSharp.PowerPack
+ FSharp.PowerPack.dll
+ False
+
+
+
+
+
+ System.Configuration
+ System.configuration.dll
+ False
+
+
+ 3.5
+
+
+ System.Data
+ System.Data.dll
+ False
+
+
+ System.Transactions
+ System.Transactions.dll
+ False
+
+
+
+
+
\ No newline at end of file
diff --git a/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.sln b/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.sln
new file mode 100644
index 0000000000..3d2b6acdae
--- /dev/null
+++ b/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "EasyRoute", "EasyRoute.fsproj", "{7B5259D4-EAA0-4BCC-9EAC-8DC054A4A092}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7B5259D4-EAA0-4BCC-9EAC-8DC054A4A092}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7B5259D4-EAA0-4BCC-9EAC-8DC054A4A092}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7B5259D4-EAA0-4BCC-9EAC-8DC054A4A092}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7B5259D4-EAA0-4BCC-9EAC-8DC054A4A092}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.suo b/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.suo
new file mode 100644
index 0000000000..354e68d201
Binary files /dev/null and b/src/mod/languages/mod_managed/managed/examples/easyroute/EasyRoute.suo differ
diff --git a/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.dll b/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.dll
new file mode 100644
index 0000000000..3665f8c6bb
Binary files /dev/null and b/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.dll differ
diff --git a/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.dll.config b/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.dll.config
new file mode 100644
index 0000000000..214f616f9e
--- /dev/null
+++ b/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.dll.config
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.fs b/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.fs
new file mode 100644
index 0000000000..d3806b4711
--- /dev/null
+++ b/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.fs
@@ -0,0 +1,91 @@
+// To get unixodbc to work on Mono Linux, you may need to create an odbc32.dll link: ln -s /lib64/libodbc.so /lib64/odbc32.dll
+open System
+open System.Data
+open FreeSWITCH
+
+type QueryResult = { dialstring: string; group: string; acctcode: string; limit: int; translated: string }
+
+module easyroute =
+ let getAppSetting (name:string) = match Configuration.ConfigurationManager.AppSettings.Get name with null -> "" | x -> x
+ let connString = getAppSetting "connectionString"
+ let defaultProfile = getAppSetting "defaultProfile"
+ let defaultGateway = getAppSetting "defaultGateway"
+ let query = match getAppSetting "customQuery" with
+ | "" -> "SELECT gateways.gateway_ip, gateways.group, gateways.limit, gateways.techprofile, numbers.acctcode, numbers.translated from gateways, numbers where numbers.number = %number% and numbers.gateway_id = gateways.gateway_id;"
+ | x -> x
+ let configOk = [ connString; defaultProfile; defaultGateway; query; ] |> List.forall (String.IsNullOrEmpty >> not)
+
+ let formatDialstring number gateway profile separator =
+ match separator with
+ | None -> sprintf "%s/%s%s" profile number gateway
+ | Some s -> sprintf "%s/%s%s%s" profile number s gateway
+
+ let getDefaultResult number sep = {
+ dialstring = formatDialstring number defaultGateway defaultProfile sep;
+ limit = 9999; group = ""; acctcode = ""; translated = number; }
+
+ let readResult (r: IDataReader) number sep =
+ let defString def = function null | "" -> def | s -> s
+ let gw = defString defaultGateway <| r.GetString(0)
+ let group = r.GetString(1)
+ let limit = match r.GetInt32(2) with 0 -> 9999 | x -> x
+ let profile = defString defaultProfile <| r.GetString(3)
+ let acctcode = r.GetString(4)
+ let translated = r.GetString(5)
+ let dialstring = formatDialstring number gw profile sep
+ { dialstring = dialstring; limit = limit; group = group; acctcode = acctcode; translated = translated; }
+
+ let lookup (number: string) sep =
+ try
+ let query = query.Replace("%number%", sprintf "'%s'" (number.Replace(@"\'", "'").Replace("'", "''"))) // Don't use params cause some odbc drivers are awesome
+ Log.WriteLine(LogLevel.Debug, "EasyRoute query prepared: {0}", query)
+ use conn = new Odbc.OdbcConnection(connString)
+ use comm = new Odbc.OdbcCommand(query, conn)
+ conn.Open()
+ use reader = comm.ExecuteReader CommandBehavior.SingleRow
+ match reader.Read() with
+ | true -> readResult reader number sep
+ | false -> Log.WriteLine(LogLevel.Error, "No records for {0}; setting default route.", number)
+ getDefaultResult number sep
+ with ex -> Log.WriteLine(LogLevel.Error, "Exception getting route for {0}. Setting default route. Exception: {1}", number, ex.ToString())
+ getDefaultResult number sep
+
+ // Returns tuple: number * separator option * field option
+ let parseArgs args =
+ let args = String.split [' '] args
+ let num = List.hd args
+ let opt = Map.of_list (List.tl args |> List.map (fun x -> match x.Split([|'='|], 2) with
+ | [|n;v|] -> n, Some v
+ | arr -> arr.[0], None))
+ (num, defaultArg (opt.TryFind "separator") (Some "@"), defaultArg (opt.TryFind "field") (None))
+open easyroute
+
+type EasyRoute() =
+ interface ILoadNotificationPlugin with
+ member x.Load() =
+ if not configOk then Log.WriteLine(LogLevel.Alert, "EasyRoute configuration is missing values.")
+ configOk
+
+ interface IApiPlugin with
+ member x.ExecuteBackground ctx =
+ Log.WriteLine(LogLevel.Error, "Background execution not supported for EasyRoute.")
+ member x.Execute ctx =
+ let num, sep, field = parseArgs ctx.Arguments
+ let res = lookup num sep
+ let sw = ctx.Stream.Write
+ match field with
+ | None -> sw "Number \tLimit \tGroup \tAcctCode \tDialstring\n"
+ sw (sprintf "%-10s\t%-10d\t%-10s\t%-10s\t%s\n" res.translated res.limit res.group res.acctcode res.dialstring)
+ | Some "dialstring" -> sw res.dialstring
+ | Some "translated" -> sw res.translated
+ | Some "limit" -> sw (string res.limit)
+ | Some "group" -> sw res.group
+ | Some "acctcode" -> sw res.acctcode
+ | _ -> sw "Invalid input!\n"
+
+ interface IAppPlugin with
+ member x.Run ctx =
+ let num, sep, field = parseArgs ctx.Arguments
+ let res = lookup num sep
+ [ "easy_destnum", res.translated; "easy_dialstring", res.dialstring; "easy_group", res.group; "easy_limit", string res.limit; "easy_acctcode", res.acctcode]
+ |> List.iter ctx.Session.SetVariable
diff --git a/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.pdb b/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.pdb
new file mode 100644
index 0000000000..010b2d60fd
Binary files /dev/null and b/src/mod/languages/mod_managed/managed/examples/easyroute/easyroute.pdb differ