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 #include "opt.h"
45 #include "globals.h"
46 #include "defs.h"
47 #include "logger.h"
48 #include "spec.h"
49 
50 #include <function.hpp>
51 
52 Options               Opt::_options;
53 CadencesMapType       Opt::_cadences;
54 GroupToDestMapType    Opt::_groups;
55 OrigToDestMapType     Opt::_fxs_hotline;
56 BoardToOrigMapType    Opt::_fxs_orig_base;
57 BranchToOptMapType    Opt::_branch_options;
58 BranchToObjectMapType Opt::_fxs_branch_map;
59 
60 /* not beautiful, should think of something! */
61 #define FUNCTION_VALUE(x) reinterpret_cast< Config::FunctionValue Options::* >( x )
62 
initialize(void)63 void Opt::initialize(void)
64 {
65     Globals::options.add(Config::Option("debug",    &Options::_debug,    false));
66     Globals::options.add(Config::Option("dialplan", &Options::_dialplan, "XML"));
67     Globals::options.add(Config::Option("context",  &Options::_context,  "default"));
68 
69 	Globals::options.add(Config::Option("echo-canceller",      &Options::_echo_canceller,      true));
70 	Globals::options.add(Config::Option("auto-gain-control",   &Options::_auto_gain_control,   true));
71 	Globals::options.add(Config::Option("out-of-band-dtmfs",   &Options::_out_of_band_dtmfs,   true));
72 	Globals::options.add(Config::Option("suppression-delay",   &Options::_suppression_delay,   true));
73 	Globals::options.add(Config::Option("pulse-forwarding",    &Options::_pulse_forwarding,    false));
74 	Globals::options.add(Config::Option("native-bridge",       &Options::_native_bridge,       true));
75 	Globals::options.add(Config::Option("recording",           &Options::_recording,           true));
76 	Globals::options.add(Config::Option("has-ctbus",           &Options::_has_ctbus,           false));
77 	Globals::options.add(Config::Option("fxs-bina",            &Options::_fxs_bina,            true));
78 	Globals::options.add(Config::Option("fxs-sharp-dial",      &Options::_fxs_sharp_dial,      true));
79 	Globals::options.add(Config::Option("drop-collect-call",   &Options::_drop_collect_call,   false));
80 	Globals::options.add(Config::Option("ignore-letter-dtmfs", &Options::_ignore_letter_dtmfs, true));
81 	Globals::options.add(Config::Option("optimize-audio-path", &Options::_optimize_audio_path, false));
82 
83     Globals::options.add(Config::Option("fxo-send-pre-audio",     &Options::_fxo_send_pre_audio,  true));
84     Globals::options.add(Config::Option("fxo-busy-disconnection", &Options::_fxo_busy_disconnection, 1250u, 50u, 90000u));
85 
86     Globals::options.add(Config::Option("auto-fax-adjustment",    &Options::_auto_fax_adjustment,    true));
87     Globals::options.add(Config::Option("fax-adjustment-timeout", &Options::_fax_adjustment_timeout, 30u, 3u, 9999u));
88 
89     Globals::options.add(Config::Option("r2-strict-behaviour", &Options::_r2_strict_behaviour, false));
90     Globals::options.add(Config::Option("r2-preconnect-wait",  &Options::_r2_preconnect_wait,  250u, 25u, 500u));
91 
92     Globals::options.add(Config::Option("fxs-digit-timeout",    &Options::_fxs_digit_timeout,   7u,  1u, 30u));
93     Globals::options.add(Config::Option("transferdigittimeout", &Options::_transferdigittimeout, 3000u, 0u, 90000u));
94 
95     Globals::options.add(Config::Option("atxfer",    &Options::_atxfer, ""));
96     Globals::options.add(Config::Option("blindxfer", &Options::_blindxfer, ""));
97 
98     Globals::options.add(Config::Option("flash-to-digits", &Options::_flash, "*1"));
99 
100     Globals::options.add(Config::Option("delay-ringback-co",  &Options::_ringback_co_delay,  1500u, 0u, 999000u));
101     Globals::options.add(Config::Option("delay-ringback-pbx", &Options::_ringback_pbx_delay, 2500u, 0u, 999000u));
102 
103     Globals::options.add(Config::Option("disconnect-delay", &Options::_disconnect_delay, 0u, 0u, 100000u));
104 
105     Globals::options.add(Config::Option("input-volume",  &Options::_input_volume, 0, -10, 10));
106     Globals::options.add(Config::Option("output-volume", &Options::_output_volume, 0, -10, 10));
107 
108     Globals::options.add(Config::Option("fxs-co-dialtone",
109         FUNCTION_VALUE(&Options::_fxs_co_dialtone), ""));
110 
111     Globals::options.add(Config::Option("log-to-disk",
112         FUNCTION_VALUE(&Options::_log_disk_option),    "standard", false));
113 
114     Globals::options.add(Config::Option("callgroup", &Options::_callgroup,   "0"));
115 
116     Globals::options.add(Config::Option("pickupgroup", &Options::_pickupgroup, "0"));
117 
118     Globals::options.add(Config::Option("log-to-console",
119         FUNCTION_VALUE(&Options::_log_console_option), "standard", false));
120 
121     Globals::options.add(Config::Option("trace",
122         FUNCTION_VALUE(&Options::_log_trace_option), "", false));
123 
124     Globals::options.add(Config::Option("record-prefix",
125         FUNCTION_VALUE(&Options::_record_prefix), "/var/spool/freeswitch/monitor/"));
126 
127     Globals::options.add(Config::Option("fxs-global-orig", &Options::_fxs_global_orig_base,  "0"));
128 
129     Globals::options.add(Config::Option("language", &Options::_global_language, ""));
130     Globals::options.add(Config::Option("mohclass", &Options::_global_mohclass, ""));
131 
132     Globals::options.add(Config::Option("context-fxo",          &Options::_context_fxo,       "khomp-DD-CC"));
133     Globals::options.add(Config::Option("context-fxo-alt",      &Options::_context2_fxo,      "khomp-DD"));
134     Globals::options.add(Config::Option("context-fxs",          &Options::_context_fxs,       "khomp-DD-CC"));
135     Globals::options.add(Config::Option("context-fxs-alt",      &Options::_context2_fxs,      "khomp-DD"));
136     Globals::options.add(Config::Option("context-gsm-call",     &Options::_context_gsm_call,  "khomp-DD-CC"));
137     Globals::options.add(Config::Option("context-gsm-call-alt", &Options::_context2_gsm_call, "khomp-DD"));
138     Globals::options.add(Config::Option("context-gsm-sms",      &Options::_context_gsm_sms,   "khomp-sms-DD-CC"));
139     Globals::options.add(Config::Option("context-digital",      &Options::_context_digital,   "khomp-DD-LL"));
140     Globals::options.add(Config::Option("context-pr",           &Options::_context_pr,        "khomp-DD-CC"));
141 
142     Globals::options.add(Config::Option("accountcode", &Options::_accountcode, ""));
143 
144     Config::StringSet activation_strings;
145     activation_strings.insert("auto");
146     activation_strings.insert("manual");
147 
148     Globals::options.add(Config::Option("kommuter-activation", &Options::_kommuter_activation , "auto", activation_strings));
149     Globals::options.add(Config::Option("kommuter-timeout",    &Options::_kommuter_timeout ,(unsigned int) 10 , (unsigned int) 0 , (unsigned int) 255));
150 
151     Globals::options.add(Config::Option("audio-packet-length", &Options::_audio_packet_size,
152          (unsigned int)KHOMP_READ_PACKET_SIZE, (unsigned int)KHOMP_MIN_READ_PACKET_SIZE, (unsigned int)KHOMP_MAX_READ_PACKET_SIZE, 8u));
153 
154     Globals::options.add(Config::Option("user-transfer-digits", &Options::_user_xfer_digits, ""));
155 
156     /* aliases */
157     Globals::options.synonym("context-gsm", "context-gsm-call");
158     Globals::options.synonym("context-gsm-alt", "context-gsm-call-alt");
159     Globals::options.synonym("echocanceller", "echo-canceller");
160     Globals::options.synonym("dtmfsuppression", "out-of-band-dtmfs");
161     Globals::options.synonym("dtmfsupression", "out-of-band-dtmfs");
162     Globals::options.synonym("pulsedetection", "pulse-forwarding");
163     Globals::options.synonym("r2preconnectwait", "r2-preconnect-wait");
164     Globals::options.synonym("bridge", "native-bridge");
165     Globals::options.synonym("suppressiondelay", "suppression-delay");
166     Globals::options.synonym("log", "log-to-disk");
167     Globals::options.synonym("volume", "output-volume");
168     Globals::options.synonym("disconnectdelay", "disconnect-delay");
169 }
170 
obtain(void)171 void Opt::obtain(void)
172 {
173     try
174     {
175         /* everything should start clean! */
176         cleanConfiguration();
177 
178         /* reset loaded options */
179         Globals::options.reset(&Opt::_options);
180 
181         /* should be loaded *BEFORE* start_k3l */
182         loadConfiguration("khomp.conf", NULL);
183 
184         /* commit, loading defaults where needed */
185             Config::Options::Messages msgs = Globals::options.commit(&Opt::_options);
186 
187         /* config already full loaded at this point, so we can use our own log system... */
188         for (Config::Options::Messages::iterator i = msgs.begin(); i != msgs.end(); i++)
189         {
190             DBG(FUNC,FMT("%s") % (*i).c_str());
191         }
192     }
193     catch (std::runtime_error & e)
194     {
195         LOG(ERROR, FMT("unable to obtain general options: %s: procedure aborted!") % e.what());
196     }
197 }
198 
commit(void)199 void Opt::commit(void)
200 {
201     processGroupString();
202 
203     /* Check FXS hotlines correcteness */
204     OrigToDestMapType::const_iterator endOfHotlines = _fxs_hotline.end();
205 
206     for (OrigToDestMapType::const_iterator i = _fxs_hotline.begin(); i != endOfHotlines; i++)
207     {
208         BranchToObjectMapType::const_iterator j = _fxs_branch_map.find(i->first);
209 
210         if (j == _fxs_branch_map.end())
211         {
212             LOG(ERROR, FMT("unable to find branch '%s': hotline '%s' to '%s' is invalid!")
213                 % i->first % i->first % i->second);
214         }
215     }
216 
217     /* Check FXS options correcteness */
218     BranchToOptMapType::const_iterator endOfOptions = _branch_options.end();
219 
220     for (BranchToOptMapType::const_iterator i = _branch_options.begin(); i != endOfOptions; i++)
221     {
222         BranchToObjectMapType::const_iterator j = _fxs_branch_map.find(i->first);
223         if (j == _fxs_branch_map.end())
224         {
225             LOG(ERROR, FMT("unable to find branch '%s' for options '%s'")
226                 % i->first % i->second);
227         }
228     }
229 }
230 
loadConfiguration(const char * file_name,const char ** section,bool show_errors)231 void Opt::loadConfiguration(const char *file_name, const char **section, bool show_errors)
232 {
233     switch_xml_t cfg, xml, settings;
234 
235     if (!(xml = switch_xml_open_cfg(file_name, &cfg, NULL)))
236     {
237         if (show_errors)
238         {
239             LOG(ERROR,FMT("Open of %s failed") % file_name);
240         }
241 
242         return;
243     }
244 
245     /* Load all the global settings pertinent to all boards */
246     settings = processSimpleXML(cfg,"settings");
247 
248     /* Process channel settings */
249     processSimpleXML(settings,"channels");
250 
251     /* Process groups settings */
252     processGroupXML(settings);
253 
254     /* Process cadence settings */
255     processCadenceXML(settings);
256 
257     /* Process fxs branches settings */
258     processFXSBranchesXML(settings);
259 
260     /* Process hotlines settings */
261     processFXSHotlines(settings);
262 
263     /* Process fxs options settings */
264     processFXSOptions(settings);
265 
266     switch_xml_free(xml);
267 }
268 
cleanConfiguration(void)269 void Opt::cleanConfiguration(void)
270 {
271     _fxs_orig_base.clear();
272     _fxs_hotline.clear();
273     _fxs_branch_map.clear();
274     _branch_options.clear();
275 
276     _groups.clear();
277     _cadences.clear();
278 
279     _cadences.insert(CadencesPairType("fast-busy", CadenceType(100,100)));
280     _cadences.insert(CadencesPairType("ringback", CadenceType(1000,4000)));
281     _cadences.insert(CadencesPairType("pbx-dialtone", CadenceType(1000,100)));
282     _cadences.insert(CadencesPairType("co-dialtone", CadenceType(0,0)));
283     _cadences.insert(CadencesPairType("vm-dialtone", CadenceType(1000,100,100,100)));
284 }
285 
286 /*
287 void Options::AmaflagOption::operator()(const Config::StringType & str)
288 {
289     //_value = Strings::tolong(str);
290     //if(_value < 0)
291     //    throw Config::Failure(STG(FMT("invalid AMA flags: %s") % str));
292 }
293 
294 void Options::CallGroupOption::operator()(const Config::StringType & str)
295 {
296     _groups = str;
297 }
298 
299 void Options::PickupGroupOption::operator()(const Config::StringType & str)
300 {
301     _groups = str;
302 }
303 */
304 
operator ()(const Config::StringType & str)305 void Options::RecordPrefixOption::operator()(const Config::StringType & str)
306 {
307     if (mkdir(str.c_str(), 493 /* 0755 */) < 0 && errno != EEXIST)
308         throw Config::Failure("the default recording directory could not be created.");
309 
310     _value = str;
311 }
312 
operator ()(const Config::StringType & str)313 void Options::CentralOfficeDialtone::operator()(const Config::StringType & str)
314 {
315     Strings::vector_type tokens;
316     Strings::tokenize(str, tokens, ",");
317 
318     for (Strings::vector_type::iterator i = tokens.begin(); i != tokens.end(); i++)
319         _value.push_back(*i);
320 }
321 
operator ()(const Config::StringType & str)322 void Options::LogDiskOption::operator()(const Config::StringType & str)
323 {
324     K::Logger::processLogDisk(NULL, str, false, true);
325 }
326 
operator ()(const Config::StringType & str)327 void Options::LogConsoleOption::operator()(const Config::StringType & str)
328 {
329     K::Logger::processLogConsole(NULL, str, false, true);
330 }
331 
operator ()(const Config::StringType & str)332 void Options::LogTraceOption::operator()(const Config::StringType & str)
333 {
334     Strings::vector_type tokens;
335     Strings::tokenize(str, tokens, ",");
336 
337     bool         enable_k3l_tracing  = false;
338     bool         enable_r2_tracing   = false;
339     bool         enable_rdsi_tracing = false;
340 
341     for (Strings::vector_type::iterator i = tokens.begin(); i != tokens.end(); i++)
342     {
343         std::string tok = Strings::trim(*i);
344 
345         /**/ if (tok == "k3l")  enable_k3l_tracing = true;
346         else if (tok == "r2")   enable_r2_tracing = true;
347         else if (tok == "rdsi") enable_rdsi_tracing = true;
348         else
349         {
350             LOG(ERROR, FMT("invalid string '%s' for option 'trace', ignoring...") % tok)
351         }
352     }
353 
354     Logfile logfile;
355 
356     /* k3l tracing */
357     if (enable_k3l_tracing)
358     {
359         K::LogConfig::set(logfile, "K3L", "Value",        enable_k3l_tracing);
360         K::LogConfig::set(logfile, "K3L", "CallProgress", enable_k3l_tracing);
361         K::LogConfig::set(logfile, "K3L", "CallAnalyzer", enable_k3l_tracing);
362         K::LogConfig::set(logfile, "K3L", "CadenceRecog", enable_k3l_tracing);
363         K::LogConfig::set(logfile, "K3L", "CallControl",  enable_k3l_tracing);
364         K::LogConfig::set(logfile, "K3L", "Fax",          enable_k3l_tracing);
365     }
366 
367     /* r2 tracing */
368     K::LogConfig::set(logfile, "R2", "Value",     enable_r2_tracing);
369     K::LogConfig::set(logfile, "R2", "Signaling", enable_r2_tracing);
370     K::LogConfig::set(logfile, "R2", "States",    enable_r2_tracing);
371 
372     /* ISDN tracing */
373     if (enable_rdsi_tracing ^ Globals::flag_trace_rdsi)
374     {
375         K::LogConfig::set(logfile, "ISDN", "Value", enable_rdsi_tracing);
376         K::LogConfig::set(logfile, "ISDN", "Lapd",  enable_rdsi_tracing);
377         K::LogConfig::set(logfile, "ISDN", "Q931",  enable_rdsi_tracing);
378     }
379 
380     try
381     {
382         Globals::k3lapi.command(-1, -1, CM_LOG_UPDATE);
383     }
384     catch(...)
385     {
386         LOG(ERROR,"Error while send command CM_LOG_UPDATE");
387     }
388 }
389 
processSimpleXML(switch_xml_t & xml,const std::string & child_name)390 switch_xml_t Opt::processSimpleXML(switch_xml_t &xml, const std::string& child_name)
391 {
392     switch_xml_t param, child;
393 
394     if ((child = switch_xml_child(xml, child_name.c_str())))
395     {
396         for (param = switch_xml_child(child, "param"); param; param = param->next)
397         {
398             char *var = (char *) switch_xml_attr_soft(param, "name");
399             char *val = (char *) switch_xml_attr_soft(param, "value");
400 
401             try
402             {
403                 DBG(FUNC,FMT("loading '%s' options: '%s'...")
404                     % var
405                     % val);
406 
407                 Globals::options.process(&Opt::_options, var, val);
408             }
409             catch (Config::Failure e)
410             {
411                 LOG(ERROR,FMT("config processing error: %s. [%s=%s]")
412                     % e.what()
413                     % var
414                     % val);
415 
416             }
417         }
418     }
419 
420     return child;
421 }
422 
processGroupXML(switch_xml_t & xml)423 void Opt::processGroupXML(switch_xml_t &xml)
424 {
425     switch_xml_t param, child;
426 
427     if ((child = switch_xml_child(xml,"groups")))
428     {
429         for (param = switch_xml_child(child, "param"); param; param = param->next)
430         {
431             char *var = (char *) switch_xml_attr_soft(param, "name");
432             char *val = (char *) switch_xml_attr_soft(param, "value");
433 
434             try
435             {
436                 DBG(FUNC,FMT("loading group '%s' options: '%s'...")
437                     % var
438                     % val);
439 
440                 _groups.insert(GroupToDestPairType(var,val));
441 
442             }
443             catch (Config::Failure e)
444             {
445                 LOG(ERROR,FMT("config processing error: %s. [%s=%s]")
446                     % e.what()
447                     % var
448                     % val);
449             }
450         }
451     }
452 }
453 
processCadenceXML(switch_xml_t & xml)454 void Opt::processCadenceXML(switch_xml_t &xml)
455 {
456     switch_xml_t param, child;
457 
458     if ((child = switch_xml_child(xml,"cadences")))
459     {
460         for (param = switch_xml_child(child, "param"); param; param = param->next)
461         {
462             char *var = (char *) switch_xml_attr_soft(param, "name");
463             char *val = (char *) switch_xml_attr_soft(param, "value");
464 
465             try
466             {
467                 DBG(FUNC,FMT("loading cadences '%s' options: '%s'...")
468                     % var
469                     % val);
470 
471                 Strings::vector_type values;
472                 Strings::tokenize(val, values, " :,.");
473 
474                 if (values.size() != 2 && values.size() != 4)
475                 {
476                     LOG(WARNING, FMT("file '%s': wrong number of arguments at cadence '%s'!")
477                         % "khomp.conf.xml"
478                         % var);
479                 }
480                 else
481                 {
482                     CadenceType cadence;
483 
484                     cadence.ring       = Strings::toulong(Strings::trim(values[0]));
485                     cadence.ring_s     = Strings::toulong(Strings::trim(values[1]));
486 
487                     if (values.size() == 4)
488                     {
489                         cadence.ring_ext   = Strings::toulong(Strings::trim(values[2]));
490                         cadence.ring_ext_s = Strings::toulong(Strings::trim(values[3]));
491                     }
492 
493                     _cadences.erase(var); /* erases previous (possibly predefined) cadence */
494                     _cadences.insert(CadencesPairType(var, cadence));
495                 }
496             }
497             catch (Config::Failure e)
498             {
499                 LOG(ERROR,FMT("config processing error: %s. [%s=%s]")
500                     % e.what()
501                     % var
502                     % val);
503 
504             }
505             catch (Strings::invalid_value e)
506             {
507                LOG(ERROR,FMT("file '%s': number expected at cadence '%s', got '%s'.")
508                     % "khomp.conf.xml"
509                     % var
510                     % e.value().c_str());
511             }
512         }
513     }
514 }
515 
processFXSBranchesXML(switch_xml_t & xml)516 void Opt::processFXSBranchesXML(switch_xml_t &xml)
517 {
518     switch_xml_t param, child;
519 
520     if ((child = switch_xml_child(xml,"fxs-branches")))
521     {
522         for (param = switch_xml_child(child, "param"); param; param = param->next)
523         {
524             char *var = (char *) switch_xml_attr_soft(param, "name");
525             char *val = (char *) switch_xml_attr_soft(param, "value");
526 
527 
528             DBG(FUNC,FMT("loading fxs-branches '%s' options: '%s'...")
529                     % var
530                     % val);
531 
532             try
533             {
534                 unsigned long orig_number = Strings::toulong(var);
535 
536                 /* gcc! stop complaining! */
537                 (void)orig_number;
538 
539                 Strings::vector_type boards;
540                 Strings::tokenize(val, boards, " :,");
541 
542                 if (boards.size() < 1)
543                 {
544                     DBG(FUNC,FMT("file '%s': orig number '%s' without any board!")
545                         % "khomp.conf.xml"
546                         % var);
547                     continue;
548                 }
549 
550                 for (Strings::vector_type::iterator iter = boards.begin(); iter != boards.end(); iter++)
551                 {
552                     /* quebrar em strings por vírgula/espaço */
553                     unsigned long serial_number = Strings::toulong(Strings::trim(*iter));
554 
555                     bool found = false;
556 
557                     for (unsigned int device = 0; device < Globals::k3lapi.device_count(); device++)
558                     {
559                         const K3L_DEVICE_CONFIG & conf = Globals::k3lapi.device_config(device);
560 
561                         std::string str_serial(conf.SerialNumber);
562 
563                         if (Strings::toulong(str_serial) == serial_number)
564                         {
565                             found = true;
566 
567                             _fxs_orig_base.insert(BoardToOrigPairType(device, var));
568                             break;
569                         }
570                     }
571 
572                     if (!found)
573                     {
574                         LOG(WARNING, FMT("file 'khomp.conf.xml': board with serial number '%u' not found!")
575                         % serial_number);
576 
577                         break;
578                     }
579                 }
580             }
581             catch (Config::Failure e)
582             {
583                 LOG(ERROR,FMT("config processing error: %s. [%s=%s]")
584                     % e.what()
585                     % var
586                     % val);
587             }
588             catch (Strings::invalid_value & e)
589             {
590                 LOG(ERROR, D("invalid numeric value: %s") % e.value());
591             }
592             catch (...)
593             {
594                 LOG(ERROR, D("config processing error..."));
595             }
596         }
597     }
598 }
599 
processFXSHotlines(switch_xml_t & xml)600 void Opt::processFXSHotlines(switch_xml_t &xml)
601 {
602     switch_xml_t param, child;
603 
604     if ((child = switch_xml_child(xml,"fxs-hotlines")))
605     {
606         for (param = switch_xml_child(child, "param"); param; param = param->next)
607         {
608             char *var = (char *) switch_xml_attr_soft(param, "name");
609             char *val = (char *) switch_xml_attr_soft(param, "value");
610 
611             try
612             {
613                 DBG(FUNC,FMT("loading fxs-hotlines '%s' options: '%s'...")
614                     % var
615                     % val);
616 
617                 unsigned long orig_number = Strings::toulong(var);
618 
619                 (void)orig_number; /* stop complaining! */
620 
621                 _fxs_hotline.insert(OrigToDestPairType(var, val));
622 
623             }
624             catch (Config::Failure e)
625             {
626                 LOG(ERROR,FMT("config processing error: %s. [%s=%s]")
627                     % e.what()
628                     % var
629                     % val);
630             }
631             catch (Strings::invalid_value e)
632             {
633                 LOG(WARNING, FMT("file '%s': number expected, got '%s'!")
634                     % "khomp.conf.xml" % e.value().c_str());
635             }
636         }
637     }
638 }
639 
processFXSOptions(switch_xml_t & xml)640 void Opt::processFXSOptions(switch_xml_t &xml)
641 {
642     switch_xml_t param, child;
643 
644     if ((child = switch_xml_child(xml,"fxs-options")))
645     {
646         for (param = switch_xml_child(child, "param"); param; param = param->next)
647         {
648             char *var = (char *) switch_xml_attr_soft(param, "name");
649             char *val = (char *) switch_xml_attr_soft(param, "value");
650 
651             try
652             {
653                 DBG(FUNC,FMT("loading fxs-options '%s' options: '%s'...")
654                     % var
655                     % val);
656 
657                 Strings::vector_type branches;
658                 Strings::tokenize(var, branches, " ,");
659 
660                 if (branches.size() < 1)
661                 {
662                     //TODO: Get linenumber
663                     LOG(WARNING, FMT("file '%s': no branches specified in line %d!")
664                     % "khomp.conf.xml" % 0);
665                 }
666                 else
667                 {
668                     for (Strings::vector_type::iterator iter = branches.begin();
669                             iter != branches.end(); iter++)
670                     {
671                         std::string tmp_branch = Strings::trim(*iter);
672 
673                         unsigned long branch_number = Strings::toulong(tmp_branch);
674                         (void) branch_number;
675 
676                         _branch_options.insert(BranchToOptPairType(tmp_branch, val));
677                     }
678                 }
679             }
680             catch (Config::Failure e)
681             {
682                 LOG(ERROR,FMT("config processing error: %s. [%s=%s]")
683                     % e.what()
684                     % var
685                     % val);
686             }
687             catch (Strings::invalid_value e)
688             {
689                 LOG(WARNING, FMT("file '%s': number expected, got '%s'!")
690                     % "khomp.conf.xml" % e.value().c_str());
691             }
692         }
693     }
694 }
695