1 /*******************************************************************************
2 
3     KHOMP generic endpoint/channel library.
4     Copyright (C) 2007-2010 Khomp Ind. & Com.
5 
6   The contents of this file are subject to the Mozilla Public License
7   Version 1.1 (the "License"); you may not use this file except in compliance
8   with the License. You may obtain a copy of the License at
9   http://www.mozilla.org/MPL/
10 
11   Software distributed under the License is distributed on an "AS IS" basis,
12   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
13   the specific language governing rights and limitations under the License.
14 
15   Alternatively, the contents of this file may be used under the terms of the
16   "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
17   case the provisions of "LGPL License" are applicable instead of those above.
18 
19   If you wish to allow use of your version of this file only under the terms of
20   the LGPL License and not to allow others to use your version of this file
21   under the MPL, indicate your decision by deleting the provisions above and
22   replace them with the notice and other provisions required by the LGPL
23   License. If you do not delete the provisions above, a recipient may use your
24   version of this file under either the MPL or the LGPL License.
25 
26   The LGPL header follows below:
27 
28     This library is free software; you can redistribute it and/or
29     modify it under the terms of the GNU Lesser General Public
30     License as published by the Free Software Foundation; either
31     version 2.1 of the License, or (at your option) any later version.
32 
33     This library is distributed in the hope that it will be useful,
34     but WITHOUT ANY WARRANTY; without even the implied warranty of
35     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
36     Lesser General Public License for more details.
37 
38     You should have received a copy of the GNU Lesser General Public License
39     along with this library; if not, write to the Free Software Foundation,
40     Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
41 
42 *******************************************************************************/
43 
44 #ifndef _APPLICATIONS_H_
45 #define _APPLICATIONS_H_
46 
47 #include "lock.h"
48 #include "khomp_pvt.h"
49 
50 struct Application
51 {
ApplicationApplication52     Application(Board::KhompPvt * pvt) : _pvt(pvt) {}
~ApplicationApplication53     ~Application() {}
54 
statisticsApplication55     Statistics * statistics() { return _app_statistics; }
56 
57     template <typename T>
statisticsApplication58     T* statistics() { return static_cast<T*>(_app_statistics); }
59 
60     Board::KhompPvt *_pvt;
61     Statistics      *_app_statistics;
62 };
63 
64 /*************************** FAX **********************************************/
65 struct Fax
66 {
FaxFax67     Fax(Board::KhompPvt * pvt) : _pvt(pvt) {}
68 
69     /*
70     bool clear(Board::KhompPvt * pvt)
71     {
72         _pvt = pvt;
73         return true;
74     }
75     */
76 
77     bool adjustForFax();
78 
79     bool sendFax(switch_core_session_t * session, const char *data);
80     bool receiveFax(switch_core_session_t * session, const char *data);
81 
82     bool onFaxChannelRelease(K3L_EVENT *e);
83 
84     bool startFaxTX(const char * orig_addr = NULL);
85     bool stopFaxTX();
86     bool startFaxRX(const char * filename, const char * orig_addr = NULL);
87     bool stopFaxRX();
88     bool addFaxFile(const char * filename, bool last = true);
89 
90 
91     Board::KhompPvt *_pvt;
92 
93     /* used by app FAX */
94     SavedCondition _fax_cond;
95     KFaxResult     _fax_result;
96 
97 };
98 
99 /*************************** TRANSFER *****************************************/
100 template <typename T, bool flash = true>
101 struct Transfer
102 {
TransferTransfer103     Transfer(Board::KhompPvt * pvt) : _pvt(pvt), _is_ok(false) {}
104 
clearTransfer105     bool clear()
106     {
107         if(!_is_ok)
108         {
109             _call = dynamic_cast<T *>(_pvt->call());
110 
111             _is_ok = true;
112 
113             if(!_call)
114             {
115                 DBG(FUNC, D("Error in cast"));
116                 _is_ok = false;
117             }
118         }
119 
120         _call->_flags.clear(Kflags::XFER_DIALING);
121 
122         return true;
123     }
124 
userTransferTransfer125     bool userTransfer(switch_core_session_t * session, const char *data)
126     {
127         DBG(FUNC, PVT_FMT(_pvt->target(), "c"));
128 
129         std::string dest("");
130         std::string opts("");
131 
132         try
133         {
134             Strings::vector_type params;
135 
136             Strings::tokenize((const char *)data, params, "|,", 2);
137 
138             dest = params[0];
139 
140             if (params.size() > 1)
141             {
142                 // other options go here...
143             }
144 
145             ScopedPvtLock lock(_pvt);
146 
147             int timeout = 5;
148 
149             if(!_pvt->call()->_flags.check(Kflags::REALLY_CONNECTED) && !_pvt->loopWhileFlagTimed(Kflags::REALLY_CONNECTED, timeout, false))
150                 return false;
151 
152             DBG(FUNC, PVT_FMT(_pvt->target(), "flashing channel!"));
153 
154             _pvt->command(KHOMP_LOG, CM_FLASH);
155 
156             lock.unlock();
157 
158             timeout = 15; // 15 * 200000 = 3s
159 
160             do
161             {
162                 usleep(200000);
163                 timeout--;
164 
165                 ScopedPvtLock lock2(_pvt);
166 
167                 if(!_pvt->call()->_flags.check(Kflags::IS_INCOMING) && !_pvt->call()->_flags.check(Kflags::IS_OUTGOING))
168                 {
169                     DBG(FUNC, PVT_FMT(_pvt->target(), "unable to do a user transfer, channel disconnected"));
170                     return false;
171                 }
172 
173             }
174             while(timeout);
175 
176             ScopedPvtLock lock3(_pvt);
177 
178             _pvt->command(KHOMP_LOG, CM_DIAL_DTMF, dest.c_str());
179 
180             _pvt->call()->_flags.set(Kflags::WAIT_SEND_DTMF);
181 
182             lock3.unlock();
183 
184             timeout = 300; // 300 * 200000 = 60s
185 
186             do
187             {
188                 usleep(200000);
189                 timeout--;
190 
191                 ScopedPvtLock lock4(_pvt);
192 
193                 if(!_pvt->call()->_flags.check(Kflags::WAIT_SEND_DTMF))
194                     break;
195             }
196             while(timeout);
197 
198         }
199         catch (ScopedLockFailed & err)
200         {
201             LOG(ERROR, PVT_FMT(_pvt->target(),"r (unable to lock %s!)") % err._msg.c_str() );
202             return false;
203         }
204 
205 
206         DBG(FUNC, PVT_FMT(_pvt->target(), "r"));
207         return true;
208     }
209 
210     /* User transfer functions */
doUserXferUnlockedTransfer211     bool doUserXferUnlocked()
212     {
213         DBG(FUNC, PVT_FMT(_pvt->target(), "c (flashing channel!)"));
214 
215         bool ret = false;
216 
217         ret = _pvt->command(KHOMP_LOG, CM_FLASH);
218 
219         DBG(FUNC, PVT_FMT(_pvt->target(), "r (%s)") % (ret ? "true" : "false"));
220         return ret;
221     }
222 
checkUserXferUnlockedTransfer223     bool checkUserXferUnlocked(std::string digit)
224     {
225         DBG(FUNC, PVT_FMT(_pvt->target(), "c (CM_FLASH)"));
226 
227 
228         if (_call->_user_xfer_digits.empty())
229         {
230             _call->_digits_buffer += digit;
231             DBG(FUNC, PVT_FMT(_pvt->target(), "r (disabled)"));
232             return false;
233         }
234 
235         _call->_user_xfer_buffer += digit;
236 
237         /* temporary buffer */
238         std::string tmp = _call->_user_xfer_buffer;
239 
240         unsigned int amount = tmp.size();
241 
242         try
243         {
244 
245         if (amount == _call->_user_xfer_digits.size())
246         {
247             if (tmp == _call->_user_xfer_digits)
248             {
249                 bool ret = doUserXferUnlocked();
250 
251                 _call->_user_xfer_buffer.clear();
252                 _call->_digits_buffer.clear();
253 
254                 Board::board(_pvt->target().device)->_timers.del(_idx_xfer_dial);
255 
256                 DBG(FUNC, PVT_FMT(_pvt->target(), "r (ret=%s, done xfer)") % (ret ? "true" : "false"));
257                 return ret;
258             }
259 
260             _call->_digits_buffer += tmp[0];
261             _call->_user_xfer_buffer.erase(0, 1);
262             DBG(FUNC, PVT_FMT(_pvt->target(), "r (false, no xfer)"));
263             return false;
264         }
265 
266         if (tmp == _call->_user_xfer_digits.substr(0,amount))
267         {
268             if (!(_call->_flags.check(Kflags::XFER_DIALING)))
269             {
270                 _call->_flags.set(Kflags::XFER_DIALING);
271                 _idx_xfer_dial = Board::board(_pvt->target().device)->_timers.add(Opt::_options._transferdigittimeout(), &userXferTimer, _pvt, TM_VAL_CALL);
272             }
273             else
274             {
275                 Board::board(_pvt->target().device)->_timers.restart(_idx_xfer_dial);
276             }
277 
278             DBG(FUNC, PVT_FMT(_pvt->target(), "r (true, buffering)"));
279             return true;
280         }
281 
282         }
283         catch (K3LAPITraits::invalid_device & err)
284         {
285             LOG(ERROR, PVT_FMT(_pvt->target(), "Unable to get device: %d!") % err.device);
286         }
287 
288         _call->_digits_buffer += tmp[0];
289         _call->_user_xfer_buffer.erase(0, 1);
290         DBG(FUNC, PVT_FMT(_pvt->target(), "r (false, buffering)"));
291 
292         return false;
293 
294     }
295 
userXferTimerTransfer296     static void userXferTimer(Board::KhompPvt * pvt)
297     {
298         DBG(FUNC, PVT_FMT(pvt->target(), "c"));
299 
300         T * call = static_cast<T *>(pvt->call());
301 
302         try
303         {
304             ScopedPvtLock lock(pvt);
305 
306             if (!call->_user_xfer_buffer.empty())
307             {
308                 pvt->command(KHOMP_LOG, CM_DIAL_DTMF, call->_user_xfer_buffer.c_str());
309 
310                 /* clear the buffer that has been send */
311                 call->_user_xfer_buffer.clear();
312             }
313 
314             call->_flags.clear(Kflags::XFER_DIALING);
315         }
316         catch (ScopedLockFailed & err)
317         {
318             LOG(ERROR, PVT_FMT(pvt->target(),"r (unable to lock %s!)") % err._msg.c_str() );
319             return;
320         }
321 
322         DBG(FUNC, PVT_FMT(pvt->target(), "r"));
323     }
324 
325     bool                    _is_ok;
326     T *                     _call;
327     Board::KhompPvt *       _pvt;
328     Board::ChanTimer::Index _idx_xfer_dial;
329 };
330 
331 template<typename T>
332 struct Transfer<T, false>
333 {
334     Transfer(Board::KhompPvt * pvt) : _pvt(pvt), _is_ok(false) {}
335 
336     bool clear()
337     {
338         if(!_is_ok)
339         {
340             _call = dynamic_cast<T *>(_pvt->call());
341 
342             _is_ok = true;
343 
344             if(!_call)
345             {
346                 DBG(FUNC, D("Error in cast"));
347                 _is_ok = false;
348             }
349         }
350 
351         _call->_flags.clear(Kflags::XFER_DIALING);
352         _call->_flags.clear(Kflags::XFER_QSIG_DIALING);
353 
354         return true;
355     }
356 
357     bool userTransfer(switch_core_session_t * session, const char *data)
358     {
359         DBG(FUNC, PVT_FMT(_pvt->target(), "c"));
360 
361         std::string dest("");
362 
363         bool opt_nowait = false;
364 
365         try
366         {
367             Strings::vector_type params;
368 
369             Strings::tokenize((const char *)data, params, "|,", 2);
370 
371             dest = params[0];
372 
373             if (params.size() > 1)
374             {
375                 opt_nowait = (params[1].find('n') != std::string::npos);
376 
377                 // other options go here...
378             }
379 
380             ScopedPvtLock lock(_pvt);
381 
382             int timeout = 5;
383 
384             if(!_pvt->call()->_flags.check(Kflags::REALLY_CONNECTED) && !_pvt->loopWhileFlagTimed(Kflags::REALLY_CONNECTED, timeout, false))
385                 return false;
386 
387             DBG(FUNC, PVT_FMT(_pvt->target(), "ss_transfer on channel!"));
388 
389             _pvt->command(KHOMP_LOG, CM_SS_TRANSFER,
390                     STG(FMT("transferred_to=\"%s\" await_connect=\"%d\"")
391                     % dest % (opt_nowait ? 0 : 1)).c_str());
392 
393         }
394         catch (ScopedLockFailed & err)
395         {
396             LOG(ERROR, PVT_FMT(_pvt->target(),"r (unable to lock %s!)") % err._msg.c_str() );
397             return false;
398         }
399 
400 
401         DBG(FUNC, PVT_FMT(_pvt->target(), "r"));
402         return true;
403     }
404 
405     /* User transfer functions */
406     bool doUserXferUnlocked(void)
407     {
408         DBG(FUNC, PVT_FMT(_pvt->target(), "c"));
409 
410         bool ret = false;
411 
412         if (_call->_flags.check(Kflags::XFER_QSIG_DIALING))
413         {
414             DBG(FUNC, PVT_FMT(_pvt->target(), "ss_transfer on channel!"));
415 
416             _call->_flags.clear(Kflags::XFER_DIALING);
417             _call->_flags.clear(Kflags::XFER_QSIG_DIALING);
418 
419             ret = _pvt->command(KHOMP_LOG, CM_SS_TRANSFER,
420                     STG(FMT("transferred_to=\"%s\" await_connect=\"1\"") % _call->_qsig_number).c_str());
421         }
422         else
423         {
424             DBG(FUNC, PVT_FMT(_pvt->target(), "starting to store digits for ss_transfer..."));
425             _call->_flags.set(Kflags::XFER_QSIG_DIALING);
426 
427             _xfer_thread = threadCreate(Transfer<T, false>::userXferPlayback,(void*) _pvt);
428             _xfer_thread->start();
429 
430             ret = true;
431         }
432 
433         DBG(FUNC, PVT_FMT(_pvt->target(), "r (%s)") % (ret ? "true" : "false"));
434         return ret;
435 
436     }
437 
438     bool checkUserXferUnlocked(std::string digit)
439     {
440         DBG(FUNC, PVT_FMT(_pvt->target(), "c (CM_SS_TRANSFER)"));
441 
442 
443         if (_call->_user_xfer_digits.empty())
444         {
445             _call->_digits_buffer += digit;
446             DBG(FUNC, PVT_FMT(_pvt->target(), "r (disabled)"));
447             return false;
448         }
449 
450         _call->_user_xfer_buffer += digit;
451 
452         DBG(FUNC, PVT_FMT(_pvt->target(), "c digits=[%s] buffer=[%s]") % _call->_user_xfer_digits % _call->_user_xfer_buffer );
453 
454         /* temporary buffer */
455         std::string tmp = _call->_user_xfer_buffer;
456 
457         unsigned int amount = tmp.size();
458 
459         try
460         {
461 
462         if (amount == _call->_user_xfer_digits.size())
463         {
464             if (tmp == _call->_user_xfer_digits)
465             {
466                 bool ret = doUserXferUnlocked();
467 
468                 _call->_user_xfer_buffer.clear();
469                 _call->_qsig_number.clear();
470                 _call->_digits_buffer.clear();
471 
472                 if(!_call->_flags.check(Kflags::XFER_QSIG_DIALING))
473                 {
474                     Board::board(_pvt->target().device)->_timers.del(_idx_xfer_dial);
475 
476                     DBG(FUNC, PVT_FMT(_pvt->target(), "r (ret=%s, done xfer)") % (ret ? "true" : "false"));
477                 }
478                 else
479                 {
480                     Board::board(_pvt->target().device)->_timers.restart(_idx_xfer_dial);
481                     DBG(FUNC, PVT_FMT(_pvt->target(), "r (waiting digits for transfer)"));
482                 }
483                 return ret;
484             }
485 
486             if (_call->_flags.check(Kflags::XFER_QSIG_DIALING))
487             {
488                 DBG(FUNC, PVT_FMT(_pvt->target(), "putting digits ('%s') on transfer-to number!") % tmp);
489 
490                 _call->_qsig_number += tmp[0];
491                 _call->_user_xfer_buffer.erase(0, 1);
492                 Board::board(_pvt->target().device)->_timers.restart(_idx_xfer_dial);
493 
494                 DBG(FUNC, PVT_FMT(_pvt->target(), "r (true, qsig transfer)"));
495                 return true;
496             }
497 
498             _call->_digits_buffer += tmp[0];
499             _call->_user_xfer_buffer.erase(0, 1);
500             DBG(FUNC, PVT_FMT(_pvt->target(), "r (false, no qsig)"));
501             return false;
502         }
503 
504         if (tmp == _call->_user_xfer_digits.substr(0,amount))
505         {
506             if (!(_call->_flags.check(Kflags::XFER_DIALING) || _call->_flags.check(Kflags::XFER_QSIG_DIALING)))
507             {
508                 _call->_flags.set(Kflags::XFER_DIALING);
509                 _idx_xfer_dial = Board::board(_pvt->target().device)->_timers.add(Opt::_options._transferdigittimeout(), &userXferTimer, _pvt, TM_VAL_CALL);
510             }
511             else
512             {
513                 Board::board(_pvt->target().device)->_timers.restart(_idx_xfer_dial);
514             }
515 
516             DBG(FUNC, PVT_FMT(_pvt->target(), "r (true, buffering)"));
517             return true;
518         }
519 
520         if (_call->_flags.check(Kflags::XFER_QSIG_DIALING))
521         {
522             DBG(FUNC, PVT_FMT(_pvt->target(), "putting digits ('%s') on transfer-to number!") % tmp);
523 
524             _call->_qsig_number += tmp[0];
525             _call->_user_xfer_buffer.erase(0, 1);
526 
527             Board::board(_pvt->target().device)->_timers.restart(_idx_xfer_dial);
528             DBG(FUNC, PVT_FMT(_pvt->target(), "r (true, qsig buffering)"));
529             return true;
530         }
531 
532         }
533         catch (K3LAPITraits::invalid_device & err)
534         {
535             LOG(ERROR, PVT_FMT(_pvt->target(), "Unable to get device: %d!") % err.device);
536         }
537 
538         _call->_digits_buffer += tmp[0];
539         _call->_user_xfer_buffer.erase(0, 1);
540         DBG(FUNC, PVT_FMT(_pvt->target(), "r (false, buffering)"));
541 
542         return false;
543     }
544 
545     static void userXferTimer(Board::KhompPvt * pvt)
546     {
547         DBG(FUNC, PVT_FMT(pvt->target(), "c"));
548 
549         T * call = static_cast<T *>(pvt->call());
550 
551         try
552         {
553             ScopedPvtLock lock(pvt);
554 
555             if (!call->_user_xfer_buffer.empty())
556             {
557                 pvt->command(KHOMP_LOG, CM_DIAL_DTMF, call->_user_xfer_buffer.c_str());
558 
559                 /* clear the buffer that has been send */
560                 call->_user_xfer_buffer.clear();
561             }
562 
563             if (!call->_qsig_number.empty())
564             {
565                 pvt->command(KHOMP_LOG, CM_SS_TRANSFER,
566                         STG(FMT("transferred_to=\"%s\" await_connect=\"1\"") % call->_qsig_number).c_str());
567 
568                 /* clear the buffer that has been send */
569                 call->_qsig_number.clear();
570             }
571 
572             call->_flags.clear(Kflags::XFER_DIALING);
573             call->_flags.clear(Kflags::XFER_QSIG_DIALING);
574         }
575         catch (ScopedLockFailed & err)
576         {
577             LOG(ERROR, PVT_FMT(pvt->target(),"r (unable to lock %s!)") % err._msg.c_str() );
578             return;
579         }
580 
581         DBG(FUNC, PVT_FMT(pvt->target(), "r"));
582     }
583 
584     static switch_status_t dtmfCallback(switch_core_session_t *session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen)
585     {
586         char sbuf[3];
587 
588         if(!session)
589         {
590             DBG(FUNC,D("session is NULL"))
591                 return SWITCH_STATUS_FALSE;
592         }
593 
594         switch_channel_t * chan = switch_core_session_get_channel(session);
595 
596         if(!chan)
597         {
598             DBG(FUNC,D("channel is NULL"))
599                 return SWITCH_STATUS_FALSE;
600         }
601 
602         switch_core_session_t *peer_session = switch_core_session_locate(switch_channel_get_partner_uuid(chan));
603 
604         if(!peer_session)
605         {
606             DBG(FUNC,D("session is NULL"))
607                 return SWITCH_STATUS_FALSE;
608         }
609 
610         switch (itype)
611         {
612             case SWITCH_INPUT_TYPE_DTMF:
613             {
614                 switch_dtmf_t *dtmf = (switch_dtmf_t *) input;
615 
616                 Board::KhompPvt * tech_pvt = static_cast< Board::KhompPvt* >(switch_core_session_get_private(peer_session));
617                 if(!tech_pvt)
618                 {
619                     DBG(FUNC,D("Init: pvt is NULL"))
620                     switch_core_session_rwunlock(peer_session);
621                     return SWITCH_STATUS_FALSE;
622                 }
623 
624                 char s[] = { dtmf->digit, '\0' };
625                 tech_pvt->sendDtmf(s);
626 
627                 break;
628             }
629             default:
630                 break;
631         }
632 
633         switch_core_session_rwunlock(peer_session);
634         return SWITCH_STATUS_SUCCESS;
635     }
636 
637 
638     static int userXferPlayback(void * pvt_ptr)
639     {
640         /* get pointer... */
641         Board::KhompPvt * pvt = static_cast < Board::KhompPvt * > (pvt_ptr);
642 
643         DBG(FUNC, PVT_FMT(pvt->target(), "c"));
644 
645         try
646         {
647             ScopedPvtLock lock(pvt);
648 
649             /* get the owner */
650             switch_channel_t * chan = pvt->getFSChannel();
651 
652             /* get other side of the bridge */
653             switch_core_session_t * peer_session = NULL;
654             switch_core_session_get_partner(pvt->session(),&peer_session);
655 
656             if(!peer_session)
657             {
658                 DBG(FUNC, PVT_FMT(pvt->target(), "r (session is null)"));
659                 return NULL;
660             }
661 
662             switch_channel_t * peer = switch_core_session_get_channel(peer_session);
663 
664             /* put the channel in hold */
665             //switch_core_session_t *session = switch_core_session_locate(switch_channel_get_partner_uuid(chan));
666             //switch_channel_t *chan_core = switch_core_session_get_channel(session);
667 
668             const char *stream;
669 
670             if (!(stream = switch_channel_get_variable(chan, SWITCH_HOLD_MUSIC_VARIABLE)))
671             {
672                 stream = "silence";
673             }
674 
675             DBG(FUNC, PVT_FMT(pvt->target(), "stream=%s") % stream);
676 
677             if (stream && strcasecmp(stream, "silence"))
678             {
679                 /* Freeswitch not get/put frames */
680                 //switch_channel_set_flag(channel, CF_HOLD);
681                 switch_ivr_broadcast(switch_core_session_get_uuid(pvt->session()),stream, SMF_ECHO_ALEG | SMF_LOOP | SMF_PRIORITY);
682             }
683 
684             switch_core_session_rwunlock(peer_session);
685             lock.unlock();
686 
687             /* kickstart my heart */
688             switch_input_args_t args = {0};
689             args.input_callback = dtmfCallback;
690 
691             /* wait while xfering... */
692             while (true)
693             {
694                 switch_ivr_collect_digits_callback(peer_session,&args,1000,0);
695                 ScopedPvtLock lock2(pvt);
696 
697                 if (!pvt->call()->_flags.check(Kflags::XFER_QSIG_DIALING))
698                 {
699                     break;
700                 }
701 
702                 lock2.unlock();
703             }
704 
705             //switch_channel_clear_flag(channel, CF_HOLD);
706 
707             switch_channel_stop_broadcast(chan);
708             switch_channel_wait_for_flag(chan, CF_BROADCAST, SWITCH_FALSE, 5000, NULL);
709             switch_core_session_rwunlock(pvt->session());
710             switch_core_session_rwunlock(peer_session);
711 
712             //switch_ivr_unhold_uuid(switch_channel_get_partner_uuid(chan));
713         }
714         catch (ScopedLockFailed & err)
715         {
716             LOG(ERROR, PVT_FMT(pvt->target(),"r (unable to lock %s!)") % err._msg.c_str() );
717             return NULL;
718         }
719         catch (Board::KhompPvt::InvalidSwitchChannel & err)
720         {
721             LOG(ERROR, PVT_FMT(pvt->target(), "r (%s)") % err._msg.c_str() );
722             return NULL;
723         }
724 
725         DBG(FUNC, PVT_FMT(pvt->target(), "r"));
726 
727         return NULL;
728     }
729 
730     bool                    _is_ok;
731     T *                     _call;
732     Board::KhompPvt *       _pvt;
733     Thread *                _xfer_thread;
734     Board::ChanTimer::Index _idx_xfer_dial;
735 };
736 
737 /*************************** SMS **********************************************/
738 #define ESL_SMS_RECEIVED "khomp::sms_received"
739 #define ESL_SMS_SENT     "khomp::sms_sent"
740 
741 struct SMS : public Application
742 {
743     typedef std::list< switch_core_session_t *> OwnersList;
744 
745     struct SMSStatistics : public Statistics
746     {
747         SMSStatistics():
748             _sms_number_incoming(0),
749             _sms_number_outgoing(0),
750             _sms_number_confirm(0),
751             _sms_number_broadcast(0) {};
752 
753         void incrementIncoming()
754         {
755             _sms_number_incoming++;
756         }
757 
758         void incrementOutgoing()
759         {
760             _sms_number_outgoing++;
761         }
762 
763         void incrementConfirm()
764         {
765             _sms_number_confirm++;
766         }
767 
768         void incrementBroadcast()
769         {
770             _sms_number_broadcast++;
771         }
772 
773         std::string getDetailed()
774         {
775             std::string tmpBuffer;
776 
777             tmpBuffer.append(STG(FMT("Number of incoming SMS: \t%d\n")  % _sms_number_incoming));
778             tmpBuffer.append(STG(FMT("Number of outgoing SMS: \t%d\n")  % _sms_number_outgoing));
779             tmpBuffer.append(STG(FMT("Number of broadcast SMS: \t%d\n") % _sms_number_broadcast));
780             tmpBuffer.append(STG(FMT("Number of confirm SMS:  \t%d\n")  % _sms_number_confirm));
781 
782             return tmpBuffer;
783         }
784 
785         void clear()
786         {
787             _sms_number_incoming  = 0;
788             _sms_number_outgoing  = 0;
789             _sms_number_confirm   = 0;
790             _sms_number_broadcast = 0;
791         }
792 
793         unsigned int _sms_number_incoming;
794         unsigned int _sms_number_outgoing;
795         unsigned int _sms_number_confirm;
796         unsigned int _sms_number_broadcast;
797     };
798 
799     SMS(Board::KhompPvt * pvt) :
800     Application(pvt),
801     _thread(NULL),
802     _shutdown(false),
803     _can_receive(false),
804     _can_send(false),
805     _result(0),
806     _mutex(Globals::module_pool),
807     _cond(Globals::module_pool),
808     _buffer(8)
809     {
810         _cond.reset();
811         _app_statistics = new SMSStatistics();
812     }
813 
814     ~SMS()
815     {
816         stop();
817         delete _app_statistics;
818     }
819 
820     struct ReceiveData
821     {
822         ReceiveData() {};
823 
824         ReceiveData(const ReceiveData & o)
825         {
826             _type    = o._type;
827             _from    = o._from;
828             _date    = o._date;
829             _size    = o._size;
830             _coding  = o._coding;
831             _serial  = o._serial;
832             _id      = o._id;
833             _page    = o._page;
834             _pages   = o._pages;
835             _sc_date = o._sc_date;
836             _status  = o._status;
837             _body    = o._body;
838         };
839 
840         void clear(void)
841         {
842             /* reset data stuff */
843             _type.clear();
844             _from.clear();
845             _date.clear();
846             _size.clear();
847             _coding.clear();
848             _serial.clear();
849             _id.clear();
850             _page.clear();
851             _pages.clear();
852             _sc_date.clear();
853             _status.clear();
854             _body.clear();
855         };
856 
857         std::string _type;
858         std::string _from;
859         std::string _date;
860         std::string _size;
861         std::string _coding;
862         std::string _serial;
863         std::string _id;
864         std::string _page;
865         std::string _pages;
866         std::string _sc_date;
867         std::string _status;
868         std::string _body;
869     };
870 
871     struct SendData
872     {
873         SendData(): _conf(false) {};
874 
875         SendData(const SendData & o)
876         {
877             _dest    = o._dest;
878             _body    = o._body;
879             _conf    = o._conf;
880         };
881 
882         void clear(void)
883         {
884             /* reset data stuff */
885             _dest.clear();
886             _body.clear();
887             _conf = false;
888         };
889 
890         std::string _dest;
891         std::string _body;
892         bool        _conf;
893     };
894 
895     static struct _SMSEvent : public ESL
896     {
897 
898         _SMSEvent() : ESL("khomp::sms")
899         {
900             if(_events)
901             {
902                 _events->push_back(ESL_SMS_RECEIVED);
903                 _events->push_back(ESL_SMS_SENT);
904             }
905         }
906 
907         ~_SMSEvent()
908         {
909             if(_events)
910             {
911                 //Remove two from vector
912                 _events->pop_back();
913                 _events->pop_back();
914             }
915         }
916 
917         bool operator()(Board::KhompPvt * pvt, ReceiveData & data)
918         {
919             switch_event_t *event = create(ESL_SMS_RECEIVED);
920 
921             if(!event)
922             {
923                 LOG(ERROR, "Cannot create SMS ESL");
924                 return false;
925             }
926 
927             add(event, pvt->target());
928             add(event, "Type", data._type);
929             add(event, "From", data._from);
930             add(event, "Date", data._date);
931             add(event, "Size", data._size);
932             add(event, "Coding", data._coding);
933             add(event, "Serial", data._serial);
934             add(event, "Id", data._id);
935             add(event, "Page", data._page);
936             add(event, "Pages", data._pages);
937             add(event, "Sc_date", data._sc_date);
938             add(event, "Status", data._status);
939             add(event, "Body", data._body);
940 
941             return fire(&event);
942         }
943 
944         bool operator()(Board::KhompPvt * pvt, SendData & data)
945         {
946             switch_event_t *event = create(ESL_SMS_SENT);
947 
948             if(!event)
949             {
950                 LOG(ERROR, "Cannot create SMS ESL");
951                 return false;
952             }
953 
954             add(event, pvt->target());
955             add(event, "Dest", data._dest);
956             add(event, "Body", data._body);
957             add(event, "Confirmation?", (data._conf ? "Yes" : "No"));
958 
959 
960             return fire(&event);
961         }
962 
963 
964 
965     } SMSEvent;
966 
967     struct Request
968     {
969         /* "empty" constructor */
970         Request(): _finished(NULL), _cause(NULL) {};
971 
972         /* "real" constructor */
973         Request(SendData & send_sms, volatile bool * finished, volatile KGsmCallCause * cause)
974             : _send_sms(send_sms), _finished(finished), _cause(cause)
975         {};
976 
977         SendData _send_sms;
978 
979         volatile bool          * _finished;
980         volatile KGsmCallCause * _cause;
981     };
982 
983     bool start()
984     {
985         _pvt->call()->_flags.clear(Kflags::SMS_DOING_UPLOAD);
986 
987         _thread = threadCreate(&smsThread, (void*) this);
988         _thread->start();
989     }
990 
991     bool stop()
992     {
993         if(!_thread)
994         {
995             return false;
996         }
997 
998         _shutdown = true;
999         _cond.signal();
1000         _thread->join();
1001         delete _thread;
1002         _thread = NULL;
1003 
1004         return true;
1005     }
1006 
1007     bool justAlloc(unsigned int count = 0);
1008     bool justStart();
1009 
1010     bool sendSMS(switch_core_session_t * session, const char *data);
1011 
1012 
1013     bool onNewSMS(K3L_EVENT *e);
1014     bool onSMSInfo(K3L_EVENT *e);
1015     bool onSMSData(K3L_EVENT *e);
1016     bool onSMSSendResult(K3L_EVENT *e);
1017 
1018     Thread                                             *_thread;
1019     bool                                                _shutdown;
1020     bool                                                _can_receive;
1021     bool                                                _can_send;
1022     ReceiveData                                         _got_sms;
1023     SendData                                            _send_sms;
1024     int                                                 _result;
1025     SavedCondition                                      _cond;
1026     Globals::Mutex                                      _mutex;
1027     Ringbuffer < SMS::Request >                         _buffer;
1028     OwnersList                                          _owners;
1029 
1030     static int smsThread(void * sms_ptr);
1031 };
1032 
1033 /******************************************************************************/
1034 
1035 
1036 #endif /* _APPLICATIONS_H_ */
1037 
1038