14415cbc6ef8c3885210bc613d9ec6cb86caf796
Stefan Schuermans implemnted operator connect...

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) #include <map>
7) #include <string>
8) 
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

9) #include "BoolFile.h"
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

10) #include "Directory.h"
11) #include "File.h"
12) #include "ListTracker.h"
13) #include "ListTracker_impl.h"
14) #include "Mgrs.h"
15) #include "Module.h"
16) #include "NameFile.h"
17) #include "OpConn.h"
18) #include "OpConnIf.h"
19) #include "OpMgr.h"
20) #include "OpSplitter.h"
21) #include "OpSplitterExtension.h"
22) #include "SettingFile.h"
23) #include "Time.h"
24) #include "TimeCallee.h"
Stefan Schuermans limit number of connections...

Stefan Schuermans authored 12 years ago

25) #include "UIntFile.h"
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

26) 
27) namespace Blinker {
28) 
29) /**
30)  * @brief constructor
31)  * @param[in] name module name
32)  * @param[in] mgrs managers
33)  * @param[in] dirBase base directory
34)  */
35) OpSplitter::OpSplitter(const std::string &name, Mgrs &mgrs,
36)                          const Directory &dirBase):
37)   Module(name, mgrs, dirBase),
38)   m_fileSound(dirBase.getFile("sound")),
Stefan Schuermans limit number of connections...

Stefan Schuermans authored 12 years ago

39)   m_fileMaxConn(dirBase.getFile("maxconn")),
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

40)   m_fileSingle(dirBase.getFile("single")),
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

41)   m_extListTracker(*this, dirBase.getSubdir("extensions"))
42) {
43)   // load extensions
44)   m_extListTracker.init();
45) 
46)   // open operator connection interface
47)   m_mgrs.m_opMgr.open(m_name, this);
48) }
49) 
50) /// virtual destructor
51) OpSplitter::~OpSplitter()
52) {
53)   // close operator connection interface
54)   m_mgrs.m_opMgr.close(m_name);
55) 
56)   // close all connections
57)   while (!m_mapLocal.empty()) {
58)     MapLocal::iterator it = m_mapLocal.begin();
59)     it->first->close();
60)     m_mapLocal.erase(it);
61)   }
62)   while (!m_mapInOut.empty()) {
63)     MapInOut::iterator it = m_mapInOut.begin();
64)     it->first->close();
65)     m_mapInOut.erase(it);
66)   }
67)   while (!m_mapOutIn.empty()) {
68)     MapOutIn::iterator it = m_mapOutIn.begin();
69)     it->first->close();
70)     m_mapOutIn.erase(it);
71)   }
72) 
73)   // unload extensions
74)   m_extListTracker.clear();
75) 
76)   // cancel time callback
77)   m_mgrs.m_callMgr.cancelTimeCall(this);
78) }
79) 
80) /// check for update of configuration
81) void OpSplitter::updateConfig()
82) {
83)   // sound name file was modified -> re-read sound name
84)   if (m_fileSound.checkModified())
85)     m_fileSound.update();
86) 
Stefan Schuermans limit number of connections...

Stefan Schuermans authored 12 years ago

87)   // max. number of conn. file was modified -> re-read max. number of conn.
88)   if (m_fileMaxConn.checkModified())
89)     m_fileMaxConn.update();
90) 
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

91)   // single mode config file was modified -> re-read single mode config
92)   if (m_fileSingle.checkModified())
93)     m_fileSingle.update();
94) 
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

95)   // extensions update
96)   m_extListTracker.updateConfig();
97) }
98) 
99) /// callback when requested time reached
100) void OpSplitter::timeCall()
101) {
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

102)   // process pending actions for local connections
103)   MapLocal::iterator it = m_mapLocal.begin();
104)   while (it != m_mapLocal.end()) {
105)     // close connection
106)     if (it->second.m_close) {
107)       MapLocal::iterator itDel = it;
108)       ++it; // we have to increment ourself to make erasing in loop work
109)       itDel->first->close();
110)       m_mapLocal.erase(itDel);
111)       continue; // it already incremented -> skip rest of loop
112)     }
113)     // send sound play request on marked local operator connection
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

114)     if (it->second.m_sendPlay) {
115)       it->second.m_sendPlay = false;
116)       if (m_fileSound.m_valid)
117)         it->first->sendPlay(m_fileSound.m_obj.m_str);
118)     }
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

119)     ++it;
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

120)   }
121) }
122) 
123) /**
124)  * @brief check if accepting new operator connction is possible
125)  * @param[in] name operator interface name
126)  * @return if accepting new connection is possible
127)  */
128) bool OpSplitter::acceptNewOpConn(const std::string &name)
129) {
Stefan Schuermans limit number of connections...

Stefan Schuermans authored 12 years ago

130)   // if maximum number of connections if limited, check it
131)   if (m_fileMaxConn.m_valid &&
132)       m_mapLocal.size() + m_mapInOut.size() >= m_fileMaxConn.m_obj.m_uint)
133)     return false; // too many connection
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

134) 
135)   // single mode
136)   if (m_fileSingle.m_valid && m_fileSingle.m_obj.m_bool) {
137) 
138)     // accept first connection
139)     if (m_mapLocal.empty() && m_mapInOut.empty())
140)       return true;
141) 
142)     // no operator interface selected yet
143)     if (m_singleOp.empty())
144)       return false;
145) 
146)     // additional connections: ask selected operator interface
147)     return m_mgrs.m_opMgr.canConnect(m_singleOp);
148) 
149)   } // if m_fileSingle
150) 
Stefan Schuermans limit number of connections...

Stefan Schuermans authored 12 years ago

151)   return true;
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

152) 
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

153)   (void)name; // unused
154) }
155) 
156) /**
157)  * @brief new operator connection
158)  * @param[in] name operator interface name
159)  * @param[in] pConn operator connection object
160)  *
161)  * The new connection may not yet be used for sending inside this callback.
162)  */
163) void OpSplitter::newOpConn(const std::string &name, OpConn *pConn)
164) {
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

165)   // this is a new incoming connection
166) 
167)   // single mode and not first connection
168)   if (m_fileSingle.m_valid && m_fileSingle.m_obj.m_bool) {
169)     if (!m_mapLocal.empty() || !m_mapInOut.empty()) {
170) 
171)       // try to open outgoiong operator connection to selected operator intf.
172)       OpConn *pOutConn = m_mgrs.m_opMgr.connect(m_singleOp, this);
173)       if (!pOutConn) {
174)         // module is not ready for connection
175)         newLocal(pConn, true); // make conn. a local conn. to be closed soon
176)         return;
177)       }
178) 
179)       // establish connection forwarding
180)       m_mapInOut[pConn] = pOutConn;
181)       m_mapOutIn[pOutConn] = pConn;
182) 
183)       return;
184)     } // if !m_mapLocal.empty() ...
185)   } // if m_fileSingle ...
186) 
187)   // make connection a local connection
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

188)   newLocal(pConn);
189) 
190)   (void)name; // unused
191) }
192) 
193) /**
194)  * @brief key command received on operator connection
195)  * @param[in] pConn operator connection object
196)  * @param[in] key key that was pressed
197)  */
198) void OpSplitter::opConnRecvKey(OpConn *pConn, char key)
199) {
200)   // local connection -> process
201)   MapLocal::iterator itLocal = m_mapLocal.find(pConn);
202)   if (itLocal != m_mapLocal.end()) {
203)     localKey(itLocal, key);
204)     return;
205)   }
206) 
207)   // incoming to outgoing connection -> forward
208)   MapInOut::iterator itInOut = m_mapInOut.find(pConn);
209)   if (itInOut != m_mapInOut.end()) {
210)     itInOut->second->sendKey(key);
211)     return;
212)   }
213) 
214)   // outgoing to incoming connection -> forward
215)   MapOutIn::iterator itOutIn = m_mapOutIn.find(pConn);
216)   if (itOutIn != m_mapOutIn.end()) {
217)     itOutIn->second->sendKey(key);
218)     return;
219)   }
220) }
221) 
222) /**
223)  * @brief play command received on operator connection
224)  * @param[in] pConn operator connection object
225)  * @param[in] sound name of sound to play
226)  */
227) void OpSplitter::opConnRecvPlay(OpConn *pConn, const std::string &sound)
228) {
229)   // play command does not make sense for local connections -> ignore
230) 
231)   // incoming to outgoing connection -> forward
232)   MapInOut::iterator itInOut = m_mapInOut.find(pConn);
233)   if (itInOut != m_mapInOut.end()) {
234)     itInOut->second->sendPlay(sound);
235)     return;
236)   }
237) 
238)   // outgoing to incoming connection -> forward
239)   MapOutIn::iterator itOutIn = m_mapOutIn.find(pConn);
240)   if (itOutIn != m_mapOutIn.end()) {
241)     itOutIn->second->sendPlay(sound);
242)     return;
243)   }
244) }
245) 
246) /**
247)  * @brief operator connection is closed
248)  * @param[in] pConn operator connection object
249)  *
250)  * The connection may not be used for sending any more in this callback.
251)  */
252) void OpSplitter::opConnClose(OpConn *pConn)
253) {
254)   // local connection -> forget this connection
255)   MapLocal::iterator itLocal = m_mapLocal.find(pConn);
256)   if (itLocal != m_mapLocal.end()) {
257)     m_mapLocal.erase(itLocal);
258)     return;
259)   }
260) 
261)   // incoming to outgoing connection -> close outgoing connection as well
262)   MapInOut::iterator itInOut = m_mapInOut.find(pConn);
263)   if (itInOut != m_mapInOut.end()) {
264)     itInOut->second->close();
265)     m_mapOutIn.erase(itInOut->second);
266)     m_mapInOut.erase(itInOut);
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

267)     if (m_mapInOut.empty()) // last connection closed -> no operator intf. sel.
268)       m_singleOp.clear();
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

269)     return;
270)   }
271) 
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

272)   // outgoing to incoming connection
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

273)   MapOutIn::iterator itOutIn = m_mapOutIn.find(pConn);
274)   if (itOutIn != m_mapOutIn.end()) {
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

275)     OpConn * pInConn = itOutIn->second;
276)     m_mapInOut.erase(pInConn);
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

277)     m_mapOutIn.erase(itOutIn);
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

278)     if (m_mapInOut.empty()) // last connection closed -> no operator intf. sel.
279)       m_singleOp.clear();
280)     // single mode and not last connection
281)     if (m_fileSingle.m_valid && m_fileSingle.m_obj.m_bool) {
282)       if (!m_mapLocal.empty() || !m_mapInOut.empty()) {
283)         // close incoming connection as well
284)         pInConn->close();
285)         return;
286)       }
287)     }
288)     // make incoming connection local
289)     newLocal(pInConn);
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

290)     return;
291)   }
292) }
293) 
294) /**
295)  * @brief create new local connection
296)  * @param[in] pConn connection to make local
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

297)  * @param[in] close if to close connection as soon as possible
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

298)  */
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

299) void OpSplitter::newLocal(OpConn *pConn, bool close /* = false */)
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

300) {
301)   // add connection to local connection map
302)   Local &local = m_mapLocal[pConn];
303)   local.m_number.clear(); // no extension dialed so far
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

304)   local.m_sendPlay = !close; // send play command if close not requested
305)   local.m_close = close;
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

306)   m_mgrs.m_callMgr.requestTimeCall(this, Time::now());
307) }
308) 
309) /**
310)  * @brief a key has been pressed for a local connection
311)  * @param[in] itLocal local connection
312)  * @param[in] key the key pressed
313)  */
314) void OpSplitter::localKey(MapLocal::iterator itLocal, char key)
315) {
316)   switch (key) {
317)     // begin new extension number
318)     case '*':
319)       itLocal->second.m_number.clear();
320)       break;
321)     // add digit to extension number
322)     case '0':
323)     case '1':
324)     case '2':
325)     case '3':
326)     case '4':
327)     case '5':
328)     case '6':
329)     case '7':
330)     case '8':
331)     case '9':
332)       itLocal->second.m_number += key;
333)       break;
334)     // close local connection / call extension
335)     case '#':
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

336)       if (itLocal->second.m_number.empty()) {
337)         itLocal->first->close();
338)         m_mapLocal.erase(itLocal);
339)       } else {
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

340)         callExtension(itLocal);
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

341)       }
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

342)       break;
343)   }
344) }
345) 
346) /**
347)  * @brief call extension dialed over local connection
348)  * @param[in] itLocal local connection
349)  */
350) void OpSplitter::callExtension(MapLocal::iterator itLocal)
351) {
352)   // lookup extension
353)   ExtMap::iterator itExt = m_extMap.find(itLocal->second.m_number);
354)   if (itExt == m_extMap.end()) {
355)     // unknown extension -> ignore
356)     itLocal->second.m_number.clear(); // begin new extension number
357)     return;
358)   }
359) 
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

360)   // save selected operator interface for single mode
361)   m_singleOp = itExt->second;
362) 
Stefan Schuermans implemnted operator connect...

Stefan Schuermans authored 12 years ago

363)   // try to open outgoiong operator connection to module
364)   OpConn *pOutConn = m_mgrs.m_opMgr.connect(itExt->second, this);
Stefan Schuermans implemented single mode for...

Stefan Schuermans authored 12 years ago

365)   if (!pOutConn) {