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