1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Joao Mesquita <jmesquita@freeswitch.org>
27  *
28  */
29 
30 #include <QtGui>
31 #include "fshost.h"
32 
33 /* Declare it globally */
34 FSHost *g_FSHost;
35 
FSHost(QObject * parent)36 FSHost::FSHost(QObject *parent) :
37     QThread(parent)
38 {
39     /* Initialize libs & globals */
40     qDebug() << "Initializing globals..." << endl;
41     switch_core_setrlimits();
42     switch_core_set_globals();
43 
44     qRegisterMetaType<QSharedPointer<Call> >("QSharedPointer<Call>");
45     qRegisterMetaType<QSharedPointer<switch_event_t> >("QSharedPointer<switch_event_t>");
46     qRegisterMetaType<QSharedPointer<switch_log_node_t> >("QSharedPointer<switch_log_node_t>");
47     qRegisterMetaType<switch_log_level_t>("switch_log_level_t");
48     qRegisterMetaType<QSharedPointer<Channel> >("QSharedPointer<Channel>");
49     qRegisterMetaType<QSharedPointer<Account> >("QSharedPointer<Account>");
50 
51     connect(this, SIGNAL(loadedModule(QString,QString)), this, SLOT(minimalModuleLoaded(QString,QString)));
52 
53 }
54 
isModuleLoaded(QString modName)55 QBool FSHost::isModuleLoaded(QString modName)
56 {
57     return _loadedModules.contains(modName);
58 }
59 
createFolders()60 void FSHost::createFolders()
61 {
62     /* Create directory structure for softphone with default configs */
63     QDir conf_dir = QDir::home();
64     if (!conf_dir.exists(".fscomm"))
65         conf_dir.mkpath(".fscomm");
66     if (!conf_dir.exists(".fscomm/recordings"))
67         conf_dir.mkpath(".fscomm/recordings");
68     if (!conf_dir.exists(".fscomm/sounds")) {
69         conf_dir.mkpath(".fscomm/sounds");
70         QFile::copy(":/sounds/test.wav", QString("%1/.fscomm/sounds/test.wav").arg(QDir::homePath()));
71     }
72     if(!QFile::exists(QString("%1/.fscomm/conf/freeswitch.xml").arg(conf_dir.absolutePath()))) {
73         conf_dir.mkdir(".fscomm/conf");
74         QFile rootXML(":/confs/freeswitch.xml");
75         QString dest = QString("%1/.fscomm/conf/freeswitch.xml").arg(conf_dir.absolutePath());
76         rootXML.copy(dest);
77     }
78 
79     /* Set all directories to the home user directory */
80     if (conf_dir.cd(".fscomm"))
81     {
82         SWITCH_GLOBAL_dirs.conf_dir = (char *) malloc(strlen(QString("%1/conf").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
83         if (!SWITCH_GLOBAL_dirs.conf_dir) {
84             emit coreLoadingError("Cannot allocate memory for conf_dir.");
85         }
86         strcpy(SWITCH_GLOBAL_dirs.conf_dir, QString("%1/conf").arg(conf_dir.absolutePath()).toAscii().constData());
87 
88         SWITCH_GLOBAL_dirs.log_dir = (char *) malloc(strlen(QString("%1/log").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
89         if (!SWITCH_GLOBAL_dirs.log_dir) {
90             emit coreLoadingError("Cannot allocate memory for log_dir.");
91         }
92         strcpy(SWITCH_GLOBAL_dirs.log_dir, QString("%1/log").arg(conf_dir.absolutePath()).toAscii().constData());
93 
94         SWITCH_GLOBAL_dirs.run_dir = (char *) malloc(strlen(QString("%1/run").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
95         if (!SWITCH_GLOBAL_dirs.run_dir) {
96             emit coreLoadingError("Cannot allocate memory for run_dir.");
97         }
98         strcpy(SWITCH_GLOBAL_dirs.run_dir, QString("%1/run").arg(conf_dir.absolutePath()).toAscii().constData());
99 
100         SWITCH_GLOBAL_dirs.db_dir = (char *) malloc(strlen(QString("%1/db").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
101         if (!SWITCH_GLOBAL_dirs.db_dir) {
102             emit coreLoadingError("Cannot allocate memory for db_dir.");
103         }
104         strcpy(SWITCH_GLOBAL_dirs.db_dir, QString("%1/db").arg(conf_dir.absolutePath()).toAscii().constData());
105 
106         SWITCH_GLOBAL_dirs.script_dir = (char *) malloc(strlen(QString("%1/script").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
107         if (!SWITCH_GLOBAL_dirs.script_dir) {
108             emit coreLoadingError("Cannot allocate memory for script_dir.");
109         }
110         strcpy(SWITCH_GLOBAL_dirs.script_dir, QString("%1/script").arg(conf_dir.absolutePath()).toAscii().constData());
111 
112         SWITCH_GLOBAL_dirs.htdocs_dir = (char *) malloc(strlen(QString("%1/htdocs").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
113         if (!SWITCH_GLOBAL_dirs.htdocs_dir) {
114             emit coreLoadingError("Cannot allocate memory for htdocs_dir.");
115         }
116         strcpy(SWITCH_GLOBAL_dirs.htdocs_dir, QString("%1/htdocs").arg(conf_dir.absolutePath()).toAscii().constData());
117     }
118 }
119 
generalLoggerHandler(QSharedPointer<switch_log_node_t> node,switch_log_level_t level)120 void FSHost::generalLoggerHandler(QSharedPointer<switch_log_node_t>node, switch_log_level_t level)
121 {
122     emit eventLog(node, level);
123 }
124 
run(void)125 void FSHost::run(void)
126 {
127     switch_core_flag_t flags = SCF_USE_SQL | SCF_USE_AUTO_NAT;
128     const char *err = NULL;
129     switch_bool_t console = SWITCH_FALSE;
130     switch_status_t destroy_status;
131 
132     createFolders();
133 
134     /* If you need to override configuration directories, you need to change them in the SWITCH_GLOBAL_dirs global structure */
135     qDebug() << "Initializing core...";
136     /* Initialize the core and load modules, that will startup FS completely */
137     if (switch_core_init(flags, console, &err) != SWITCH_STATUS_SUCCESS) {
138         fprintf(stderr, "Failed to initialize FreeSWITCH's core: %s\n", err);
139         emit coreLoadingError(err);
140     }
141 
142     qDebug() << "Everything OK, Entering runtime loop ...";
143 
144     if (switch_event_bind("FSHost", SWITCH_EVENT_ALL, SWITCH_EVENT_SUBCLASS_ANY, eventHandlerCallback, NULL) != SWITCH_STATUS_SUCCESS) {
145             switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
146     }
147 
148     emit loadingModules("Loading modules...", Qt::AlignRight|Qt::AlignBottom, Qt::blue);
149     if (switch_core_init_and_modload(flags, console, &err) != SWITCH_STATUS_SUCCESS) {
150         fprintf(stderr, "Failed to initialize FreeSWITCH's core: %s\n", err);
151         emit coreLoadingError(err);
152     }
153 
154     switch_log_bind_logger(loggerHandler, SWITCH_LOG_DEBUG, SWITCH_FALSE);
155     emit ready();
156 
157     /* Go into the runtime loop. If the argument is true, this basically sets runtime.running = 1 and loops while that is set
158      * If its false, it initializes the libedit for the console, then does the same thing
159      */
160     switch_core_runtime_loop(!console);
161     fflush(stdout);
162 
163 
164     switch_event_unbind_callback(eventHandlerCallback);
165     /* When the runtime loop exits, its time to shutdown */
166     destroy_status = switch_core_destroy();
167     if (destroy_status == SWITCH_STATUS_SUCCESS)
168     {
169         qDebug() << "We have properly shutdown the core.";
170     }
171 }
172 
generalEventHandler(QSharedPointer<switch_event_t> event)173 void FSHost::generalEventHandler(QSharedPointer<switch_event_t>event)
174 {
175     QString uuid = switch_event_get_header_nil(event.data(), "Unique-ID");
176 
177     emit newEvent(event);
178 
179     switch(event.data()->event_id) {
180     case SWITCH_EVENT_CHANNEL_CREATE: /*1A - 17B*/
181         {
182             eventChannelCreate(event, uuid);
183             break;
184         }
185     case SWITCH_EVENT_CHANNEL_ANSWER: /*2A - 31B*/
186         {
187             eventChannelAnswer(event, uuid);
188             break;
189         }
190     case SWITCH_EVENT_CODEC:/*3/4A - 24/25B*/
191         {
192             eventCodec(event, uuid);
193             break;
194         }
195     case SWITCH_EVENT_CHANNEL_STATE:/*6/7/8/37/44/46A - 20/21/22/28/38/40/42B*/
196         {
197             eventChannelState(event, uuid);
198             break;
199         }
200     case SWITCH_EVENT_CHANNEL_EXECUTE:/*9/11/13/15A*/
201         {
202             eventChannelExecute(event, uuid);
203             break;
204         }
205     case SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE:/*10/12/14/16/35A*/
206         {
207             eventChannelExecuteComplete(event, uuid);
208             break;
209         }
210     case SWITCH_EVENT_CHANNEL_OUTGOING:/*18B*/
211         {
212             eventChannelOutgoing(event, uuid);
213             break;
214         }
215     case SWITCH_EVENT_CHANNEL_ORIGINATE:/*19B*/
216         {
217             eventChannelOriginate(event, uuid);
218             break;
219         }
220     case SWITCH_EVENT_CALL_UPDATE:/*23/29/30B*/
221         {
222             eventCallUpdate(event, uuid);
223             break;
224         }
225     case SWITCH_EVENT_CHANNEL_PROGRESS:
226         {
227             eventChannelProgress(event, uuid);
228             break;
229         }
230     case SWITCH_EVENT_CHANNEL_PROGRESS_MEDIA:/*26B*/
231         {
232             eventChannelProgressMedia(event, uuid);
233             break;
234         }
235     case SWITCH_EVENT_CHANNEL_BRIDGE:/*27A*/
236         {
237             eventChannelBridge(event, uuid);
238             break;
239         }
240     /*32?*/
241     /*case SWITCH_EVENT_RECV_INFO:
242         {
243             eventRecvInfo(event, uuid);
244             break;
245         }*/
246     case SWITCH_EVENT_CHANNEL_HANGUP:/*36A-33B*/
247         {
248             eventChannelHangup(event, uuid);
249             break;
250         }
251     case SWITCH_EVENT_CHANNEL_UNBRIDGE:/*34A*/
252         {
253             eventChannelUnbridge(event, uuid);
254             break;
255         }
256     case SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE:/*39/43B*/
257         {
258             eventChannelHangupComplete(event, uuid);
259             break;
260         }
261     case SWITCH_EVENT_CHANNEL_DESTROY:/*45A-41B*/
262         {
263             eventChannelDestroy(event, uuid);
264             break;
265         }
266     case SWITCH_EVENT_CUSTOM:/*5A*/
267         {
268             if (strcmp(event.data()->subclass_name, "sofia::gateway_state") == 0)
269             {
270                 QString state = switch_event_get_header_nil(event.data(), "State");
271                 QString gw = switch_event_get_header_nil(event.data(), "Gateway");
272                 QSharedPointer<Account> acc = _accounts.value(gw);
273                 if (acc.isNull())
274                     return;
275 
276                 if (state == "TRYING") {
277                     acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
278                     acc.data()->setState(FSCOMM_GW_STATE_TRYING);
279                     emit accountStateChange(acc);
280                 } else if (state == "REGISTER") {
281                     acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
282                     acc.data()->setState(FSCOMM_GW_STATE_REGISTER);
283                     emit accountStateChange(acc);
284                 } else if (state == "REGED") {
285                     acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
286                     acc.data()->setState(FSCOMM_GW_STATE_REGED);
287                     emit accountStateChange(acc);
288                 } else if (state == "UNREGED") {
289                     acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
290                     acc.data()->setState(FSCOMM_GW_STATE_UNREGED);
291                     emit accountStateChange(acc);
292                 } else if (state == "UNREGISTER") {
293                     acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
294                     acc.data()->setState(FSCOMM_GW_STATE_UNREGISTER);
295                     emit accountStateChange(acc);
296                 } else if (state =="FAILED") {
297                     acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
298                     acc.data()->setState(FSCOMM_GW_STATE_FAILED);
299                     emit accountStateChange(acc);
300                 } else if (state == "FAIL_WAIT") {
301                     acc.data()->setState(FSCOMM_GW_STATE_FAIL_WAIT);
302                     emit accountStateChange(acc);
303                 } else if (state == "EXPIRED") {
304                     acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
305                     acc.data()->setState(FSCOMM_GW_STATE_EXPIRED);
306                     emit accountStateChange(acc);
307                 } else if (state == "NOREG") {
308                     acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
309                     acc.data()->setState(FSCOMM_GW_STATE_NOREG);
310                     emit accountStateChange(acc);
311                 }
312             }
313             else if (strcmp(event.data()->subclass_name, "sofia::gateway_add") == 0)
314             {
315                 QString gw = switch_event_get_header_nil(event.data(), "Gateway");
316                 Account * accPtr = new Account(gw);
317                 QSharedPointer<Account> acc = QSharedPointer<Account>(accPtr);
318                 acc.data()->setState(FSCOMM_GW_STATE_NOAVAIL);
319                 _accounts.insert(gw, acc);
320                 emit newAccount(acc);
321             }
322             else if (strcmp(event.data()->subclass_name, "sofia::gateway_delete") == 0)
323             {
324                 QSharedPointer<Account> acc = _accounts.take(switch_event_get_header_nil(event.data(), "Gateway"));
325                 if (!acc.isNull())
326                     emit delAccount(acc);
327             }
328             else
329             {
330                 //printEventHeaders(event);
331             }
332             break;
333         }
334     case SWITCH_EVENT_MODULE_LOAD:
335         {
336             QString modType = switch_event_get_header_nil(event.data(), "type");
337             QString modKey = switch_event_get_header_nil(event.data(), "key");
338             emit loadedModule(modType, modKey);
339             break;
340         }
341     default:
342         break;
343     }
344 }
345 
eventChannelCreate(QSharedPointer<switch_event_t> event,QString uuid)346 void FSHost::eventChannelCreate(QSharedPointer<switch_event_t>event, QString uuid)
347 {
348     Channel *channelPtr = new Channel(uuid);
349     QSharedPointer<Channel>channel(channelPtr);
350     _channels.insert(uuid, channel);
351 }
eventChannelAnswer(QSharedPointer<switch_event_t> event,QString uuid)352 void FSHost::eventChannelAnswer(QSharedPointer<switch_event_t>event, QString uuid)
353 {
354     _channels.value(uuid).data()->setDestinatinonNumber(switch_event_get_header_nil(event.data(), "Caller-Destination-Number"));
355     if (_active_calls.contains(uuid))
356     {
357         _active_calls.value(uuid).data()->setAnsweredEpoch(QString(switch_event_get_header_nil(event.data(), "Caller-Channel-Answered-Time")).toULongLong());
358         _active_calls.value(uuid).data()->setState(FSCOMM_CALL_STATE_ANSWERED);
359         emit answered(_active_calls.value(uuid));
360     }
361 }
eventChannelState(QSharedPointer<switch_event_t> event,QString uuid)362 void FSHost::eventChannelState(QSharedPointer<switch_event_t>event, QString uuid)
363 {}
eventChannelExecute(QSharedPointer<switch_event_t> event,QString uuid)364 void FSHost::eventChannelExecute(QSharedPointer<switch_event_t>event, QString uuid)
365 {}
eventChannelExecuteComplete(QSharedPointer<switch_event_t> event,QString uuid)366 void FSHost::eventChannelExecuteComplete(QSharedPointer<switch_event_t>event, QString uuid)
367 {
368     _channels.value(uuid).data()->setPaCallId(atoi(switch_event_get_header_nil(event.data(), "variable_pa_call_id")));
369 }
eventChannelOutgoing(QSharedPointer<switch_event_t> event,QString uuid)370 void FSHost::eventChannelOutgoing(QSharedPointer<switch_event_t>event, QString uuid)
371 {
372     /* Checks if this is an inbound or outbound call */
373     /** Outbound call */
374     if ( strcmp(switch_event_get_header_nil(event.data(), "Caller-Source"), "mod_portaudio") == 0 )
375     {
376         Call *callPtr = new Call();
377 
378         callPtr->setCallDirection(FSCOMM_CALL_DIRECTION_OUTBOUND);
379         callPtr->setChannel(_channels.value(uuid));
380         callPtr->setOtherLegChannel(_channels.value(switch_event_get_header_nil(event.data(), "Other-Leg-Unique-ID")));
381         QSharedPointer<Call> call(callPtr);
382         _active_calls.insert(uuid, call);
383         call.data()->setState(FSCOMM_CALL_STATE_TRYING);
384         emit newOutgoingCall(call);
385     }
386     /** Inbound call */
387     else
388     {
389         Call *callPtr = new Call();
390         callPtr->setCallDirection(FSCOMM_CALL_DIRECTION_INBOUND);
391         callPtr->setChannel(_channels.value(uuid));
392         callPtr->setOtherLegChannel(_channels.value(switch_event_get_header_nil(event.data(), "Other-Leg-Unique-ID")));
393         QSharedPointer<Call> call(callPtr);
394         _active_calls.insert(uuid, call);
395         call.data()->setState(FSCOMM_CALL_STATE_RINGING);
396         _channels.value(uuid).data()->setCreatedEpoch(QString(switch_event_get_header_nil(event.data(), "Caller-Channel-Created-Time")).toULongLong());
397         emit ringing(call);
398     }
399 }
eventChannelOriginate(QSharedPointer<switch_event_t> event,QString uuid)400 void FSHost::eventChannelOriginate(QSharedPointer<switch_event_t>event, QString uuid)
401 {}
eventChannelProgress(QSharedPointer<switch_event_t> event,QString uuid)402 void FSHost::eventChannelProgress(QSharedPointer<switch_event_t>event, QString uuid)
403 {}
eventChannelProgressMedia(QSharedPointer<switch_event_t> event,QString uuid)404 void FSHost::eventChannelProgressMedia(QSharedPointer<switch_event_t>event, QString uuid)
405 {
406     _channels.value(uuid).data()->setProgressEpoch(QString(switch_event_get_header_nil(event.data(), "Caller-Channel-Progress-Time")).toULongLong());
407     if (_active_calls.contains(uuid))
408     {
409         _active_calls.value(uuid).data()->setState(FSCOMM_CALL_STATE_RINGING);
410         emit ringing(_active_calls.value(uuid));
411     }
412 }
eventChannelBridge(QSharedPointer<switch_event_t> event,QString uuid)413 void FSHost::eventChannelBridge(QSharedPointer<switch_event_t>event, QString uuid)
414 {
415     QString time;
416     time = switch_event_get_header_nil(event.data(), "Caller-Channel-Progress-Time");
417     if (time.toULongLong() > 0) _channels.value(uuid).data()->setProgressEpoch(time.toULongLong());
418     time = switch_event_get_header_nil(event.data(), "Caller-Channel-Progress-Media-Time");
419     if (time.toULongLong() > 0) _channels.value(uuid).data()->setProgressMediaEpoch(time.toULongLong());
420 }
eventChannelHangup(QSharedPointer<switch_event_t> event,QString uuid)421 void FSHost::eventChannelHangup(QSharedPointer<switch_event_t>event, QString uuid)
422 {}
eventChannelUnbridge(QSharedPointer<switch_event_t> event,QString uuid)423 void FSHost::eventChannelUnbridge(QSharedPointer<switch_event_t>event, QString uuid)
424 {}
eventChannelHangupComplete(QSharedPointer<switch_event_t> event,QString uuid)425 void FSHost::eventChannelHangupComplete(QSharedPointer<switch_event_t>event, QString uuid)
426 {
427     if (_active_calls.contains(uuid))
428     {
429         if (_active_calls.value(uuid).data()->getState() != FSCOMM_CALL_STATE_ANSWERED)
430         {
431             _active_calls.value(uuid).data()->setState(FSCOMM_CALL_STATE_FAILED);
432             _active_calls.value(uuid).data()->setCause(switch_event_get_header_nil(event.data(), "variable_originate_disposition"));
433             emit callFailed(_active_calls.value(uuid));
434             return;
435         }
436         emit hungup(_active_calls.take(uuid));
437     }
438 }
eventChannelDestroy(QSharedPointer<switch_event_t> event,QString uuid)439 void FSHost::eventChannelDestroy(QSharedPointer<switch_event_t>event, QString uuid)
440 {
441     _channels.take(uuid);
442 }
eventCodec(QSharedPointer<switch_event_t> event,QString uuid)443 void FSHost::eventCodec(QSharedPointer<switch_event_t>event, QString uuid)
444 {
445     _channels.value(uuid).data()->setCidName(switch_event_get_header_nil(event.data(), "Caller-Caller-ID-Name"));
446     _channels.value(uuid).data()->setCidNumber(switch_event_get_header_nil(event.data(), "Caller-Caller-ID-Number"));
447 }
eventCallUpdate(QSharedPointer<switch_event_t> event,QString uuid)448 void FSHost::eventCallUpdate(QSharedPointer<switch_event_t>event, QString uuid)
449 {}
eventRecvInfo(QSharedPointer<switch_event_t> event,QString uuid)450 void FSHost::eventRecvInfo(QSharedPointer<switch_event_t>event, QString uuid)
451 {}
452 
minimalModuleLoaded(QString modType,QString modKey)453 void FSHost::minimalModuleLoaded(QString modType, QString modKey)
454 {
455     if (modType == "endpoint")
456     {
457         _loadedModules.append(modKey);
458     }
459 }
460 
accountReloadCmd(QSharedPointer<Account> acc)461 void FSHost::accountReloadCmd(QSharedPointer<Account> acc)
462 {
463     QString res;
464     QString arg = QString("profile softphone killgw %1").arg(acc.data()->getName());
465 
466     connect(this, SIGNAL(delAccount(QSharedPointer<Account>)), this, SLOT(accountReloadSlot(QSharedPointer<Account>)));
467 
468     if (g_FSHost->sendCmd("sofia", arg.toAscii().data() , &res) != SWITCH_STATUS_SUCCESS)
469     {
470         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not killgw %s from profile softphone.\n",
471                           acc.data()->getName().toAscii().data());
472     }
473     _reloading_Accounts.append(acc.data()->getName());
474 }
475 
accountReloadSlot(QSharedPointer<Account> acc)476 void FSHost::accountReloadSlot(QSharedPointer<Account> acc)
477 {
478     if (_reloading_Accounts.contains(acc.data()->getName()))
479     {
480         _reloading_Accounts.takeAt(_reloading_Accounts.indexOf(acc.data()->getName(), 0));
481         QString res;
482         if (g_FSHost->sendCmd("sofia", "profile softphone rescan", &res) != SWITCH_STATUS_SUCCESS)
483         {
484             switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not rescan the softphone profile.\n");
485             return;
486         }
487         if (_reloading_Accounts.isEmpty())
488             disconnect(this, SLOT(accountReloadSlot(QSharedPointer<Account>)));
489     }
490 }
491 
sendCmd(const char * cmd,const char * args,QString * res)492 switch_status_t FSHost::sendCmd(const char *cmd, const char *args, QString *res)
493 {
494     switch_status_t status = SWITCH_STATUS_FALSE;
495     switch_stream_handle_t stream = { 0 };
496     SWITCH_STANDARD_STREAM(stream);
497     //qDebug() << "Sending command: " << cmd << args << endl;
498     status = switch_api_execute(cmd, args, NULL, &stream);
499     *res = switch_str_nil((char *) stream.data);
500     switch_safe_free(stream.data);
501 
502     return status;
503 }
504 
getAccountByUUID(QString uuid)505 QSharedPointer<Account> FSHost::getAccountByUUID(QString uuid)
506 {
507     foreach(QSharedPointer<Account> acc, _accounts.values())
508     {
509         if (acc.data()->getUUID() == uuid)
510             return acc;
511     }
512     return QSharedPointer<Account>();
513 }
514 
getCurrentActiveCall()515 QSharedPointer<Call> FSHost::getCurrentActiveCall()
516 {
517     foreach(QSharedPointer<Call> call, _active_calls.values())
518     {
519         if (call.data()->isActive())
520             return call;
521     }
522     return QSharedPointer<Call>();
523 }
524 
printEventHeaders(QSharedPointer<switch_event_t> event)525 void FSHost::printEventHeaders(QSharedPointer<switch_event_t>event)
526 {
527     switch_event_header_t *hp;
528     qDebug() << QString("Received event: %1(%2)").arg(switch_event_name(event.data()->event_id), switch_event_get_header_nil(event.data(), "Event-Subclass"));
529     for (hp = event.data()->headers; hp; hp = hp->next) {
530         qDebug() << hp->name << "=" << hp->value;
531     }
532     qDebug() << "\n\n";
533 }
534 
getAccountByName(QString accStr)535 QSharedPointer<Account> FSHost::getAccountByName(QString accStr)
536 {
537     foreach(QSharedPointer<Account> acc, _accounts.values())
538     {
539         if (acc.data()->getName() == accStr)
540             return acc;
541     }
542     return QSharedPointer<Account>();
543 }
544 
getCurrentDefaultAccount()545 QSharedPointer<Account> FSHost::getCurrentDefaultAccount()
546 {
547     ISettings *settings = new ISettings();
548     //settings->beginGroup("FreeSWITCH/conf/globals");
549     //QString accString = settings->value("default_gateway").toString();
550     //settings->endGroup();
551     delete (settings);
552     return getAccountByName("Other"); /* Pay attention to this! */
553 }
554 
555 /*
556    Used to match callback from fs core. We dup the event and call the class
557    method callback to make use of the signal/slot infrastructure.
558   */
eventHandlerCallback(switch_event_t * event)559 static void eventHandlerCallback(switch_event_t *event)
560 {
561     switch_event_t *clone = NULL;
562     if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
563         QSharedPointer<switch_event_t> e(clone);
564         g_FSHost->generalEventHandler(e);
565     }
566 }
567 
568 /*
569   Used to propagate logs on the application
570   */
loggerHandler(const switch_log_node_t * node,switch_log_level_t level)571 static switch_status_t loggerHandler(const switch_log_node_t *node, switch_log_level_t level)
572 {
573     switch_log_node_t *clone = switch_log_node_dup(node);
574     QSharedPointer<switch_log_node_t> l(clone);
575     g_FSHost->generalLoggerHandler(l, level);
576     return SWITCH_STATUS_SUCCESS;
577 }
578