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