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 _KHOMP_PVT_E1_H_ 45 #define _KHOMP_PVT_E1_H_ 46 47 #include "khomp_pvt.h" 48 49 #include "applications.h" 50 51 /******************************************************************************/ 52 /********************************** E1 Board **********************************/ 53 /******************************************************************************/ 54 struct BoardE1: public Board 55 { 56 /******************************************************************************/ 57 /********************************* E1 Channel *********************************/ 58 struct KhompPvtE1: public KhompPvt 59 { 60 /*********************************** E1 Call **********************************/ 61 struct CallE1 : public Call 62 { CallE1BoardE1::KhompPvtE1::CallE163 CallE1() {} 64 65 bool process(std::string name, std::string value = "") 66 { 67 if (name == "answer_info") 68 { 69 _call_info_report = true; 70 } 71 else if (name == "drop_on") 72 { 73 _call_info_report = true; 74 75 Strings::vector_type drop_item; 76 Strings::tokenize (value, drop_item, ".+"); 77 78 for (Strings::vector_type::iterator i = drop_item.begin(); i != drop_item.end(); i++) 79 { 80 81 if ((*i) == "message_box") _call_info_drop |= CI_MESSAGE_BOX; 82 else if ((*i) == "human_answer") _call_info_drop |= CI_HUMAN_ANSWER; 83 else if ((*i) == "answering_machine") _call_info_drop |= CI_ANSWERING_MACHINE; 84 else if ((*i) == "carrier_message") _call_info_drop |= CI_CARRIER_MESSAGE; 85 else if ((*i) == "unknown") _call_info_drop |= CI_UNKNOWN; 86 else 87 { 88 LOG(ERROR, FMT("unknown paramenter to 'calldrop' Dial option: '%s'.") % (*i)); 89 continue; 90 } 91 92 DBG(FUNC, FMT("droping call on '%s'.") % (*i)); 93 } 94 } 95 else 96 { 97 return Call::process(name, value); 98 } 99 100 return true; 101 } 102 clearBoardE1::KhompPvtE1::CallE1103 bool clear() 104 { 105 _call_info_report = false; 106 _call_info_drop = 0; 107 108 _var_fax_adjust = T_UNKNOWN; 109 110 return Call::clear(); 111 } 112 113 /* report what we got? */ 114 bool _call_info_report; 115 116 /* what call info flags should make us drop the call? */ 117 long int _call_info_drop; 118 119 TriState _var_fax_adjust; 120 121 ChanTimer::Index _idx_disconnect; 122 123 }; 124 /******************************************************************************/ KhompPvtE1BoardE1::KhompPvtE1125 KhompPvtE1(K3LAPIBase::GenericTarget & target) : KhompPvt(target) 126 { 127 _fax = new Fax(this); 128 command(KHOMP_LOG,CM_ENABLE_CALL_ANSWER_INFO); 129 } 130 ~KhompPvtE1BoardE1::KhompPvtE1131 ~KhompPvtE1() 132 { 133 delete _fax; 134 } 135 callE1BoardE1::KhompPvtE1136 CallE1 * callE1() 137 { 138 return (CallE1 *)call(); 139 } 140 141 int makeCall(std::string params = ""); 142 143 bool onChannelRelease(K3L_EVENT *e); 144 bool onCallSuccess(K3L_EVENT *e); 145 bool onAudioStatus(K3L_EVENT *e); 146 bool onCallAnswerInfo(K3L_EVENT *e); 147 bool onDisconnect(K3L_EVENT *e); 148 eventHandlerBoardE1::KhompPvtE1149 virtual bool eventHandler(K3L_EVENT *e) 150 { 151 DBG(STRM, D("(E1) c")); 152 153 bool ret = true; 154 155 switch(e->Code) 156 { 157 case EV_CHANNEL_FREE: 158 case EV_CHANNEL_FAIL: 159 ret = onChannelRelease(e); 160 break; 161 case EV_CALL_ANSWER_INFO: 162 ret = onCallAnswerInfo(e); 163 break; 164 case EV_DISCONNECT: 165 ret = onDisconnect(e); 166 break; 167 case EV_AUDIO_STATUS: 168 ret = onAudioStatus(e); 169 break; 170 case EV_FAX_CHANNEL_FREE: 171 ret = _fax->onFaxChannelRelease(e); 172 break; 173 case EV_FAX_FILE_SENT: 174 case EV_FAX_FILE_FAIL: 175 case EV_FAX_TX_TIMEOUT: 176 case EV_FAX_PAGE_CONFIRMATION: 177 case EV_FAX_REMOTE_INFO: 178 break; 179 default: 180 ret = KhompPvt::eventHandler(e); 181 break; 182 } 183 184 DBG(STRM, D("(E1) r")); 185 186 return ret; 187 } 188 189 bool application(ApplicationType type, switch_core_session_t * session, const char *data); 190 191 bool setupConnection(); 192 bool indicateBusyUnlocked(int cause, bool sent_signaling = false); 193 void setAnswerInfo(int answer_info); 194 bool validContexts(MatchExtension::ContextListType & contexts, 195 std::string extra_context = ""); 196 bool isOK(void); 197 isPhysicalFreeBoardE1::KhompPvtE1198 bool isPhysicalFree() 199 { 200 K3L_CHANNEL_STATUS status; 201 202 if (k3lGetDeviceStatus (_target.device, _target.object + ksoChannel, &status, sizeof (status)) != ksSuccess) 203 return false; 204 205 bool physically_free = (status.AddInfo == kecsFree); 206 207 if(status.CallStatus != kcsFree || !physically_free) 208 { 209 DBG(FUNC, PVT_FMT(_target, "call status not free, or not physically free!")); 210 return false; 211 } 212 213 return true; 214 } 215 216 virtual bool cleanup(CleanupType type = CLN_HARD) 217 { 218 try 219 { 220 Board::board(_target.device)->_timers.del(callE1()->_idx_disconnect); 221 } catchBoardE1::KhompPvtE1222 catch (K3LAPITraits::invalid_device & err) 223 { 224 LOG(ERROR, PVT_FMT(target(), "Unable to get device: %d!") % err.device); 225 } 226 227 callE1()->_idx_disconnect.reset(); 228 229 switch (type) 230 { 231 case CLN_HARD: 232 case CLN_FAIL: 233 call()->_flags.clear(Kflags::FAX_DETECTED); 234 break; 235 case CLN_SOFT: 236 break; 237 } 238 239 return KhompPvt::cleanup(type); 240 } 241 getSpecialVariablesBoardE1::KhompPvtE1242 virtual void getSpecialVariables() 243 { 244 try 245 { 246 const char * str_fax = getFSChannelVar("KAdjustForFax"); 247 248 callE1()->_var_fax_adjust = (str_fax ? (!SAFE_strcasecmp(str_fax, "true") ? T_TRUE : T_FALSE) : T_UNKNOWN); 249 } 250 catch(Board::KhompPvt::InvalidSwitchChannel & err) 251 { 252 LOG(ERROR, PVT_FMT(_target, "(E1) %s") % err._msg.c_str()); 253 } 254 255 KhompPvt::getSpecialVariables(); 256 } 257 258 /* used by app FAX */ 259 Fax * _fax; 260 261 static void delayedDisconnect(Board::KhompPvt * pvt); 262 }; 263 /******************************************************************************/ 264 /********************************** ISDN Channel ******************************/ 265 struct KhompPvtISDN: public KhompPvtE1 266 { 267 /********************************** ISDN Call *********************************/ 268 struct CallISDN : public CallE1 269 { 270 CallISDNBoardE1::KhompPvtISDN::CallISDN271 CallISDN() {} 272 273 bool process(std::string name, std::string value = "") 274 { 275 if ((name == "uui" ) || (name == "uui_ex")) 276 { 277 if(value.find("#") != std::string::npos) 278 { 279 Strings::vector_type values; 280 Strings::tokenize(value, values, "#", 2); 281 282 try 283 { 284 std::string uui_proto_s = values[0]; 285 _uui_extended = (name == "uui_ex"); 286 _uui_descriptor = Strings::toulong(uui_proto_s); 287 _uui_information.clear(); 288 289 for (unsigned int i = 0; i < values[1].size(); ++i) 290 _uui_information += STG(FMT("%02hhx") % ((unsigned char)values[1][i])); 291 292 DBG(FUNC, FMT("uui adjusted (ex=%s, proto=%s, data='%s')!") 293 % (_uui_extended ? "true" : "false") 294 % uui_proto_s.c_str() 295 % _uui_information.c_str()); 296 } catchBoardE1::KhompPvtISDN::CallISDN297 catch (...) 298 { 299 LOG(ERROR, FMT("invalid %s protocol descriptor: '%s' is not a number.") 300 % (_uui_extended ? "uui_ex" : "uui") 301 % value.c_str()); 302 } 303 } 304 else 305 { 306 LOG(ERROR, FMT("invalid %s protocol descriptor, need a '#'.") 307 % (_uui_extended ? "uui_ex" : "uui")) 308 } 309 } 310 else if (name == "usr_xfer") 311 { 312 _user_xfer_digits = value; 313 } 314 else 315 { 316 return CallE1::process(name, value); 317 } 318 319 return true; 320 } 321 clearBoardE1::KhompPvtISDN::CallISDN322 bool clear() 323 { 324 _uui_extended = false; 325 _uui_descriptor = -1; 326 _uui_information.clear(); 327 _isdn_cause = -1; 328 329 _user_xfer_digits = Opt::_options._user_xfer_digits(); 330 _user_xfer_buffer.clear(); 331 _digits_buffer.clear(); 332 _qsig_number.clear(); 333 334 return CallE1::clear(); 335 } 336 337 /* used for isdn EV_USER_INFORMATION */ 338 long int _uui_descriptor; 339 std::string _uui_information; 340 long int _isdn_cause; 341 bool _uui_extended; 342 343 /* what should we dial to trigger an user-signaled transfer? */ 344 /* used for xfer on user signaling */ 345 std::string _user_xfer_digits; 346 std::string _user_xfer_buffer; 347 std::string _digits_buffer; 348 std::string _qsig_number; 349 350 /* isdn information */ 351 std::string _isdn_orig_type_of_number; 352 std::string _isdn_orig_numbering_plan; 353 std::string _isdn_dest_type_of_number; 354 std::string _isdn_dest_numbering_plan; 355 std::string _isdn_orig_presentation; 356 357 }; 358 /******************************************************************************/ KhompPvtISDNBoardE1::KhompPvtISDN359 KhompPvtISDN(K3LAPIBase::GenericTarget & target) : KhompPvtE1(target) 360 { 361 _transfer = new Transfer<CallISDN, false>(this); 362 } 363 ~KhompPvtISDNBoardE1::KhompPvtISDN364 ~KhompPvtISDN() 365 { 366 delete _transfer; 367 } 368 callISDNBoardE1::KhompPvtISDN369 CallISDN * callISDN() 370 { 371 return (CallISDN *)call(); 372 } 373 374 int makeCall(std::string params = ""); 375 bool doChannelAnswer(CommandRequest &); 376 377 bool onSyncUserInformation(K3L_EVENT *e); 378 bool onIsdnProgressIndicator(K3L_EVENT *e); 379 bool onNewCall(K3L_EVENT *e); 380 bool onCallSuccess(K3L_EVENT *e); 381 bool onCallFail(K3L_EVENT *e); 382 eventHandlerBoardE1::KhompPvtISDN383 virtual bool eventHandler(K3L_EVENT *e) 384 { 385 DBG(STRM, D("(ISDN) c")); 386 387 bool ret = true; 388 389 switch(e->Code) 390 { 391 case EV_USER_INFORMATION: 392 ret = onSyncUserInformation(e); 393 break; 394 case EV_ISDN_PROGRESS_INDICATOR: 395 ret = onIsdnProgressIndicator(e); 396 break; 397 case EV_NEW_CALL: 398 ret = onNewCall(e); 399 break; 400 case EV_CALL_SUCCESS: 401 ret = onCallSuccess(e); 402 break; 403 case EV_CALL_FAIL: 404 ret = onCallFail(e); 405 break; 406 case EV_SS_TRANSFER_FAIL: 407 break; 408 default: 409 ret = KhompPvtE1::eventHandler(e); 410 break; 411 } 412 413 DBG(STRM, D("(ISDN) r")); 414 415 return ret; 416 } 417 418 bool application(ApplicationType type, switch_core_session_t * session, const char *data); 419 420 int causeFromCallFail(int fail); 421 int callFailFromCause(int cause); 422 void reportFailToReceive(int fail_code); 423 RingbackDefs::RingbackStType sendRingBackStatus(int rb_value = RingbackDefs::RB_SEND_DEFAULT); 424 bool sendPreAudio(int rb_value = RingbackDefs::RB_SEND_NOTHING); 425 bool sendDtmf(std::string digit); 426 427 virtual bool cleanup(CleanupType type = CLN_HARD) 428 { 429 _transfer->clear(); 430 431 /* 432 switch (type) 433 { 434 case CLN_HARD: 435 case CLN_FAIL: 436 break; 437 case CLN_SOFT: 438 break; 439 } 440 */ 441 442 return KhompPvtE1::cleanup(type); 443 } 444 setSpecialVariablesBoardE1::KhompPvtISDN445 virtual void setSpecialVariables() 446 { 447 try 448 { 449 /* rdsi user info */ 450 if (callISDN()->_uui_descriptor != -1) 451 { 452 DBG(FUNC,"Setting ISDN descriptor"); 453 454 std::string descriptor = STG(FMT("%d") % callISDN()->_uui_descriptor); 455 456 setFSChannelVar("KUserInfoExtended", (callISDN()->_uui_extended ? "true" : "false")); 457 setFSChannelVar("KUserInfoDescriptor", descriptor.c_str()); 458 setFSChannelVar("KUserInfoData", callISDN()->_uui_information.c_str()); 459 460 callISDN()->_uui_extended = false; 461 callISDN()->_uui_descriptor = -1; 462 callISDN()->_uui_information.clear(); 463 } 464 465 if (!callISDN()->_isdn_orig_type_of_number.empty()) 466 setFSChannelVar("KISDNOrigTypeOfNumber", callISDN()->_isdn_orig_type_of_number.c_str()); 467 468 if (!callISDN()->_isdn_dest_type_of_number.empty()) 469 setFSChannelVar("KISDNDestTypeOfNumber", callISDN()->_isdn_dest_type_of_number.c_str()); 470 471 if (!callISDN()->_isdn_orig_numbering_plan.empty()) 472 setFSChannelVar("KISDNOrigNumberingPlan", callISDN()->_isdn_orig_numbering_plan.c_str()); 473 474 if (!callISDN()->_isdn_dest_numbering_plan.empty()) 475 setFSChannelVar("KISDNDestNumberingPlan", callISDN()->_isdn_dest_numbering_plan.c_str()); 476 477 if (!callISDN()->_isdn_orig_presentation.empty()) 478 setFSChannelVar("KISDNOrigPresentation", callISDN()->_isdn_orig_presentation.c_str()); 479 } 480 catch(Board::KhompPvt::InvalidSwitchChannel & err) 481 { 482 LOG(ERROR, PVT_FMT(_target, "(ISDN) %s") % err._msg.c_str()); 483 } 484 485 KhompPvtE1::setSpecialVariables(); 486 } 487 getSpecialVariablesBoardE1::KhompPvtISDN488 virtual void getSpecialVariables() 489 { 490 try 491 { 492 const char * isdn_orig_type = getFSChannelVar("KISDNOrigTypeOfNumber"); 493 const char * isdn_dest_type = getFSChannelVar("KISDNDestTypeOfNumber"); 494 const char * isdn_orig_numbering = getFSChannelVar("KISDNOrigNumberingPlan"); 495 const char * isdn_dest_numbering = getFSChannelVar("KISDNDestNumberingPlan"); 496 const char * isdn_orig_presentation = getFSChannelVar("KISDNOrigPresentation"); 497 498 LOG(ERROR, PVT_FMT(_target,"ISDNORIG: %s") % (isdn_orig_type ? isdn_orig_type : "")); 499 500 callISDN()->_isdn_orig_type_of_number = (isdn_orig_type ? isdn_orig_type : ""); 501 callISDN()->_isdn_dest_type_of_number = (isdn_dest_type ? isdn_dest_type : ""); 502 callISDN()->_isdn_orig_numbering_plan = (isdn_orig_numbering ? isdn_orig_numbering : ""); 503 callISDN()->_isdn_dest_numbering_plan = (isdn_dest_numbering ? isdn_dest_numbering : ""); 504 callISDN()->_isdn_orig_presentation = (isdn_orig_presentation ? isdn_orig_presentation : ""); 505 } 506 catch(Board::KhompPvt::InvalidSwitchChannel & err) 507 { 508 LOG(ERROR, PVT_FMT(_target, "(ISDN) %s") % err._msg.c_str()); 509 } 510 511 KhompPvt::getSpecialVariables(); 512 } 513 514 Transfer<CallISDN, false> * _transfer; 515 }; 516 /******************************************************************************/ 517 /********************************* R2 Channel *********************************/ 518 struct KhompPvtR2: public KhompPvtE1 519 { 520 /********************************* R2 Call ************************************/ 521 struct CallR2 : public CallE1 522 { 523 CallR2BoardE1::KhompPvtR2::CallR2524 CallR2() {} 525 526 527 bool process(std::string name, std::string value = "") 528 { 529 if (name == "category") 530 { 531 try 532 { 533 unsigned long int category = Strings::toulong (value); 534 DBG(FUNC, FMT("r2 category adjusted (%s)!") % value.c_str()); 535 _r2_category = category; 536 } catchBoardE1::KhompPvtR2::CallR2537 catch (...) 538 { 539 LOG(ERROR, FMT("invalid r2 category: '%s' is not a number.") % value.c_str()); 540 } 541 } 542 else 543 { 544 return CallE1::process(name, value); 545 } 546 return true; 547 } 548 clearBoardE1::KhompPvtR2::CallR2549 bool clear() 550 { 551 _r2_category = -1; 552 _r2_condition = -1; 553 554 return CallE1::clear(); 555 } 556 557 long int _r2_category; 558 long int _r2_condition; 559 560 ChanTimer::Index _idx_number_dial; 561 std::string _incoming_exten; 562 }; 563 /******************************************************************************/ KhompPvtR2BoardE1::KhompPvtR2564 KhompPvtR2(K3LAPIBase::GenericTarget & target) : KhompPvtE1(target) 565 { 566 K3L_E1600A_FW_CONFIG dspAcfg; 567 568 if (k3lGetDeviceConfig(_target.device, ksoFirmware + kfiE1600A, &dspAcfg, sizeof(dspAcfg)) != ksSuccess) 569 { 570 DBG(FUNC, PVT_FMT(target, "unable to get signaling locality for board: assuming brazilian signaling")); 571 572 _r2_country = Verbose::R2_COUNTRY_BRA; 573 574 return; 575 } 576 Regex::Expression e(".+\\((Arg|Bra|Chi|Mex|Ury|Ven)\\).+", Regex::E_EXTENDED); 577 std::string fwname(dspAcfg.FwVersion); 578 579 Regex::Match what(fwname, e); 580 581 if (!what.matched() || !what.matched(1)) 582 { 583 DBG(FUNC, PVT_FMT(target, "invalid firmware string, unable to find country code: assuming brazilian signaling.\n")); 584 585 _r2_country = Verbose::R2_COUNTRY_BRA; 586 return; 587 } 588 589 std::string country = what.submatch(1); 590 591 /**/ if (country == "Arg") 592 _r2_country = Verbose::R2_COUNTRY_ARG; 593 else if (country == "Bra") 594 _r2_country = Verbose::R2_COUNTRY_BRA; 595 else if (country == "Chi") 596 _r2_country = Verbose::R2_COUNTRY_CHI; 597 else if (country == "Mex") 598 _r2_country = Verbose::R2_COUNTRY_MEX; 599 else if (country == "Ury") 600 _r2_country = Verbose::R2_COUNTRY_URY; 601 else if (country == "Ven") 602 _r2_country = Verbose::R2_COUNTRY_VEN; 603 else 604 { 605 DBG(FUNC, PVT_FMT(target, "invalid firmware string (%s), assuming brazilian signaling.") % country.c_str()); 606 607 _r2_country = Verbose::R2_COUNTRY_BRA; 608 return; 609 } 610 611 DBG(FUNC, PVT_FMT(target, "adjusting country signaling to code '%s'...") 612 % country.c_str()); 613 614 } 615 ~KhompPvtR2BoardE1::KhompPvtR2616 ~KhompPvtR2() {} 617 callR2BoardE1::KhompPvtR2618 CallR2 * callR2() 619 { 620 return (CallR2 *)call(); 621 } 622 forceDisconnectBoardE1::KhompPvtR2623 bool forceDisconnect(void) 624 { 625 char cmd[] = { 0x07, (char)(_target.object + 1) }; 626 627 try 628 { 629 Globals::k3lapi.raw_command(_target.device, 0, cmd, sizeof(cmd)); 630 } 631 catch(K3LAPI::failed_raw_command &e) 632 { 633 return false; 634 } 635 636 return true; 637 }; 638 639 int makeCall(std::string params = ""); 640 bool doChannelAnswer(CommandRequest &); 641 bool doChannelHangup(CommandRequest &); 642 643 bool onNewCall(K3L_EVENT *e); 644 bool onCallSuccess(K3L_EVENT *e); 645 bool onCallFail(K3L_EVENT *e); 646 bool onNumberDetected(K3L_EVENT *e); 647 eventHandlerBoardE1::KhompPvtR2648 virtual bool eventHandler(K3L_EVENT *e) 649 { 650 DBG(STRM, D("(R2) c")); 651 652 bool ret = true; 653 654 switch(e->Code) 655 { 656 case EV_NEW_CALL: 657 ret = onNewCall(e); 658 break; 659 case EV_CALL_SUCCESS: 660 ret = onCallSuccess(e); 661 break; 662 case EV_CALL_FAIL: 663 ret = onCallFail(e); 664 break; 665 case EV_DIALED_DIGIT: 666 ret = onNumberDetected(e); 667 break; 668 default: 669 ret = KhompPvtE1::eventHandler(e); 670 break; 671 } 672 673 DBG(STRM, D("(R2) r")); 674 675 return ret; 676 677 } 678 679 int causeFromCallFail(int fail); 680 int callFailFromCause(int cause); 681 void reportFailToReceive(int fail_code); 682 RingbackDefs::RingbackStType sendRingBackStatus(int rb_value = RingbackDefs::RB_SEND_DEFAULT); 683 bool sendPreAudio(int rb_value = RingbackDefs::RB_SEND_NOTHING); 684 bool indicateRinging(); 685 setSpecialVariablesBoardE1::KhompPvtR2686 virtual void setSpecialVariables() 687 { 688 try 689 { 690 /* r2 caller category */ 691 if (callR2()->_r2_category != -1) 692 { 693 setFSChannelVar("KR2GotCategory",STG(FMT("%d") % callR2()->_r2_category).c_str()); 694 setFSChannelVar("KR2StrCategory",Verbose::signGroupII((KSignGroupII)callR2()->_r2_category).c_str()); 695 } 696 } 697 catch(Board::KhompPvt::InvalidSwitchChannel & err) 698 { 699 LOG(ERROR, PVT_FMT(_target, "(R2) %s") % err._msg.c_str()); 700 } 701 702 KhompPvtE1::setSpecialVariables(); 703 } 704 705 virtual bool cleanup(CleanupType type = CLN_HARD) 706 { 707 call()->_flags.clear(Kflags::NEEDS_RINGBACK_CMD); 708 call()->_flags.clear(Kflags::NUMBER_DIAL_ONGOING); 709 call()->_flags.clear(Kflags::NUMBER_DIAL_FINISHD); 710 711 switch (type) 712 { 713 case CLN_HARD: 714 case CLN_FAIL: 715 break; 716 case CLN_SOFT: 717 break; 718 } 719 720 return KhompPvtE1::cleanup(type); 721 } 722 723 static void numberDialTimer(Board::KhompPvt * pvt); 724 725 public: 726 Verbose::R2CountryType _r2_country; 727 728 }; 729 /******************************************************************************/ 730 /********************************* FLASH Channel ******************************/ 731 /* ksigLineSide ksigCAS_EL7 ksigE1LC */ 732 struct KhompPvtFlash: public KhompPvtR2 733 { 734 /********************************* R2 Call ************************************/ 735 struct CallFlash : public CallR2 736 { 737 CallFlashBoardE1::KhompPvtFlash::CallFlash738 CallFlash() {} 739 740 bool process(std::string name, std::string value = "") 741 { 742 if (name == "usr_xfer") 743 { 744 _user_xfer_digits = value; 745 } 746 else 747 { 748 return CallR2::process(name, value); 749 } 750 751 return true; 752 } 753 clearBoardE1::KhompPvtFlash::CallFlash754 bool clear() 755 { 756 _user_xfer_digits = Opt::_options._user_xfer_digits(); 757 _user_xfer_buffer.clear(); 758 _digits_buffer.clear(); 759 760 return CallR2::clear(); 761 } 762 763 /* used for xfer on user signaling */ 764 std::string _user_xfer_digits; 765 std::string _user_xfer_buffer; 766 std::string _digits_buffer; 767 768 }; 769 /******************************************************************************/ KhompPvtFlashBoardE1::KhompPvtFlash770 KhompPvtFlash(K3LAPIBase::GenericTarget & target) : KhompPvtR2(target) 771 { 772 _transfer = new Transfer<CallFlash>(this); 773 } 774 ~KhompPvtFlashBoardE1::KhompPvtFlash775 ~KhompPvtFlash() 776 { 777 delete _transfer; 778 } 779 callFlashBoardE1::KhompPvtFlash780 CallFlash * callFlash() 781 { 782 return (CallFlash *)call(); 783 } 784 785 bool application(ApplicationType type, switch_core_session_t * session, const char *data); 786 787 bool sendDtmf(std::string digit); 788 789 virtual bool cleanup(CleanupType type = CLN_HARD) 790 { 791 _transfer->clear(); 792 793 /* 794 switch (type) 795 { 796 case CLN_HARD: 797 case CLN_FAIL: 798 break; 799 case CLN_SOFT: 800 break; 801 } 802 */ 803 804 return KhompPvtR2::cleanup(type); 805 } 806 807 Transfer<CallFlash> * _transfer; 808 }; 809 /******************************************************************************/ 810 /********************************* FSX Channel ********************************/ 811 struct KhompPvtFXS: public KhompPvt 812 { 813 /********************************** FXS Call **********************************/ 814 struct CallFXS : public Call 815 { CallFXSBoardE1::KhompPvtFXS::CallFXS816 CallFXS() {} 817 818 bool process(std::string name, std::string value = "") 819 { 820 if (name == "ring") 821 { 822 Strings::vector_type ring_item; 823 Strings::tokenize (value, ring_item, "."); 824 825 if (ring_item.size() != 2) 826 { 827 LOG(ERROR, FMT("invalid values on ring string: two numbers, dot separated, are needed.")); 828 return false; 829 } 830 831 try 832 { 833 unsigned long int time_on = Strings::toulong (ring_item[0]); 834 unsigned long int time_off = Strings::toulong (ring_item[1]); 835 836 _ring_on = time_on; 837 _ring_off = time_off; 838 839 DBG(FUNC, D("ring values adjusted (%i,%i).") % time_on % time_off); 840 } catchBoardE1::KhompPvtFXS::CallFXS841 catch (...) 842 { 843 LOG(ERROR, FMT("invalid number on ring string.")); 844 } 845 } 846 else if (name == "ring_ext") 847 { 848 if (_ring_on == -1) // so ring was not set. 849 { 850 LOG(ERROR, FMT("ring_ext only make sense if ring values are set.")); 851 return false; 852 } 853 854 Strings::vector_type ring_item; 855 Strings::tokenize (value, ring_item, "."); 856 857 if (ring_item.size() != 2) 858 { 859 LOG(ERROR, FMT("invalid values on ring_ext string: two numbers, dot separated, are needed.")); 860 return false; 861 } 862 863 try 864 { 865 unsigned long int time_on = Strings::toulong (ring_item[0]); 866 unsigned long int time_off = Strings::toulong (ring_item[1]); 867 868 _ring_on_ext = time_on; 869 _ring_off_ext = time_off; 870 871 DBG(FUNC, D("ring_ext values adjusted (%i,%i).") % time_on % time_off); 872 } catchBoardE1::KhompPvtFXS::CallFXS873 catch (...) 874 { 875 LOG(ERROR, FMT("invalid number on ring_ext string.")); 876 } 877 } 878 else if (name == "ring_cadence") 879 { 880 CadencesMapType::iterator i = Opt::_cadences.find(value); 881 882 if (i != Opt::_cadences.end()) 883 { 884 CadenceType cadence = (*i).second; 885 886 _ring_on = cadence.ring; 887 _ring_off = cadence.ring_s; 888 _ring_on_ext = cadence.ring_ext; 889 _ring_off_ext = cadence.ring_ext_s; 890 891 DBG(FUNC, D("cadence adjusted (%i,%i,%i,%i).") 892 % cadence.ring 893 % cadence.ring_s 894 % cadence.ring_ext 895 % cadence.ring_ext_s); 896 } 897 else 898 { 899 LOG(ERROR, FMT("unable to find cadence '%s'!") % value); 900 } 901 } 902 else 903 { 904 return Call::process(name, value); 905 } 906 907 return true; 908 } 909 clearBoardE1::KhompPvtFXS::CallFXS910 bool clear() 911 { 912 _ring_on = -1; 913 _ring_off = -1; 914 _ring_on_ext = -1; 915 _ring_off_ext = -1; 916 917 _incoming_exten.clear(); 918 //_flash_transfer.clear(); 919 920 //_uuid_other_session.clear(); 921 922 return Call::clear(); 923 } 924 925 long int _ring_on; 926 long int _ring_off; 927 long int _ring_on_ext; 928 long int _ring_off_ext; 929 930 ChanTimer::Index _idx_dial; 931 932 std::string _incoming_exten; 933 934 //ChanTimer::Index _idx_transfer; 935 936 //std::string _flash_transfer; 937 //std::string _uuid_other_session; 938 939 940 }; 941 /******************************************************************************/ KhompPvtFXSBoardE1::KhompPvtFXS942 KhompPvtFXS(K3LAPIBase::GenericTarget & target) : KhompPvt(target) 943 { 944 //command(KHOMP_LOG,CM_ENABLE_CALL_ANSWER_INFO); 945 /* sequence numbers on FXS */ 946 static OrigToNseqMapType fxs_nseq = generateNseqMap(); 947 948 load(fxs_nseq); 949 } 950 ~KhompPvtFXSBoardE1::KhompPvtFXS951 ~KhompPvtFXS() {} 952 callFXSBoardE1::KhompPvtFXS953 CallFXS * callFXS() 954 { 955 return (CallFXS *)call(); 956 } 957 958 int makeCall(std::string params = ""); 959 bool doChannelAnswer(CommandRequest &); 960 bool doChannelHangup(CommandRequest &); 961 962 bool onChannelRelease(K3L_EVENT *e); 963 bool onSeizureStart(K3L_EVENT *); 964 bool onCallSuccess(K3L_EVENT *); 965 bool onDtmfDetected(K3L_EVENT *); 966 //bool onDtmfSendFinish(K3L_EVENT *); 967 bool onFlashDetected(K3L_EVENT *); 968 eventHandlerBoardE1::KhompPvtFXS969 virtual bool eventHandler(K3L_EVENT *e) 970 { 971 DBG(STRM, D("(FXS) c")); 972 973 bool ret = true; 974 975 switch(e->Code) 976 { 977 case EV_CHANNEL_FREE: 978 case EV_CHANNEL_FAIL: 979 ret = onChannelRelease(e); 980 break; 981 case EV_SEIZURE_START: 982 ret = onSeizureStart(e); 983 break; 984 case EV_CALL_SUCCESS: 985 ret = onCallSuccess(e); 986 break; 987 case EV_DTMF_DETECTED: 988 case EV_PULSE_DETECTED: 989 ret = onDtmfDetected(e); 990 break; 991 /* 992 case EV_DTMF_SEND_FINISH: 993 ret = onDtmfSendFinish(e); 994 break; 995 */ 996 case EV_FLASH: 997 ret = onFlashDetected(e); 998 break; 999 default: 1000 ret = KhompPvt::eventHandler(e); 1001 break; 1002 } 1003 1004 DBG(STRM, D("(FXS) r")); 1005 1006 return ret; 1007 } 1008 1009 bool setupConnection(); 1010 void load(OrigToNseqMapType & fxs_nseq); 1011 void loadOptions(); 1012 bool parseBranchOptions(std::string options_str); 1013 bool alloc(); 1014 bool indicateBusyUnlocked(int cause, bool sent_signaling = false); 1015 void reportFailToReceive(int fail_code); 1016 bool validContexts(MatchExtension::ContextListType & contexts, 1017 std::string extra_context = ""); 1018 bool isOK(void); 1019 1020 //bool startTransfer(); 1021 //bool stopTransfer(); 1022 //bool transfer(std::string & context, bool blind = false); 1023 hasNumberDialBoardE1::KhompPvtFXS1024 bool hasNumberDial() { return false; } 1025 isPhysicalFreeBoardE1::KhompPvtFXS1026 bool isPhysicalFree() 1027 { 1028 K3L_CHANNEL_STATUS status; 1029 1030 if (k3lGetDeviceStatus (_target.device, _target.object + ksoChannel, &status, sizeof (status)) != ksSuccess) 1031 return false; 1032 1033 bool physically_free = (status.AddInfo == kfxsOnHook); 1034 1035 if(status.CallStatus != kcsFree || !physically_free) 1036 { 1037 DBG(FUNC, PVT_FMT(_target, "call status not free, or not physically free!")); 1038 return false; 1039 } 1040 1041 return true; 1042 } 1043 1044 virtual bool cleanup(CleanupType type = CLN_HARD) 1045 { 1046 callFXS()->_flags.clear(Kflags::FXS_DIAL_ONGOING); 1047 callFXS()->_flags.clear(Kflags::FXS_DIAL_FINISHD); 1048 callFXS()->_flags.clear(Kflags::FXS_FLASH_TRANSFER); 1049 1050 switch (type) 1051 { 1052 case CLN_HARD: 1053 case CLN_FAIL: 1054 callFXS()->_flags.clear(Kflags::FXS_OFFHOOK); 1055 break; 1056 case CLN_SOFT: 1057 break; 1058 } 1059 1060 return KhompPvt::cleanup(type); 1061 } 1062 1063 1064 /* number based on fxs-global-orig */ 1065 std::string _fxs_fisical_addr; 1066 /* the branch number, possibly the new calleridnum */ 1067 std::string _fxs_orig_addr; 1068 std::string _calleridname; 1069 int _amaflags; 1070 std::string _callgroup; 1071 std::string _pickupgroup; 1072 std::string _context; 1073 int _input_volume; 1074 int _output_volume; 1075 std::string _mailbox; 1076 std::string _flash; 1077 1078 static OrigToNseqMapType generateNseqMap(); 1079 static void dialTimer(KhompPvt * pvt); 1080 //static void transferTimer(KhompPvt * pvt); 1081 padOrigBoardE1::KhompPvtFXS1082 static std::string padOrig(std::string orig_base, unsigned int padding) 1083 { 1084 unsigned int orig_size = orig_base.size(); 1085 unsigned int orig_numb = 0; 1086 1087 try 1088 { 1089 orig_numb = Strings::toulong(orig_base); 1090 } 1091 catch(Strings::invalid_value & e) 1092 { 1093 LOG(ERROR, D("invalid numeric value: %s") % e.value()); 1094 } 1095 1096 return STG(FMT(STG(FMT("%%0%dd") % orig_size)) % (orig_numb + padding)); 1097 } 1098 cleanupIndicationsBoardE1::KhompPvtFXS1099 void cleanupIndications(bool force) 1100 { 1101 if (call()->_indication == INDICA_BUSY && !force) 1102 { 1103 DBG(FUNC, PVT_FMT(_target, "skipping busy indication cleanup on FXS channel.")); 1104 return; 1105 } 1106 1107 KhompPvt::cleanupIndications(force); 1108 } 1109 }; 1110 /******************************************************************************/ 1111 /******************************************************************************/ BoardE1BoardE11112 BoardE1(int id) : Board(id) {} 1113 initializeChannelsBoardE11114 void initializeChannels(void) 1115 { 1116 LOG(MESSAGE, "(E1) loading channels ..."); 1117 1118 for (unsigned obj = 0; obj < Globals::k3lapi.channel_count(_device_id); obj++) 1119 { 1120 K3LAPIBase::GenericTarget tgt(Globals::k3lapi, K3LAPIBase::GenericTarget::CHANNEL, _device_id, obj); 1121 KhompPvt * pvt; 1122 1123 switch(Globals::k3lapi.channel_config(_device_id, obj).Signaling) 1124 { 1125 CASE_RDSI_SIG: 1126 pvt = new BoardE1::KhompPvtISDN(tgt); 1127 pvt->_call = new BoardE1::KhompPvtISDN::CallISDN(); 1128 DBG(FUNC, "(E1) ISDN channel"); 1129 break; 1130 CASE_R2_SIG: 1131 pvt = new BoardE1::KhompPvtR2(tgt); 1132 pvt->_call = new BoardE1::KhompPvtR2::CallR2(); 1133 pvt->command(KHOMP_LOG, CM_DISCONNECT); 1134 DBG(FUNC, "(E1) R2 channel"); 1135 break; 1136 CASE_FLASH_GRP: 1137 pvt = new BoardE1::KhompPvtFlash(tgt); 1138 pvt->_call = new BoardE1::KhompPvtFlash::CallFlash(); 1139 pvt->command(KHOMP_LOG, CM_DISCONNECT); 1140 DBG(FUNC, "(E1) \"Flash\" channel"); 1141 break; 1142 case ksigAnalogTerminal: 1143 pvt = new BoardE1::KhompPvtFXS(tgt); 1144 pvt->_call = new BoardE1::KhompPvtFXS::CallFXS(); 1145 DBG(FUNC, "(E1) FXS channel"); 1146 break; 1147 default: 1148 pvt = new Board::KhompPvt(tgt); 1149 pvt->_call = new Board::KhompPvt::Call(); 1150 DBG(FUNC, FMT("(E1) signaling %d unknown") % Globals::k3lapi.channel_config(_device_id, obj).Signaling); 1151 break; 1152 } 1153 1154 _channels.push_back(pvt); 1155 1156 pvt->cleanup(); 1157 1158 } 1159 } 1160 1161 bool onLinkStatus(K3L_EVENT *e); 1162 eventHandlerBoardE11163 virtual bool eventHandler(const int obj, K3L_EVENT *e) 1164 { 1165 DBG(STRM, D("(E1 Board) c")); 1166 1167 int ret = true; 1168 1169 switch(e->Code) 1170 { 1171 case EV_LINK_STATUS: 1172 case EV_PHYSICAL_LINK_DOWN: 1173 case EV_PHYSICAL_LINK_UP: 1174 1175 if (K::Logger::Logg.classe(C_LINK_STT).enabled() || K::Logger::Logg.classe(C_EVENT).enabled()) 1176 { 1177 std::string msg = Globals::verbose.event (obj, e) + "."; 1178 LOG(LINK_STT, msg); 1179 } 1180 1181 ret = onLinkStatus(e); 1182 break; 1183 default: 1184 ret = Board::eventHandler(obj, e); 1185 break; 1186 } 1187 1188 DBG(STRM, D("(E1 Board) r")); 1189 1190 return ret; 1191 } 1192 1193 }; 1194 /******************************************************************************/ 1195 /******************************************************************************/ 1196 /******************************************************************************/ 1197 #endif /* _KHOMP_PVT_H_*/ 1198 1199