69ac12fcb8ee5ac55fadc04d3a96a3a7c2d0038a
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 phone connector module basi...

Stefan Schuermans authored 12 years ago

134) /**
135)  * @brief operator connection is closed
136)  * @param[in] pConn operator connection object
137)  */
138) template<typename ADDR, typename SOCK>
139) void Phone<ADDR, SOCK>::opConnClose(OpConn *pConn)
140) {
141)   // get phone line of connection
142)   ConnLineMap::iterator itConn = m_connLineMap.find(pConn);
143)   if (itConn == m_connLineMap.end())
144)     return;
145)   unsigned int line = itConn->second;
146) 
147)   // send hangup message
148)   sendHangup(line);
149) 
150)   // remove connection from maps
151)   m_connLineMap.erase(itConn);
152)   m_lineConnMap.erase(line);
153) }
154) 
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

155) /// (re-)read server address
156) template<typename ADDR, typename SOCK>
157) void Phone<ADDR, SOCK>::readServer()
158) {
159)   m_fileServer.update();
160) 
161)   // register with new server
162)   sendRegister();
163) }
164) 
165) /// create socket and bind it
166) template<typename ADDR, typename SOCK>
167) void Phone<ADDR, SOCK>::createSock()
168) {
169)   // create socket
170)   if (!m_pSock) {
171)     m_pSock = new SOCK();
172)     if (!m_pSock)
173)       return;
174)   }
175) 
176)   // get bind address from bind address setting file
177)   m_fileBind.update();
178)   if (!m_fileBind.m_valid) {
179)     delete m_pSock;
180)     m_pSock = NULL;
181)     return;
182)   }
183) 
184)   // bind socket
185)   if (!m_pSock->bind(m_fileBind.m_obj)) {
186)     delete m_pSock;
187)     m_pSock = NULL;
188)     return;
189)   }
190) 
191)   // request callback on recepetion
192)   m_mgrs.m_callMgr.requestIoReadCall(this, m_pSock);
193) 
194)   // register with server
195)   sendRegister();
196) }
197) 
198) /// destroy socket
199) template<typename ADDR, typename SOCK>
200) void Phone<ADDR, SOCK>::destroySock()
201) {
202)   // cancel callback request
203)   m_mgrs.m_callMgr.cancelIoReadCall(this, m_pSock);
204) 
205)   // destroy socket
206)   if (m_pSock) {
207)     delete m_pSock;
208)     m_pSock = NULL;
209)   }
210) }
211) 
212) /// register with server
213) template<typename ADDR, typename SOCK>
214) void Phone<ADDR, SOCK>::sendRegister()
215) {
216)   send("0:register");
217) 
218)   // set time for next register message and next heartbeat
219)   m_timeRegister = Time::now() + m_serverTimeout;
220)   m_timeHeartbeat = m_timeRegister + m_heartbeatInterval;
221)   updateTimeCallback();
222) }
223) 
224) /// send heartbeat to server
225) template<typename ADDR, typename SOCK>
226) void Phone<ADDR, SOCK>::sendHeartbeat()
227) {
228)   send("0:heartbeat");
229) 
230)   // set time for next heartbeat
231)   m_timeHeartbeat = Time::now() + m_heartbeatInterval;
232)   updateTimeCallback();
233) }
234) 
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

235) /**
236)  * @brief send hangup message
237)  * @param[in] line number of line to hangup
238)  */
239) template<typename ADDR, typename SOCK>
240) void Phone<ADDR, SOCK>::sendHangup(unsigned int line)
241) {
242)   std::stringstream strm;
243)   strm << line << ":hangup";
244)   send(strm.str());
245) }
246) 
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

247) /**
248)  * @brief send message to server
249)  * @param[in] msg message to send
250)  */
251) template<typename ADDR, typename SOCK>
252) void Phone<ADDR, SOCK>::send(const std::string &msg)
253) {
254)   // check that there is a socket and a server address
255)   if (!m_pSock || !m_fileServer.m_valid)
256)     return;
257) 
258)   // send message
259)   m_pSock->send(msg, m_fileServer.m_obj);
260) }
261) 
262) /// receive data from socket
263) template<typename ADDR, typename SOCK>
264) void Phone<ADDR, SOCK>::receiveFromSock()
265) {
266)   std::string msg;
267)   ADDR addr;
268) 
269)   // make sure socket exists
270)   if (!m_pSock)
271)     return;
272) 
273)   // receive (leave if no reception)
274)   if (!m_pSock->recv(msg, addr))
275)     return;
276) 
277)   // check that packet came from server address
278)   if (!m_fileServer.m_valid || addr != m_fileServer.m_obj)
279)     return; // mismatch
280) 
281)   // reset server timeout
282)   m_timeRegister = Time::now() + m_serverTimeout;
283)   updateTimeCallback();
284) 
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

285)   // process message
286)   serverMsg(msg);
287) }
288) 
289) /**
290)  * @brief process message from server
291)  * @param[in] msg message from server
292)  */
293) template<typename ADDR, typename SOCK>
294) void Phone<ADDR, SOCK>::serverMsg(const std::string &msg)
295) {
296)   // get line number and command
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

298)   unsigned int line;
299)   std::string cmd;
300)   if (!parser.uintNo(line) || !parser.fixChr(':') ||
301)       !parser.untilDelim(":", false, cmd))
302)     return;
303) 
304)   // incoming call
305)   if (cmd == "setup") {
306)     std::string caller, extension;
307)     if (!parser.fixChr(':') || !parser.untilDelim(":", true, caller) ||
308)         !parser.fixChr(':') || !parser.untilDelim(":", false, extension))
309)       return;
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

311)   }
312) 
313)   // hangup
314)   else if (cmd == "onhook") {
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

316)   }
317) 
318)   // DTMF symbol (i.e. key pressed)
319)   else if (cmd == "dtmf") {
320)     char key;
321)     if (!parser.fixChr(':') || !parser.oneChrOf("0123456789*#", key))
322)       return;
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

324)   }
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

325) }
326) 
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

327) /**
328)  * @brief process incoming call
329)  * @param[in] line number of phone line
330)  * @param[in] extension extenstion called (i.e. phone number)
331)  */
332) template<typename ADDR, typename SOCK>
333) void Phone<ADDR, SOCK>::incomingCall(unsigned int line,
334)                                      const std::string &extension)
335) {
336)   // hangup old call on this line (to be on the safe side)
337)   hangup(line);
338) 
339)   // lookup extension
340)   ExtMap::iterator itExt = m_extMap.find(extension);
341)   if (itExt == m_extMap.end())
342)     return; // unknown extension -> ignore
343) 
344)   // try to open operator connection to module
345)   OpConn *pConn = m_mgrs.m_opMgr.connect(itExt->second, this);
346)   if (!pConn) // module is not ready for connection
347)     return;
348) 
349)   // add connection to maps
350)   m_lineConnMap[line] = pConn;
351)   m_connLineMap[pConn] = line;
352) }
353) 
354) /**
355)  * @brief hangup on phone line
356)  * @param[in] line number of phone line
357)  */
358) template<typename ADDR, typename SOCK>
359) void Phone<ADDR, SOCK>::hangup(unsigned int line)
360) {
361)   // get connection
362)   LineConnMap::iterator itLine = m_lineConnMap.find(line);
363)   if (itLine == m_lineConnMap.end())
364)     return; // no connection on this line
365)   OpConn *pConn = itLine->second;
366) 
367)   // close connection
368)   pConn->close();
369) 
370)   // remove connection from maps
371)   m_lineConnMap.erase(itLine);
372)   m_connLineMap.erase(pConn);
373) }
374) 
375) /**
376)  * @brief key pressed on phone line
377)  * @param[in] line number of phone line
378)  * @param[in] key key that has been pressed
379)  */
380) template<typename ADDR, typename SOCK>
381) void Phone<ADDR, SOCK>::keyPressed(unsigned int line, char key)
382) {
383)   // get connection
384)   LineConnMap::iterator itLine = m_lineConnMap.find(line);
385)   if (itLine == m_lineConnMap.end())
386)     return; // no connection on this line
387)   OpConn *pConn = itLine->second;
388) 
389)   // TODO
390)   (void)pConn;
391)   (void)key;
392) }
393)