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