Example #1
0
// FreeSwitchDBDelete deletes a value from FreeSWITCH's mod_db key/value database
func FreeSwitchDBDelete(c *eventsocket.Connection, realm string, key string) error {
	_, err := c.Send(fmt.Sprintf("api db delete/%s/%s", realm, key))
	if err != nil {
		return err
	}
	return nil
}
Example #2
0
// FreeSwitchDBInsert inserts a value into FreeSWITCH's mod_db key/value database
func FreeSwitchDBInsert(c *eventsocket.Connection, realm string, key string, value string) error {
	_, err := c.Send(fmt.Sprintf("api db insert/%s/%s/%s", realm, key, value))
	if err != nil {
		return err
	}
	return nil
}
Example #3
0
// FreeSwitchDBSelect retreives a value from FreeSWITCH's mod_db key/value database
func FreeSwitchDBSelect(c *eventsocket.Connection, realm string, key string) (string, error) {
	result, err := c.Send(fmt.Sprintf("api db select/%s/%s", realm, key))
	if err != nil {
		return "", err
	}
	return result.Body, nil
}
Example #4
0
// FreeSwitchDBExists checks if a value exists in FreeSWITCH's mod_db key/value database
func FreeSwitchDBExists(c *eventsocket.Connection, realm string, key string) (bool, error) {
	result, err := c.Send(fmt.Sprintf("api db exists/%s/%s", realm, key))
	if err != nil {
		return false, err
	}

	return result.Body == "true", nil
}
Example #5
0
// SetSoftmodemFallback saves the given softmodem fallback setting for a caller id
// to FreeSWITCH's mod_db
func SetSoftmodemFallback(c *eventsocket.Connection, cidnum string, enabled bool) error {
	if !Config.Freeswitch.SoftmodemFallback || cidnum == "" {
		return nil
	}

	var err error
	if c == nil {
		c, err = eventsocket.Dial(Config.Freeswitch.Socket, Config.Freeswitch.Password)
		if err != nil {
			return err
		}
		defer c.Close()
	}

	return FreeSwitchDBInsert(c, modDbFallbackRealm, cidnum, fmt.Sprintf("%d", time.Now().Unix()))
}
Example #6
0
// GetSoftmodemFallback checks if fallback to SpanDSP's softmodem (no T.38)
// should be enabled for the given callerid number
func GetSoftmodemFallback(c *eventsocket.Connection, cidnum string) (bool, error) {
	if !Config.Freeswitch.SoftmodemFallback || cidnum == "" {
		return false, nil
	}

	var err error
	if c == nil {
		c, err = eventsocket.Dial(Config.Freeswitch.Socket, Config.Freeswitch.Password)
		if err != nil {
			return false, err
		}
		defer c.Close()
	}

	exists, err := FreeSwitchDBExists(c, modDbFallbackRealm, cidnum)
	if err != nil {
		return false, err
	}

	return exists, nil
}
Example #7
0
func outboundHandler(c *eventsocket.Connection) {

	r = redis.New()
	r_err = r.Connect(host, port)
	if r_err != nil {
		log.Fatalf("Connect failed: %s\n", r_err.Error())
	}
	log.Println("Connected to redis-server.")

	fmt.Println("new client:", c.RemoteAddr())

	s := Session{}
	s.c = c

	{
		ev, err := c.Send("connect")
		if err != nil {
			fmt.Println("ERROR: ", err)
			return
		}

		s.callerid = ev.Get("Channel-Caller-Id-Number")
		s.callername = ev.Get("Channel-Caller-Id-Name")
		s.inbound_uuid = ev.Get("Channel-Unique-Id")
	}

	c.Send("linger 5")
	c.Execute("answer", "", true)

	go secretaryCallOut(&s)

	c.Execute("playback", "local_stream://moh", true)

	fmt.Println("playback aborted")

	normal_clearing := false
	{
		ev, err := c.Send("api uuid_getvar " + s.inbound_uuid +
			" hangup_cause")
		if err != nil && ev.Body != "" {
			normal_clearing = true
		}
	}

	hup := false

	if s.secretary_uuid == "" {
		hup = true
	} else {
		ev, err := c.Send("api uuid_exists " + s.secretary_uuid)
		if err != nil || ev.Body == "false" {
			hup = true
		} else {
			// secretary is running
			if normal_clearing {
				// abort the secretary
				fmt.Println("Aborting the secretary")
				c.Send("api uuid_kill " + s.secretary_uuid)
			}
		}
	}

	if hup {
		c.Execute("playback", "misc/sorry.wav", true)
		c.Execute("sleep", "500", true)
		c.Execute("hangup", "", false)
		fmt.Println("hup")
	}

	c.Close()
}
Example #8
0
func playAndGetOneDigit(
	sound string,
	c *eventsocket.Connection,
	uuid string) string {

	c.Send("filter Unique-ID " + uuid)
	c.Send("event plain CHANNEL_EXECUTE_COMPLETE")

	{
		_, err := c.ExecuteUUID(
			uuid,
			"play_and_get_digits",
			"1 1 1 400 # "+
				sound+" silence_stream://250 result \\d")
		if err != nil {
			fmt.Println("Error executing play_and_get_digits: ",
				err)
			return ""
		}
	}

	finished := false
	ret := ""

	for !finished {

		ev, err := c.ReadEvent()
		if err != nil {
			finished = true
		} else {
			if ev.Get("Event-Name") ==
				"CHANNEL_EXECUTE_COMPLETE" &&
				ev.Get("Application") == "play_and_get_digits" {
				ret = ev.Get("Variable_result")
				finished = true
			}
		}
	}

	c.Send("noevents")
	c.Send("filter delete Unique-ID " + uuid)

	return ret
}
Example #9
0
func outboundHandler(c *eventsocket.Connection) {

	{
		r = redis.New()
		r_err = r.Connect(host, port)
		if r_err != nil {
			log.Fatalf("Connect failed: %s\n", r_err.Error())
		}
		// log.Println("连接redis服务器.")
	}

	fmt.Println("new client:", c.RemoteAddr())

	s := Session{}
	s.c = c

	{
		ev, err := c.Send("connect")
		if err != nil {
			fmt.Println("ERROR: ", err)
			return
		}

		s.caller_id_number = ev.Get("Channel-Caller-Id-Number")
		s.callername = ev.Get("Channel-Caller-Id-Name")
		s.destination_number = ev.Get("Channel-Destination-Number")
		s.inbound_uuid = ev.Get("Channel-Unique-Id")
		// 根据主被叫确定办公电话,客户电话,客户电话状态和分机号码
		s.office_number_type = "湖南好搜"
		s.custom_number_status = "未知"
		if len(s.caller_id_number) == 4 { //主叫4位,内线外呼
			s.call_direction = "呼出"
			s.subnum = s.caller_id_number
			s.custom_number = s.destination_number
			s.office_number, err = r.HGet("rec:"+s.subnum, "phone")
			if err != nil {
				s.office_number = "82088888"
			}
			// 确定分机所属部门及客户电话状态
			if subnum, _ := r.SIsMember("allusers:100", s.subnum); subnum {
				s.subnum_type = "销售"
				if cnum, _ := r.SIsMember("rec:custom", s.custom_number); cnum {
					s.custom_number_status = "custom"
				}
				if cnum, _ := r.SIsMember("rec:warning", s.custom_number); cnum {
					s.custom_number_status = "warning"
				}
				if cnum, _ := r.SIsMember("rec:bother", s.custom_number); cnum {
					s.custom_number_status = "bother"
				}
			}
		} else if len(s.caller_id_number) > 7 { //主叫7位以上号码,1.外线呼入,被叫是好搜; 2.分公司/客户呼入,被叫是客户; 3.外线呼入,被叫是分公司/客户)
			s.call_direction = "呼入"
			s.custom_number = s.caller_id_number
			s.office_number = s.destination_number
			// 确定办公电话类型
			if cnum, _ := r.SIsMember("phone:hnzby", s.caller_id_number); cnum { //主叫电话为周边云号码
				s.call_direction = "呼出"
				s.custom_number = s.destination_number
				s.office_number = s.caller_id_number
				s.office_number_type = "湖南周边云"
			} else if dnum, _ := r.SIsMember("phone:hnzby", s.destination_number); dnum { //被叫电话位周边云号码
				s.office_number_type = "湖南周边云"
			} else {
				s.subnum, err = r.HGet("rec:phone", s.caller_id_number) //通过办公号码找到分机号
				if err != nil {
					s.subnum = "8888"
				}
			}

		} else { //其他异常号码,转前台
			s.call_direction = "未知"
			s.custom_number_status = "异常"
		}

		// 确定客户电话类型
		s.custom_number = clearNum(s.custom_number)
		if validate(s.custom_number, MOBILE) { //是否手机号码
			if cnum, _ := r.SIsMember("phone:hdata:0731", s.custom_number[0:7]); cnum {
				s.custom_number_type = "本地手机"
			} else {
				s.custom_number_type = "外地手机"
				s.custom_number = "0" + s.custom_number //加0
			}

		} else {
			if s.custom_number[0:1] == "0" {
				s.custom_number_type = "外地固话"
			} else {
				s.custom_number_type = "本地固话"
			}
		}
		r.Quit()
		// log.Println("断开redis服务器.")
	}
	// 录音文件名
	year := time.Now().Format("2006")
	month := time.Now().Format("01")
	day := time.Now().Format("02")
	s.rec_file = fmt.Sprintf("/mnt/stone/%s/%s/%s/%s_%s_%s.wav", year, month, day, s.caller_id_number, s.destination_number, s.inbound_uuid)
	// 流程控制
	// 1. 是否分公司/客户号码,送到相应网关
	// 2. 是否不识别的主/被叫号码(用 call_direction="未知" 来表示)
	// 3. 呼出号码处理
	//    3.1 是否销售分机外呼 --> 是否设置了电话号码状态 --> 播放相应提示语音,DTMF按键 --> 挂机
	//    3.2 不满足上述条件,则直接外呼
	// 4. 呼入号码处理
	//    4.1 是否有对应的分机号码 -->(分机是否在线) --> 直接转分机
	//    4.2 不满足上述条件,转前台总机

	ringback := "ringback=file_string://" + WAIT
	c.Execute("set", ringback, false)
	c.Execute("set", "hangup_after_bridge=true", false)
	// c.Send("linger 5")
	c.Execute("answer", "", true)
	// c.Execute("playback", "local_stream://moh", true)
	cmd := "user/[email protected]"
	if s.office_number_type != "湖南好搜" {
		if s.office_number_type == "湖南周边云" {
			callerIDNumber := "effective_caller_id_number=" + s.caller_id_number
			c.Execute("set", callerIDNumber, false)
			if s.call_direction == "呼入" {
				cmd = "sofia/gateway/hnzby/" + s.destination_number
			} else if s.call_direction == "呼出" {
				cmd = "sofia/gateway/serv36/" + s.destination_number
			}
		}
	} else if s.call_direction == "呼出" {
		if s.subnum_type == "销售" {
			if s.custom_number_status == "warning" || s.custom_number_status == "custom" || s.custom_number_status == "bother" {

				log.Println("销售电话")
				sound := "/usr/share/freeswitch/sounds/" + s.custom_number_status + ".wav"
				c.Execute("playback", sound, true)
				// started := time.Now()
				// digit := ""
				c.Execute("hungup", "", true)
				// for time.Since(started).Seconds() < 60 && digit == "" {

				//	ev, err := c.Send("api uuid_exists " + s.inbound_uuid)
				//	if err != nil || ev.Body == "false" {
				//		break
				//	}

				//	digit = playAndGetOneDigit(
				//		sound,
				//		c, s.inbound_uuid)
				// }

				// if digit != "1" {
				//	c.Send("api uuid_break " + s.inbound_uuid)
				//	c.Close()
				//	return
				//	c.Send("api uuid_break " + s.inbound_uuid)
				c.Close()
				return
			}
		}
		c.Execute("set", "RECORD_ANSWER_REQ=true", false)
		c.Execute("record_session", s.rec_file, false)
		callerIDNumber := "effective_caller_id_number=" + s.office_number
		c.Execute("set", callerIDNumber, false)
		cmd = "{ignore_early_media=false}sofia/gateway/serv36/" + s.custom_number
	} else if s.call_direction == "呼入" {
		c.Execute("set", "RECORD_ANSWER_REQ=true", false)
		c.Execute("record_session", s.rec_file, false)
		cmd = "user/" + s.subnum + "@192.168.36.1"
	} else {
		c.Execute("set", "RECORD_ANSWER_REQ=true", false)
		c.Execute("record_session", s.rec_file, false)
	}

	log.Println(s.caller_id_number, "-->", s.destination_number, s.call_direction, " 分机:", s.subnum, ", 办公电话:", s.office_number, ", 电话所属:", s.office_number_type)

	_, err := c.Execute("bridge", cmd, false)
	if err != nil {
		// hup = true
		log.Println("Error calling out: ", err)
	} else {
		// c.Send("api uuid_break " + s.inbound_uuid) //可能有挂断异常的情况,强行挂断。
		c.Send("api uuid_kill " + s.inbound_uuid)
		log.Println(s.caller_id_number, "-->", s.destination_number, "挂断")
	}

	// go secretaryCallOut(&s)

	// c.Execute("playback", "local_stream://moh", true)

	// fmt.Println("playback aborted")

	// normal_clearing := false
	// {
	//	ev, err := c.Send("api uuid_getvar " + s.inbound_uuid +
	//		" hangup_cause")
	//	if err != nil && ev.Body != "" {
	//		normal_clearing = true
	//	}
	// }

	// hup := false

	// if s.secretary_uuid == "" {
	//	hup = true
	// } else {
	//	ev, err := c.Send("api uuid_exists " + s.secretary_uuid)
	//	if err != nil || ev.Body == "false" {
	//		hup = true
	//	} else {
	//		// secretary is running
	//		if normal_clearing {
	//			// abort the secretary
	//			fmt.Println("Aborting the secretary")
	//			c.Send("api uuid_kill " + s.secretary_uuid)
	//		}
	//	}
	// }

	// if hup {
	//	c.Execute("playback", "misc/sorry.wav", true)
	//	c.Execute("sleep", "500", true)
	//	c.Execute("hangup", "", false)
	//	fmt.Println("hup")
	// }

	c.Close()
}
Example #10
0
func handler(c *eventsocket.Connection) {
	fmt.Println("new client:", c.RemoteAddr())
	c.Send("connect")
	c.Send("myevents")
	c.Execute("answer", "", false)
	ev, err := c.Execute("playback", audioFile, true)
	if err != nil {
		log.Fatal(err)
	}
	ev.PrettyPrint()
	for {
		ev, err = c.ReadEvent()
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println("\nNew event")
		ev.PrettyPrint()
		if ev.Get("Application") == "playback" {
			if ev.Get("Application-Response") == "FILE PLAYED" {
				c.Send("exit")
			}
		}
	}
}
Example #11
0
// Handle incoming call
func (e *EventSocketServer) handler(c *eventsocket.Connection) {
	logger.Logger.Println("Incoming Event Socket connection from", c.RemoteAddr())

	connectev, err := c.Send("connect") // Returns: Ganzer Event mit alles
	if err != nil {
		c.Send("exit")
		logger.Logger.Print(err)
		return
	}

	channelUUID := uuid.Parse(connectev.Get("Unique-Id"))
	if channelUUID == nil {
		c.Send("exit")
		logger.Logger.Print(err)
		return
	}
	defer logger.Logger.Println(channelUUID, "Handler ending")

	// Filter and subscribe to events
	c.Send("linger")
	c.Send(fmt.Sprintf("filter Unique-ID %v", channelUUID))
	c.Send("event plain CHANNEL_CALLSTATE CUSTOM spandsp::rxfaxnegociateresult spandsp::rxfaxpageresult spandsp::rxfaxresult")

	// Extract Caller/Callee
	recipient := connectev.Get("Variable_sip_to_user")
	cidname := connectev.Get("Channel-Caller-Id-Name")
	cidnum := connectev.Get("Channel-Caller-Id-Number")

	logger.Logger.Printf("Incoming call to %v from %v <%v>", recipient, cidname, cidnum)

	var device *Device
	if gofaxlib.Config.Gofaxd.AllocateInboundDevices {
		// Find free device
		device, err := devmanager.FindDevice(fmt.Sprintf("Receiving facsimile"))
		if err != nil {
			logger.Logger.Println(err)
			c.Execute("respond", "404", true)
			c.Send("exit")
			return
		}
		defer device.SetReady()
	}

	var usedDevice string
	if device != nil {
		usedDevice = device.Name
	} else {
		usedDevice = defaultDevice
	}

	csi := gofaxlib.Config.Freeswitch.Ident

	// Query DynamicConfig
	if dcCmd := gofaxlib.Config.Gofaxd.DynamicConfig; dcCmd != "" {
		logger.Logger.Println("Calling DynamicConfig script", dcCmd)
		dc, err := gofaxlib.DynamicConfig(dcCmd, usedDevice, cidnum, cidname, recipient)
		if err != nil {
			logger.Logger.Println("Error calling DynamicConfig:", err)
		} else {
			// 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 dynamicCsi := dc.GetFirst("LocalIdentifier"); dynamicCsi != "" {
				csi = dynamicCsi
			}

		}
	}

	sessionlog, err := gofaxlib.NewSessionLogger()
	if err != nil {
		c.Send("exit")
		logger.Logger.Print(err)
		return
	}

	logger.Logger.Println(channelUUID, "Logging events for commid", sessionlog.CommID(), "to", sessionlog.Logfile())
	sessionlog.Log("Inbound channel UUID: ", channelUUID)

	// Check if T.38 should be disabled
	disableT38 := gofaxlib.Config.Freeswitch.DisableT38
	if disableT38 {
		sessionlog.Log("T.38 disabled by configuration")
	} else {
		disableT38, err = gofaxlib.GetSoftmodemFallback(nil, cidnum)
		if err != nil {
			sessionlog.Log(err)
			disableT38 = false
		}
		if disableT38 {
			sessionlog.Log(fmt.Sprintf("Softmodem fallback active for caller %s, disabling T.38", cidnum))
		}
	}

	sessionlog.Log(fmt.Sprintf("Accepting call to %v from %v <%v> with commid %v", recipient, cidname, cidnum, sessionlog.CommID()))

	if device != nil {
		// Notify faxq
		gofaxlib.Faxq.ModemStatus(device.Name, "I"+sessionlog.CommID())
		gofaxlib.Faxq.ReceiveStatus(device.Name, "B")
		gofaxlib.Faxq.ReceiveStatus(device.Name, "S")
		defer gofaxlib.Faxq.ReceiveStatus(device.Name, "E")
	}

	// Start interacting with the caller

	if gofaxlib.Config.Gofaxd.Answerafter != 0 {
		c.Execute("ring_ready", "", true)
		c.Execute("sleep", strconv.FormatUint(gofaxlib.Config.Gofaxd.Answerafter, 10), true)
	}

	c.Execute("answer", "", true)

	if gofaxlib.Config.Gofaxd.Waittime != 0 {
		c.Execute("playback", "silence_stream://"+strconv.FormatUint(gofaxlib.Config.Gofaxd.Waittime, 10), true)
	}

	// Find filename in recvq to save received .tif
	seq, err := gofaxlib.GetSeqFor(recvqDir)
	if err != nil {
		c.Send("exit")
		sessionlog.Log(err)
		return
	}
	filename := filepath.Join(recvqDir, fmt.Sprintf(recvqFileFormat, seq))
	filenameAbs := filepath.Join(gofaxlib.Config.Hylafax.Spooldir, filename)

	sessionlog.Log("Rxfax to", filenameAbs)

	if disableT38 {
		c.Execute("set", "fax_enable_t38=false", true)
	} else {
		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", csi), true)
	c.Execute("rxfax", filenameAbs, true)

	result := gofaxlib.NewFaxResult(channelUUID, sessionlog)
	es := gofaxlib.NewEventStream(c)

	pages := result.TransferredPages

EventLoop:
	for {
		select {
		case ev := <-es.Events():
			if ev.Get("Content-Type") == "text/disconnect-notice" {
				sessionlog.Log("Received disconnect message")
				//c.Close()
				//break EventLoop
			} else {
				result.AddEvent(ev)
				if result.Hangupcause != "" {
					c.Close()
					break EventLoop
				}

				if pages != result.TransferredPages {
					pages = result.TransferredPages
					if device != nil {
						gofaxlib.Faxq.ReceiveStatus(device.Name, "P")
					}
				}
			}
		case err := <-es.Errors():
			if err.Error() == "EOF" {
				sessionlog.Log("Event socket client disconnected")
			} else {
				sessionlog.Log("Error:", err)
			}
			break EventLoop
		case _ = <-e.killChan:
			sessionlog.Log("Kill reqeust received, destroying channel")
			c.Send(fmt.Sprintf("api uuid_kill %v", channelUUID))
			c.Close()
			return
		}
	}

	if device != nil {
		gofaxlib.Faxq.ReceiveStatus(device.Name, "D")
	}
	sessionlog.Log(fmt.Sprintf("Success: %v, Hangup Cause: %v, Result: %v", result.Success, result.Hangupcause, result.ResultText))

	xfl := gofaxlib.NewXFRecord(result)
	xfl.Modem = usedDevice
	xfl.Filename = filename
	xfl.Destnum = recipient
	xfl.Cidnum = cidnum
	xfl.Cidname = cidname
	if err = xfl.SaveReceptionReport(); err != nil {
		sessionlog.Log(err)
	}

	// If reception failed:
	// Check if softmodem fallback should be enabled on the next call
	if gofaxlib.Config.Freeswitch.SoftmodemFallback && !result.Success {
		var activateFallback bool

		if result.NegotiateCount > 1 {
			// Activate fallback if negotiation was repeated
			sessionlog.Log(fmt.Sprintf("Fax failed with %d negotiations, enabling softmodem fallback for calls from/to %s.", result.NegotiateCount, cidnum))
			activateFallback = true
		} else {
			var badrows uint
			for _, p := range result.PageResults {
				badrows += p.BadRows
			}
			if badrows > 0 {
				// Activate fallback if any bad rows were present
				sessionlog.Log(fmt.Sprintf("Fax failed with %d bad rows in %d pages, enabling softmodem fallback for calls from/to %s.", badrows, result.TransferredPages, cidnum))
				activateFallback = true
			}
		}

		if activateFallback {
			err = gofaxlib.SetSoftmodemFallback(nil, cidnum, true)
			if err != nil {
				sessionlog.Log(err)
			}
		}

	}

	// Process received file
	rcvdcmd := gofaxlib.Config.Gofaxd.FaxRcvdCmd
	if rcvdcmd == "" {
		rcvdcmd = defaultFaxrcvdCmd
	}
	errmsg := ""
	if !result.Success {
		errmsg = result.ResultText
	}

	cmd := exec.Command(rcvdcmd, filename, usedDevice, sessionlog.CommID(), errmsg, cidnum, cidname, recipient)
	sessionlog.Log("Calling", cmd.Path, cmd.Args)
	if output, err := cmd.CombinedOutput(); err != nil {
		sessionlog.Log(cmd.Path, "ended with", err)
		sessionlog.Log(output)
	} else {
		sessionlog.Log(cmd.Path, "ended successfully")
	}

	return
}