3fc21e2edcd508f41a1891b542b0154556f4b6ae
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

1) /* Blinker
2)    Copyright 2011 Stefan Schuermans <stefan@blinkenarea.org>
3)    Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
4)    a blinkenarea.org project */
5) 
6) #ifndef BLINKER_PHONE_IMPL_H
7) #define BLINKER_PHONE_IMPL_H
8) 
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

9) #include <sstream>
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

10) #include <string>
11) 
12) #include "Directory.h"
13) #include "File.h"
14) #include "IoCallee.h"
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

15) #include "ListTracker.h"
16) #include "ListTracker_impl.h"
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

17) #include "Mgrs.h"
18) #include "Module.h"
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

19) #include "OpConn.h"
20) #include "OpConnIf.h"
21) #include "OpMgr.h"
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

22) #include "Phone.h"
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

23) #include "PhoneExtension.h"
24) #include "PhoneExtension_impl.h"
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

25) #include "SettingFile.h"
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

26) #include "StringParser.h"
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

27) #include "Time.h"
28) #include "TimeCallee.h"
29) 
30) namespace Blinker {
31) 
32) /**
33)  * @brief constructor
Stefan Schuermans make modules know their name

Stefan Schuermans authored 12 years ago

34)  * @param[in] name module name
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

35)  * @param[in] mgrs managers
36)  * @param[in] dirBase base directory
37)  */
38) template<typename ADDR, typename SOCK>
Stefan Schuermans make modules know their name

Stefan Schuermans authored 12 years ago

39) Phone<ADDR, SOCK>::Phone(const std::string &name, Mgrs &mgrs,
40)                          const Directory &dirBase):
41)   Module(name, mgrs, dirBase),
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

42)   m_fileBind(dirBase.getFile("bind")),
43)   m_fileServer(dirBase.getFile("server")),
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

44)   m_extListTracker(*this, dirBase.getSubdir("extensions")),
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

45)   m_pSock(NULL)
46) {
47)   // read server address
48)   readServer();
49) 
50)   // create and bind socket
51)   createSock();
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

52) 
53)   // load extensions
54)   m_extListTracker.init();
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

55) }
56) 
57) /// virtual destructor
58) template<typename ADDR, typename SOCK>
59) Phone<ADDR, SOCK>::~Phone()
60) {
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

61)   // unload extensions
62)   m_extListTracker.clear();
63) 
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

64)   // close all connections
65)   while (!m_connLineMap.empty()) {
66)     ConnLineMap::iterator it = m_connLineMap.begin();
67)     it->first->close();
68)     sendHangup(it->second);
69)     m_connLineMap.erase(it);
70)   }
71) 
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

72)   // destroy socket
73)   destroySock();
74) 
75)   // cancel time callback
76)   m_mgrs.m_callMgr.cancelTimeCall(this);
77) }
78) 
79) /// check for update of configuration
80) template<typename ADDR, typename SOCK>
81) void Phone<ADDR, SOCK>::updateConfig()
82) {
83)   // bind address file was modified -> re-create socket
84)   if (m_fileBind.checkModified()) {
85)     destroySock();
86)     createSock();
87)   }
88) 
89)   // server address file was modified -> re-read server address
90)   if (m_fileServer.checkModified())
91)     readServer();
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

92) 
93)   // extensions update
94)   m_extListTracker.updateConfig();
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

95) }
96) 
97) /// callback when requested time reached
98) template<typename ADDR, typename SOCK>
99) void Phone<ADDR, SOCK>::timeCall()
100) {
101)   Time now = Time::now();
102) 
103)   // server timeout -> re-register
104)   if (m_timeRegister <= now)
105)     sendRegister();
106) 
107)   // send heartbeat
108)   if (m_timeHeartbeat <= now)
109)     sendHeartbeat();
110) }
111) 
112) /**
113)  * @brief callback when I/O object is readable
114)  * @param[in] io I/O object that is readable
115)  */
116) template<typename ADDR, typename SOCK>
117) void Phone<ADDR, SOCK>::ioReadCall(Io *io)
118) {
119)   // reception on socket
120)   if (io == m_pSock)
121)     receiveFromSock();
122) }
123) 
124) /**
125)  * @brief callback when I/O object is writable
126)  * @param[in] io I/O object that is writable
127)  */
128) template<typename ADDR, typename SOCK>
129) void Phone<ADDR, SOCK>::ioWriteCall(Io *io)
130) {
131)   (void)io; // unused
132) }
133) 
Stefan Schuermans implemented play and key me...

Stefan Schuermans authored 12 years ago

134) /**
135)  * @brief key command received on operator connection
136)  * @param[in] pConn operator connection object
137)  * @param[in] key key that was pressed
138)  */
139) template<typename ADDR, typename SOCK>
140) void Phone<ADDR, SOCK>::opConnRecvKey(OpConn *pConn, char key)
141) {
142)   // the key command does not make sense in this direction, ignore it
143)   (void)pConn; // unused
144)   (void)key; // unused
145) }
146) 
147) /**
148)  * @brief play command received on operator connection
149)  * @param[in] pConn operator connection object
150)  * @param[in] sound name of sound to play
151)  */
152) template<typename ADDR, typename SOCK>
153) void Phone<ADDR, SOCK>::opConnRecvPlay(OpConn *pConn, const std::string &sound)
154) {
155)   // get phone line of connection
156)   unsigned int line;
157)   if (!conn2line(pConn, line))
158)     return;
159) 
160)   // send play message
161)   sendPlay(line, sound);
162) }
163) 
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

164) /**
165)  * @brief operator connection is closed
166)  * @param[in] pConn operator connection object
167)  */
168) template<typename ADDR, typename SOCK>
169) void Phone<ADDR, SOCK>::opConnClose(OpConn *pConn)
170) {
171)   // get phone line of connection
Stefan Schuermans implemented play and key me...

Stefan Schuermans authored 12 years ago

172)   unsigned int line;
173)   if (!conn2line(pConn, line))
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

174)     return;
175) 
176)   // send hangup message
177)   sendHangup(line);
178) 
179)   // remove connection from maps
Stefan Schuermans implemented play and key me...

Stefan Schuermans authored 12 years ago

180)   m_connLineMap.erase(pConn);
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

181)   m_lineConnMap.erase(line);
182) }
183) 
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

184) /// (re-)read server address
185) template<typename ADDR, typename SOCK>
186) void Phone<ADDR, SOCK>::readServer()
187) {
188)   m_fileServer.update();
189) 
190)   // register with new server
191)   sendRegister();
192) }
193) 
194) /// create socket and bind it
195) template<typename ADDR, typename SOCK>
196) void Phone<ADDR, SOCK>::createSock()
197) {
198)   // create socket
199)   if (!m_pSock) {
200)     m_pSock = new SOCK();
201)     if (!m_pSock)
202)       return;
203)   }
204) 
205)   // get bind address from bind address setting file
206)   m_fileBind.update();
207)   if (!m_fileBind.m_valid) {
208)     delete m_pSock;
209)     m_pSock = NULL;
210)     return;
211)   }
212) 
213)   // bind socket
214)   if (!m_pSock->bind(m_fileBind.m_obj)) {
215)     delete m_pSock;
216)     m_pSock = NULL;
217)     return;
218)   }
219) 
220)   // request callback on recepetion
221)   m_mgrs.m_callMgr.requestIoReadCall(this, m_pSock);
222) 
223)   // register with server
224)   sendRegister();
225) }
226) 
227) /// destroy socket
228) template<typename ADDR, typename SOCK>
229) void Phone<ADDR, SOCK>::destroySock()
230) {
231)   // cancel callback request
232)   m_mgrs.m_callMgr.cancelIoReadCall(this, m_pSock);
233) 
234)   // destroy socket
235)   if (m_pSock) {
236)     delete m_pSock;
237)     m_pSock = NULL;
238)   }
239) }
240) 
241) /// register with server
242) template<typename ADDR, typename SOCK>
243) void Phone<ADDR, SOCK>::sendRegister()
244) {
245)   send("0:register");
246) 
247)   // set time for next register message and next heartbeat
248)   m_timeRegister = Time::now() + m_serverTimeout;
249)   m_timeHeartbeat = m_timeRegister + m_heartbeatInterval;
250)   updateTimeCallback();
251) }
252) 
253) /// send heartbeat to server
254) template<typename ADDR, typename SOCK>
255) void Phone<ADDR, SOCK>::sendHeartbeat()
256) {
257)   send("0:heartbeat");
258) 
259)   // set time for next heartbeat
260)   m_timeHeartbeat = Time::now() + m_heartbeatInterval;
261)   updateTimeCallback();
262) }
263) 
Stefan Schuermans implemented play and key me...

Stefan Schuermans authored 12 years ago

264) /**
265)  * @brief send play message
266)  * @param[in] line number of line to request play on
267)  * @param[in] sound name of sound to request
268)  */
269) template<typename ADDR, typename SOCK>
270) void Phone<ADDR, SOCK>::sendPlay(unsigned int line, const std::string &sound)
271) {
272)   std::stringstream strm;
273)   strm << line << ":playbackground:" << sound;
274)   send(strm.str());
275) }
276) 
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

277) /**
278)  * @brief send hangup message
279)  * @param[in] line number of line to hangup
280)  */
281) template<typename ADDR, typename SOCK>
282) void Phone<ADDR, SOCK>::sendHangup(unsigned int line)
283) {
284)   std::stringstream strm;
285)   strm << line << ":hangup";
286)   send(strm.str());
287) }
288) 
Stefan Schuermans accepting EBIP calls works now

Stefan Schuermans authored 12 years ago

289) /**
290)  * @brief send accept message
291)  * @param[in] line number of line accept on
292)  */
293) template<typename ADDR, typename SOCK>
294) void Phone<ADDR, SOCK>::sendAccept(unsigned int line)
295) {
296)   std::stringstream strm;
297)   strm << line << ":accept";
298)   send(strm.str());
299) }
300) 
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

301) /**
302)  * @brief send message to server
303)  * @param[in] msg message to send
304)  */
305) template<typename ADDR, typename SOCK>
306) void Phone<ADDR, SOCK>::send(const std::string &msg)
307) {
308)   // check that there is a socket and a server address
309)   if (!m_pSock || !m_fileServer.m_valid)
310)     return;
311) 
312)   // send message
313)   m_pSock->send(msg, m_fileServer.m_obj);
314) }
315) 
316) /// receive data from socket
317) template<typename ADDR, typename SOCK>
318) void Phone<ADDR, SOCK>::receiveFromSock()
319) {
320)   std::string msg;
321)   ADDR addr;
322) 
323)   // make sure socket exists
324)   if (!m_pSock)
325)     return;
326) 
327)   // receive (leave if no reception)
328)   if (!m_pSock->recv(msg, addr))
329)     return;
330) 
331)   // check that packet came from server address
332)   if (!m_fileServer.m_valid || addr != m_fileServer.m_obj)
333)     return; // mismatch
334) 
335)   // reset server timeout
336)   m_timeRegister = Time::now() + m_serverTimeout;
337)   updateTimeCallback();
338) 
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

339)   // process message
340)   serverMsg(msg);
341) }
342) 
343) /**
344)  * @brief process message from server
345)  * @param[in] msg message from server
346)  */
347) template<typename ADDR, typename SOCK>
348) void Phone<ADDR, SOCK>::serverMsg(const std::string &msg)
349) {
350)   // get line number and command
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

351)   StringParser parser(msg);
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

352)   unsigned int line;
353)   std::string cmd;
354)   if (!parser.uintNo(line) || !parser.fixChr(':') ||
355)       !parser.untilDelim(":", false, cmd))
356)     return;
357) 
358)   // incoming call
359)   if (cmd == "setup") {
360)     std::string caller, extension;
361)     if (!parser.fixChr(':') || !parser.untilDelim(":", true, caller) ||
362)         !parser.fixChr(':') || !parser.untilDelim(":", false, extension))
363)       return;
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

364)     incomingCall(line, extension);
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

365)   }
366) 
367)   // hangup
368)   else if (cmd == "onhook") {
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

369)     hangup(line);
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

370)   }
371) 
372)   // DTMF symbol (i.e. key pressed)
373)   else if (cmd == "dtmf") {
374)     char key;
375)     if (!parser.fixChr(':') || !parser.oneChrOf("0123456789*#", key))
376)       return;
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

377)     keyPressed(line, key);
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

378)   }
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

379) }
380) 
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

381) /**
382)  * @brief process incoming call
383)  * @param[in] line number of phone line
384)  * @param[in] extension extenstion called (i.e. phone number)
385)  */
386) template<typename ADDR, typename SOCK>
387) void Phone<ADDR, SOCK>::incomingCall(unsigned int line,
388)                                      const std::string &extension)
389) {
390)   // hangup old call on this line (to be on the safe side)
391)   hangup(line);
392) 
393)   // lookup extension
394)   ExtMap::iterator itExt = m_extMap.find(extension);
395)   if (itExt == m_extMap.end())
396)     return; // unknown extension -> ignore
397) 
398)   // try to open operator connection to module
399)   OpConn *pConn = m_mgrs.m_opMgr.connect(itExt->second, this);
400)   if (!pConn) // module is not ready for connection
401)     return;
402) 
403)   // add connection to maps
404)   m_lineConnMap[line] = pConn;
405)   m_connLineMap[pConn] = line;
Stefan Schuermans accepting EBIP calls works now

Stefan Schuermans authored 12 years ago

406) 
407)   // send accept message
408)   sendAccept(line);
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

409) }
410) 
411) /**
412)  * @brief hangup on phone line
413)  * @param[in] line number of phone line
414)  */
415) template<typename ADDR, typename SOCK>
416) void Phone<ADDR, SOCK>::hangup(unsigned int line)
417) {
418)   // get connection
Stefan Schuermans implemented play and key me...

Stefan Schuermans authored 12 years ago

419)   OpConn *pConn;
420)   if (!line2conn(line, pConn))
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

421)     return; // no connection on this line
422) 
423)   // close connection
424)   pConn->close();
425) 
426)   // remove connection from maps
Stefan Schuermans implemented play and key me...

Stefan Schuermans authored 12 years ago

427)   m_lineConnMap.erase(line);
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

428)   m_connLineMap.erase(pConn);
429) }
430) 
431) /**
432)  * @brief key pressed on phone line
433)  * @param[in] line number of phone line
434)  * @param[in] key key that has been pressed
435)  */
436) template<typename ADDR, typename SOCK>
437) void Phone<ADDR, SOCK>::keyPressed(unsigned int line, char key)
438) {
439)   // get connection
Stefan Schuermans implemented play and key me...

Stefan Schuermans authored 12 years ago

440)   OpConn *pConn;
441)   if (!line2conn(line, pConn))
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

442)     return; // no connection on this line
443) 
Stefan Schuermans implemented play and key me...

Stefan Schuermans authored 12 years ago

444)   // send key press event over connection
445)   pConn->sendKey(key);
446) }
447) 
448) /**
449)  * @brief get phone line number from operator connection
450)  * @param[in] pConn operator connection object
451)  * @param[out] line phone line number
452)  * @return if phone line was found
453)  */
454) template<typename ADDR, typename SOCK>
455) bool Phone<ADDR, SOCK>::conn2line(OpConn *pConn, unsigned int &line) const
456) {
457)   ConnLineMap::const_iterator itConn = m_connLineMap.find(pConn);
458)   if (itConn == m_connLineMap.end())
459)     return false;
460)   line = itConn->second;
461)   return true;
462) }
463) 
464) /**
465)  * @brief get operator connection from phone line number
466)  * @param[in] line phone line number
467)  * @param[out] pConn operator connection object
468)  * @return if phone line was found
469)  */
470) template<typename ADDR, typename SOCK>
471) bool Phone<ADDR, SOCK>::line2conn(unsigned int line, OpConn *&pConn) const
472) {
473)   LineConnMap::const_iterator itLine = m_lineConnMap.find(line);
474)   if (itLine == m_lineConnMap.end())
475)     return false;
476)   pConn = itLine->second;
477)   return true;
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

478) }
479)