Skip to content

Commit

Permalink
Add DynamicConfig for outgoing faxes (see README.md)
Browse files Browse the repository at this point in the history
  • Loading branch information
Markus Lindenberg committed May 21, 2014
1 parent 15a433d commit 4b28668
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 23 deletions.
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,41 @@ sudo /etc/init.d/hylafax restart
### Logging

GOfax.IP logs everything it does to syslog.

## Advanced Features

As the _virtual modems_ visible in HylaFAX are not tied to preconfigured lines but assigned dynamically, it is not feasible to assign static telephone numbers to individual modems. Instead, GOfax.IP can query a `DynamicConfig` script before trying to send outgoing faxes that works similar to the `DynamicConfig` feature in HylaFAX' `faxgetty`. Using the sender's user id (`owner`), it can be used to set the Callerid, TSI and Header for each individual outgoing fax. It is also possible to reject an outgoing fax.

### DynamicConfig for incoming faxes

`DynamicConfig` as used and documented in HylaFAX can be used by GOfax.IP.
One option per line can be set, comments are note allowed.

**Parameters**
The following arguments are provided to the `DynamicConfig` script for incoming faxes:

* Used modem name
* Caller-ID number
* Caller-ID name
* Destination number (SIP To-User)

**Supported options**
* `RejectCall: true` will reject the call. Default is to allow the call
* `LocalIdentifier: +1 234 567` will assign a CSI (Called Station Identifier) that will be used for this fax reception. The Default CSI can be set in `gofax.conf` in the `ident` parameter.

### DynamicConfig for outgoing faxes

**This is a special feature of GOfax.IP, a similar mechanism does not exist in traditional HylaFAX installations.**

**Parameters**
The following arguments are provided to the `DynamicConfig` script for outgoing faxes:

* Used modem name
* Owner (User ID as set `sendfax -o` or the `FAXUSER` environment variable, optinally verified by PAM)
* Destination number

**Supported options**
* `RejectCall: true` will reject the outgoing fax. The fax will instantly fail and not be retried.
* `LocalIdentifier: +1 234 567` will assign a TSI (Transmitting Station Identifier) for this call. The Default TSI can be set in `gofax.conf` in the `ident` parameter.
* `TagLine: ACME` will assign a header string to be shown on the top of each page. This does not support format strings as used by HylaFAX; if defined a header string is always shown with the current timestamp and page number as set by SpanDSP.
* `FAXNumber: 1337` will set the outgoing caller id number as used by FreeSWITCH when originating the call.
10 changes: 8 additions & 2 deletions config/gofax.conf
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ answerafter = 2000
; Wait after answering before starting fax negotiation
waittime = 1000

; Support for rejecting calls, script has to
;return "RejectCall: true" on stdout
; Support for rejecting calls and setting CSI for incoming faxes
;dynamicconfig = etc/DynamicConfig

[gofaxsend]
; Default outgoing caller id number
faxnumber = 4711

; Support for settings TSI/Header and Callerid for outgoing faxes
;dynamicconfig = etc/DynamicConfigOutgoing
30 changes: 15 additions & 15 deletions src/gofaxd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"os/exec"
"path/filepath"
"strconv"
"strings"
)

const (
Expand Down Expand Up @@ -123,28 +122,29 @@ func (e *EventSocketServer) handler(c *eventsocket.Connection) {
used_device = DEFAULT_DEVICE
}

csi := gofaxlib.Config.Freeswitch.Ident

// Query DynamicConfig
if dc_cmd := gofaxlib.Config.Gofaxd.DynamicConfig; dc_cmd != "" {
logger.Logger.Println("Calling DynamicConfig script", dc_cmd)
dc, err := gofaxlib.DynamicConfig(dc_cmd, used_device, cidnum, cidname, recipient)
if err != nil {
logger.Logger.Println("Error calling DynamicConfig:", err)
} else {
if rejectval := dc.GetFirst("RejectCall"); rejectval != "" {
switch strings.ToLower(rejectval) {
case "true":
fallthrough
case "1":
fallthrough
case "yes":
logger.Logger.Println("DynamicConfig decided to reject this call")
c.Execute("respond", "404", true)
c.Send("exit")
return
}
// Check if call should be rejected
if gofaxlib.DynamicConfigBool(dc.GetFirst("RejectCall")) {
logger.Logger.Println("DynamicConfig decided to reject this call")
c.Execute("respond", "404", true)
c.Send("exit")
return
}
}

// Check if a custom identifier should be set
if dynamic_csi := dc.GetFirst("LocalIdentifier"); dynamic_csi != "" {
csi = dynamic_csi
}

}
}

sessionlog, err := gofaxlib.NewSessionLogger()
Expand Down Expand Up @@ -193,7 +193,7 @@ func (e *EventSocketServer) handler(c *eventsocket.Connection) {

c.Execute("set", "fax_enable_t38_request=true", true)
c.Execute("set", "fax_enable_t38=true", true)
c.Execute("set", fmt.Sprintf("fax_ident=%s", gofaxlib.Config.Freeswitch.Ident), true)
c.Execute("set", fmt.Sprintf("fax_ident=%s", csi), true)
c.Execute("rxfax", filename_abs, true)

result := gofaxlib.NewFaxResult(channel_uuid, sessionlog)
Expand Down
4 changes: 4 additions & 0 deletions src/gofaxlib/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ type config struct {
DynamicConfig string
AllocateInboundDevices bool
}
Gofaxsend struct {
FaxNumber string
DynamicConfig string
}
}

func LoadConfig(filename string) {
Expand Down
29 changes: 24 additions & 5 deletions src/gofaxlib/dynamicconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ type HylaConfig struct {
params []param
}

func NewHylaConfig() *HylaConfig {
return new(HylaConfig)
}

func (h *HylaConfig) GetFirst(tag string) string {
tag = strings.ToLower(tag)
for _, param := range h.params {
if param.Tag == tag {
return param.Value
Expand All @@ -53,30 +58,44 @@ func (h *HylaConfig) GetFirst(tag string) string {
return ""
}

func DynamicConfig(command string, device string, cidnum string, cidname string, recipient string) (*HylaConfig, error) {
if Config.Gofaxd.DynamicConfig == "" {
func DynamicConfig(command string, args ...string) (*HylaConfig, error) {

if command == "" {
return nil, errors.New("No DynamicConfig command provided")
}

cmd := exec.Command(Config.Gofaxd.DynamicConfig, device, cidnum, cidname, recipient)
cmd := exec.Command(command, args...)
out, err := cmd.Output()
if err != nil {
return nil, err
}

h := new(HylaConfig)
h := NewHylaConfig()

scanner := bufio.NewScanner(bytes.NewBuffer(out))
for scanner.Scan() {
parts := strings.SplitN(scanner.Text(), ":", 2)
if len(parts) != 2 {
continue
}
h.params = append(h.params, param{strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])})
h.params = append(h.params, param{strings.ToLower(strings.TrimSpace(parts[0])), strings.TrimSpace(parts[1])})
}
if err = scanner.Err(); err != nil {
return nil, err
}

return h, nil
}

func DynamicConfigBool(value string) (result bool) {
switch strings.ToLower(value) {
case "true":
fallthrough
case "1":
fallthrough
case "yes":
result = true
}

return
}
45 changes: 44 additions & 1 deletion src/gofaxsend/sendqfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func SendQfile(qfilename string) (int, error) {
faxjob := NewFaxJob()

faxjob.Number = qf.GetFirst("number")
faxjob.Cidnum = qf.GetFirst("faxnumber")
faxjob.Cidnum = gofaxlib.Config.Gofaxsend.FaxNumber //qf.GetFirst("faxnumber")
faxjob.Cidname = qf.GetFirst("sender")
faxjob.Ident = gofaxlib.Config.Freeswitch.Ident
faxjob.Header = gofaxlib.Config.Freeswitch.Header
Expand All @@ -68,6 +68,49 @@ func SendQfile(qfilename string) (int, error) {
}
}

// Query DynamicConfig
if dc_cmd := gofaxlib.Config.Gofaxsend.DynamicConfig; dc_cmd != "" {
logger.Logger.Println("Calling DynamicConfig script", dc_cmd)
dc, err := gofaxlib.DynamicConfig(dc_cmd, *device_id, qf.GetFirst("owner"), faxjob.Number)
if err != nil {
errmsg := fmt.Sprintln("Error calling DynamicConfig:", err)
logger.Logger.Println(errmsg)
qf.Set("status", errmsg)
if err = qf.Write(); err != nil {
logger.Logger.Println("Error updating qfile:", err)
}
return SEND_FAILED, errors.New(errmsg)

} else {

// Check if call should be rejected
if gofaxlib.DynamicConfigBool(dc.GetFirst("RejectCall")) {
errmsg := "Transmission rejected by DynamicConfig"
logger.Logger.Println(errmsg)
qf.Set("status", errmsg)
if err = qf.Write(); err != nil {
logger.Logger.Println("Error updating qfile:", err)
}
return SEND_FAILED, errors.New(errmsg)
}

// Check if a custom identifier should be set
if dynamic_tsi := dc.GetFirst("LocalIdentifier"); dynamic_tsi != "" {
faxjob.Ident = dynamic_tsi
}

if tagline := dc.GetFirst("TagLine"); tagline != "" {
faxjob.Header = tagline
}

if faxnumber := dc.GetFirst("FAXNumber"); faxnumber != "" {
faxjob.Cidnum = faxnumber
}

}
}

// Start session
sessionlog, err := gofaxlib.NewSessionLogger()
if err != nil {
return SEND_FAILED, err
Expand Down

0 comments on commit 4b28668

Please sign in to comment.