dd3837f23962c8a7a328f96af116dfdb9c45a1bf
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
34)  * @param[in] mgrs managers
35)  * @param[in] dirBase base directory
36)  */
37) template<typename ADDR, typename SOCK>
38) Phone<ADDR, SOCK>::Phone(Mgrs &mgrs, const Directory &dirBase):
39)   Module(mgrs, dirBase),
40)   m_fileBind(dirBase.getFile("bind")),
41)   m_fileServer(dirBase.getFile("server")),
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

322)   }
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

323) }
324) 
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

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