]> git.ipfire.org Git - thirdparty/freeswitch.git/blame - src/switch_cpp.cpp
unint. var fix
[thirdparty/freeswitch.git] / src / switch_cpp.cpp
CommitLineData
03845667
MJ
1/*
2 * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3 * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
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 <anthmct@yahoo.com>
21 * Portions created by the Initial Developer are Copyright (C)
22 * the Initial Developer. All Rights Reserved.
23 *
24 * Contributor(s):
25 *
26 * Anthony Minessale II <anthmct@yahoo.com>
27 *
28 *
29 * switch_cpp.cpp -- C++ wrapper
30 *
31 */
32
83f84876
AM
33#include <switch.h>
34#include <switch_cpp.h>
35
8107c49a
MJ
36#ifdef _MSC_VER
37#pragma warning(disable:4127 4003)
38#endif
39
eec83be1
AM
40static void event_handler(switch_event_t *event)
41{
a1cf7067
AM
42 EventConsumer *E = (EventConsumer *) event->bind_user_data;
43 switch_event_t *dup;
44
45 switch_event_dup(&dup, event);
46
47 if (switch_queue_trypush(E->events, dup) != SWITCH_STATUS_SUCCESS) {
48 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot queue any more events.....\n");
49 }
50
eec83be1
AM
51}
52
a1cf7067 53SWITCH_DECLARE_CONSTRUCTOR EventConsumer::EventConsumer(const char *event_name, const char *subclass_name)
eec83be1 54{
a1cf7067
AM
55 switch_name_event(event_name, &e_event_id);
56 switch_core_new_memory_pool(&pool);
57
eec83be1 58 if (!switch_strlen_zero(subclass_name)) {
a1cf7067 59 e_subclass_name = switch_core_strdup(pool, subclass_name);
eec83be1 60 } else {
a1cf7067 61 e_subclass_name = NULL;
eec83be1
AM
62 }
63
a1cf7067
AM
64 switch_queue_create(&events, 5000, pool);
65
66 if (switch_event_bind_removable(__FILE__, e_event_id, e_subclass_name, event_handler, this, &node) == SWITCH_STATUS_SUCCESS) {
67 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "bound to %s %s\n", event_name, switch_str_nil(e_subclass_name));
68 } else {
69 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot bind to %s %s\n", event_name, switch_str_nil(e_subclass_name));
eec83be1
AM
70 }
71
a1cf7067
AM
72}
73
eec83be1 74
a1cf7067
AM
75SWITCH_DECLARE(Event *) EventConsumer::pop(int block)
76{
77 void *pop = NULL;
78 Event *ret = NULL;
79 switch_event_t *event;
eec83be1 80
a1cf7067
AM
81 if (block) {
82 switch_queue_pop(events, &pop);
83 } else {
84 switch_queue_trypop(events, &pop);
85 }
86
87 if ((event = (switch_event_t *) pop)) {
88 ret = new Event(event);
89 }
eec83be1 90
a1cf7067
AM
91 return ret;
92}
eec83be1
AM
93
94SWITCH_DECLARE_CONSTRUCTOR EventConsumer::~EventConsumer()
95{
eec83be1
AM
96 if (node) {
97 switch_event_unbind(&node);
98 }
a1cf7067
AM
99
100 switch_core_destroy_memory_pool(&pool);
eec83be1 101}
aa47e3e5
AM
102
103SWITCH_DECLARE_CONSTRUCTOR IVRMenu::IVRMenu(IVRMenu *main,
104 const char *name,
105 const char *greeting_sound,
106 const char *short_greeting_sound,
107 const char *invalid_sound,
108 const char *exit_sound,
109 const char *confirm_macro,
110 const char *confirm_key,
111 int confirm_attempts,
112 int inter_timeout,
113 int digit_len,
114 int timeout,
115 int max_failures)
116{
117 menu = NULL;
118 switch_core_new_memory_pool(&pool);
119 switch_assert(pool);
120 if (switch_strlen_zero(name)) {
121 name = "no name";
122 }
123
124 switch_ivr_menu_init(&menu, main ? main->menu : NULL, name, greeting_sound, short_greeting_sound, invalid_sound,
125 exit_sound, confirm_macro, confirm_key, confirm_attempts, inter_timeout, digit_len, timeout, max_failures, pool);
126
127
128}
129
130SWITCH_DECLARE_CONSTRUCTOR IVRMenu::~IVRMenu()
131{
132 if (menu) {
133 switch_ivr_menu_stack_free(menu);
134 }
135 switch_core_destroy_memory_pool(&pool);
136}
137
138SWITCH_DECLARE(void) IVRMenu::bindAction(char *action, const char *arg, const char *bind)
139{
140 switch_ivr_action_t ivr_action = SWITCH_IVR_ACTION_NOOP;
141
878bbceb
AM
142 this_check_void();
143
aa47e3e5
AM
144 if (switch_ivr_menu_str2action(action, &ivr_action) == SWITCH_STATUS_SUCCESS) {
145 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "bind %s to %s(%s)\n", bind, action, arg);
146 switch_ivr_menu_bind_action(menu, ivr_action, arg, bind);
147 } else {
148 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid action %s\n", action);
149 }
150}
151
152SWITCH_DECLARE(void) IVRMenu::execute(CoreSession *session, const char *name)
153{
878bbceb 154 this_check_void();
aa47e3e5
AM
155 switch_ivr_menu_execute(session->session, menu, (char *)name, NULL);
156}
157
8f5a873d
AM
158SWITCH_DECLARE_CONSTRUCTOR API::API()
159{
160 last_data = NULL;
161}
162
163SWITCH_DECLARE_CONSTRUCTOR API::~API()
164{
165 switch_safe_free(last_data);
166}
167
168
1a2131de 169SWITCH_DECLARE(const char *) API::execute(const char *cmd, const char *arg)
8f5a873d
AM
170{
171 switch_stream_handle_t stream = { 0 };
878bbceb 172 this_check("");
8f5a873d
AM
173 SWITCH_STANDARD_STREAM(stream);
174 switch_api_execute(cmd, arg, NULL, &stream);
175 last_data = (char *) stream.data;
176 return last_data;
177}
178
1a2131de 179SWITCH_DECLARE(const char *) API::executeString(const char *cmd)
8f5a873d
AM
180{
181 char *arg;
182 switch_stream_handle_t stream = { 0 };
183 char *mycmd = strdup(cmd);
184
185 switch_assert(mycmd);
186
878bbceb
AM
187 this_check("");
188
8f5a873d
AM
189 if ((arg = strchr(mycmd, ' '))) {
190 *arg++ = '\0';
191 }
192
193 switch_safe_free(last_data);
194
195 SWITCH_STANDARD_STREAM(stream);
196 switch_api_execute(mycmd, arg, NULL, &stream);
197 last_data = (char *) stream.data;
198 switch_safe_free(mycmd);
199 return last_data;
200}
e028f269 201
069d4681 202SWITCH_DECLARE_CONSTRUCTOR Event::Event(const char *type, const char *subclass_name)
ae76db7b
AM
203{
204 switch_event_types_t event_id;
59526679 205
ae76db7b
AM
206 if (switch_name_event(type, &event_id) != SWITCH_STATUS_SUCCESS) {
207 event_id = SWITCH_EVENT_MESSAGE;
208 }
209
210 switch_event_create_subclass(&event, event_id, subclass_name);
59526679
AM
211 serialized_string = NULL;
212 mine = 1;
213}
214
069d4681 215SWITCH_DECLARE_CONSTRUCTOR Event::Event(switch_event_t *wrap_me, int free_me)
59526679
AM
216{
217 event = wrap_me;
218 mine = free_me;
219 serialized_string = NULL;
ae76db7b
AM
220}
221
069d4681 222SWITCH_DECLARE_CONSTRUCTOR Event::~Event()
ae76db7b 223{
59526679
AM
224
225 if (serialized_string) {
226 free(serialized_string);
227 }
228
229 if (event && mine) {
ae76db7b
AM
230 switch_event_destroy(&event);
231 }
232}
233
59526679 234
069d4681 235SWITCH_DECLARE(const char *)Event::serialize(const char *format)
59526679
AM
236{
237 int isxml = 0;
238
878bbceb
AM
239 this_check("");
240
59526679 241
a1cf7067
AM
242 switch_safe_free(serialized_string);
243
59526679
AM
244 if (!event) {
245 return "";
246 }
247
248 if (format && !strcasecmp(format, "xml")) {
249 isxml++;
250 }
251
252 if (isxml) {
253 switch_xml_t xml;
59526679
AM
254 if ((xml = switch_event_xmlize(event, SWITCH_VA_NONE))) {
255 serialized_string = switch_xml_toxml(xml, SWITCH_FALSE);
256 switch_xml_free(xml);
257 return serialized_string;
258 } else {
259 return "";
260 }
261 } else {
262 if (switch_event_serialize(event, &serialized_string, SWITCH_TRUE) == SWITCH_STATUS_SUCCESS) {
a1cf7067 263 serialized_string = switch_mprintf("'%s'", serialized_string);
59526679
AM
264 return serialized_string;
265 }
266 }
267
268 return "";
269
270}
271
069d4681 272SWITCH_DECLARE(bool) Event::fire(void)
ae76db7b 273{
878bbceb
AM
274
275 this_check(false);
276
59526679
AM
277 if (!mine) {
278 switch_log_printf(SWITCH_CHANNEL_LOG,SWITCH_LOG_ERROR, "Not My event!\n");
279 return false;
280 }
281
ae76db7b 282 if (event) {
2b5f3563
AM
283 switch_event_t *new_event;
284 if (switch_event_dup(&new_event, event) == SWITCH_STATUS_SUCCESS) {
285 switch_event_fire(&new_event);
286 return true;
287 }
ae76db7b
AM
288 }
289 return false;
290}
291
b6d649fc 292SWITCH_DECLARE(bool) Event::setPriority(switch_priority_t priority)
ae76db7b 293{
878bbceb
AM
294 this_check(false);
295
ae76db7b
AM
296 if (event) {
297 switch_event_set_priority(event, priority);
298 return true;
299 }
300 return false;
301}
302
1a2131de 303SWITCH_DECLARE(const char *)Event::getHeader(char *header_name)
ae76db7b 304{
878bbceb
AM
305 this_check("");
306
ae76db7b
AM
307 if (event) {
308 return switch_event_get_header(event, header_name);
309 }
310 return NULL;
311}
312
b6d649fc 313SWITCH_DECLARE(bool) Event::addHeader(const char *header_name, const char *value)
ae76db7b 314{
878bbceb
AM
315 this_check(false);
316
ae76db7b
AM
317 if (event) {
318 return switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header_name, value) == SWITCH_STATUS_SUCCESS ? true : false;
319 }
320
321 return false;
322}
323
b6d649fc 324SWITCH_DECLARE(bool) Event::delHeader(const char *header_name)
ae76db7b 325{
878bbceb
AM
326 this_check(false);
327
ae76db7b
AM
328 if (event) {
329 return switch_event_del_header(event, header_name) == SWITCH_STATUS_SUCCESS ? true : false;
330 }
331
332 return false;
333}
334
335
b6d649fc 336SWITCH_DECLARE(bool) Event::addBody(const char *value)
ae76db7b 337{
878bbceb
AM
338 this_check(false);
339
ae76db7b
AM
340 if (event) {
341 return switch_event_add_body(event, "%s", value) == SWITCH_STATUS_SUCCESS ? true : false;
342 }
343
344 return false;
345}
346
b6d649fc 347SWITCH_DECLARE(char *)Event::getBody(void)
ae76db7b 348{
878bbceb
AM
349
350 this_check((char *)"");
351
ae76db7b
AM
352 if (event) {
353 return switch_event_get_body(event);
354 }
355
356 return NULL;
357}
358
d5e4046d 359SWITCH_DECLARE(const char *)Event::getType(void)
b6d649fc 360{
878bbceb
AM
361 this_check("");
362
b6d649fc
AM
363 if (event) {
364 return switch_event_name(event->event_id);
365 }
366
d5e4046d 367 return (char *) "invalid";
b6d649fc
AM
368}
369
a3ccefa7
AM
370
371SWITCH_DECLARE_CONSTRUCTOR DTMF::DTMF(char idigit, uint32_t iduration)
372{
373 digit = idigit;
374
375 if (iduration == 0) {
a358cf8e 376 iduration = SWITCH_DEFAULT_DTMF_DURATION;
a3ccefa7
AM
377 }
378
379 duration = iduration;
380}
381
382SWITCH_DECLARE_CONSTRUCTOR DTMF::~DTMF()
383{
384
385}
386
387
069d4681 388SWITCH_DECLARE_CONSTRUCTOR Stream::Stream()
ae76db7b
AM
389{
390 SWITCH_STANDARD_STREAM(mystream);
391 stream_p = &mystream;
392 mine = 1;
393}
394
069d4681 395SWITCH_DECLARE_CONSTRUCTOR Stream::Stream(switch_stream_handle_t *sp)
ae76db7b
AM
396{
397 stream_p = sp;
398 mine = 0;
399}
400
401
069d4681 402SWITCH_DECLARE_CONSTRUCTOR Stream::~Stream()
ae76db7b
AM
403{
404 if (mine) {
405 switch_safe_free(mystream.data);
406 }
407}
408
069d4681 409SWITCH_DECLARE(void) Stream::write(const char *data)
ae76db7b 410{
878bbceb 411 this_check_void();
ae76db7b
AM
412 stream_p->write_function(stream_p, "%s", data);
413}
414
069d4681 415SWITCH_DECLARE(const char *)Stream::get_data()
ae76db7b 416{
878bbceb
AM
417 this_check("");
418
ae76db7b
AM
419 return stream_p ? (const char *)stream_p->data : NULL;
420}
e028f269
MJ
421
422
47985c56 423SWITCH_DECLARE_CONSTRUCTOR CoreSession::CoreSession()
e028f269 424{
24a27c6e 425 init_vars();
e028f269 426}
83f84876 427
47985c56 428SWITCH_DECLARE_CONSTRUCTOR CoreSession::CoreSession(char *nuuid)
83f84876 429{
a06997ee 430 init_vars();
24a27c6e 431
59526679 432 if (!strchr(nuuid, '/') && (session = switch_core_session_locate(nuuid))) {
94b22258 433 uuid = strdup(nuuid);
d895c81d 434 channel = switch_core_session_get_channel(session);
94b22258 435 allocated = 1;
ae76db7b
AM
436 } else {
437 switch_call_cause_t cause;
438 if (switch_ivr_originate(NULL, &session, &cause, nuuid, 60, NULL, NULL, NULL, NULL, SOF_NONE) == SWITCH_STATUS_SUCCESS) {
d895c81d 439 channel = switch_core_session_get_channel(session);
ae76db7b
AM
440 allocated = 1;
441 switch_set_flag(this, S_HUP);
442 uuid = strdup(switch_core_session_get_uuid(session));
4b929592 443 switch_channel_set_state(switch_core_session_get_channel(session), CS_SOFT_EXECUTE);
ae76db7b
AM
444 }
445 }
83f84876
AM
446}
447
47985c56 448SWITCH_DECLARE_CONSTRUCTOR CoreSession::CoreSession(switch_core_session_t *new_session)
83f84876
AM
449{
450 init_vars();
24a27c6e 451
6d1f4f6d
MJ
452 if (new_session) {
453 session = new_session;
454 channel = switch_core_session_get_channel(session);
455 allocated = 1;
456 switch_core_session_read_lock(session);
457 }
83f84876
AM
458}
459
47985c56 460SWITCH_DECLARE_CONSTRUCTOR CoreSession::~CoreSession()
83f84876 461{
e49f38e8 462 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CoreSession::~CoreSession desctructor\n");
6f78befa 463 switch_channel_t *channel = NULL;
75dbe890 464
75dbe890 465 this_check_void();
75dbe890
AM
466 switch_safe_free(xml_cdr_text);
467 switch_safe_free(uuid);
468 switch_safe_free(tts_name);
469 switch_safe_free(voice_name);
24a27c6e 470
83f84876 471 if (session) {
6f78befa 472 channel = switch_core_session_get_channel(session);
9b303411 473 if (switch_test_flag(this, S_HUP) && !switch_channel_test_flag(channel, CF_TRANSFER)) {
6f78befa
TL
474 switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
475 }
83f84876
AM
476 switch_core_session_rwunlock(session);
477 }
83f84876
AM
478}
479
a5e10ebc
AM
480SWITCH_DECLARE(char *) CoreSession::getXMLCDR()
481{
482
483 switch_xml_t cdr;
878bbceb
AM
484
485 this_check((char *)"");
d5e4046d 486 sanity_check((char *)"");
a5e10ebc
AM
487
488 switch_safe_free(xml_cdr_text);
489
490 if (switch_ivr_generate_xml_cdr(session, &cdr) == SWITCH_STATUS_SUCCESS) {
491 xml_cdr_text = switch_xml_toxml(cdr, SWITCH_FALSE);
492 switch_xml_free(cdr);
493 }
494
495 return (char *) (xml_cdr_text ? xml_cdr_text : "");
496}
497
498SWITCH_DECLARE(void) CoreSession::setEventData(Event *e)
499{
878bbceb 500 this_check_void();
a5e10ebc
AM
501 sanity_check_noreturn;
502
503 if (channel && e->event) {
504 switch_channel_event_set_data(channel, e->event);
505 }
506}
507
47985c56 508SWITCH_DECLARE(int) CoreSession::answer()
83f84876
AM
509{
510 switch_status_t status;
878bbceb 511 this_check(-1);
83f84876
AM
512 sanity_check(-1);
513 status = switch_channel_answer(channel);
514 return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
515}
516
47985c56 517SWITCH_DECLARE(int) CoreSession::preAnswer()
83f84876
AM
518{
519 switch_status_t status;
878bbceb 520 this_check(-1);
83f84876 521 sanity_check(-1);
8107c49a 522 status = switch_channel_pre_answer(channel);
83f84876
AM
523 return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
524}
525
47985c56 526SWITCH_DECLARE(void) CoreSession::hangup(char *cause)
83f84876 527{
878bbceb
AM
528 this_check_void();
529 sanity_check_noreturn;
f45d0601 530 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CoreSession::hangup\n");
996cfa54 531 this->begin_allow_threads();
83f84876 532 switch_channel_hangup(channel, switch_channel_str2cause(cause));
996cfa54 533 this->end_allow_threads();
83f84876
AM
534}
535
47985c56 536SWITCH_DECLARE(void) CoreSession::setPrivate(char *var, void *val)
59526679 537{
878bbceb 538 this_check_void();
59526679
AM
539 sanity_check_noreturn;
540 switch_channel_set_private(channel, var, val);
541}
542
47985c56 543SWITCH_DECLARE(void *)CoreSession::getPrivate(char *var)
59526679 544{
878bbceb 545 this_check(NULL);
59526679
AM
546 sanity_check(NULL);
547 return switch_channel_get_private(channel, var);
548}
549
47985c56 550SWITCH_DECLARE(void) CoreSession::setVariable(char *var, char *val)
83f84876 551{
878bbceb 552 this_check_void();
f32f6f24 553 sanity_check_noreturn;
83f84876
AM
554 switch_channel_set_variable(channel, var, val);
555}
556
47985c56 557SWITCH_DECLARE(const char *)CoreSession::getVariable(char *var)
83f84876 558{
878bbceb
AM
559 this_check("");
560 sanity_check("");
343d77a4 561 return switch_channel_get_variable(channel, var);
83f84876
AM
562}
563
47985c56 564SWITCH_DECLARE(void) CoreSession::execute(char *app, char *data)
83f84876
AM
565{
566 const switch_application_interface_t *application_interface;
878bbceb 567 this_check_void();
f32f6f24 568 sanity_check_noreturn;
83f84876 569
c806a20d 570 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CoreSession::execute. app: %s data:%s\n", app, data);
83f84876 571 if ((application_interface = switch_loadable_module_get_application_interface(app))) {
fedefcb6 572 begin_allow_threads();
83f84876 573 switch_core_session_exec(session, application_interface, data);
fedefcb6 574 end_allow_threads();
83f84876
AM
575 }
576}
577
47985c56 578SWITCH_DECLARE(void) CoreSession::setDTMFCallback(void *cbfunc, char *funcargs) {
6f78befa 579
878bbceb 580 this_check_void();
a06997ee
AM
581 sanity_check_noreturn;
582
6f78befa
TL
583 cb_state.funcargs = funcargs;
584 cb_state.function = cbfunc;
585
586 args.buf = &cb_state;
587 args.buflen = sizeof(cb_state); // not sure what this is used for, copy mod_spidermonkey
588
589 switch_channel_set_private(channel, "CoreSession", this);
590
591 // we cannot set the actual callback to a python function, because
592 // the callback is a function pointer with a specific signature.
593 // so, set it to the following c function which will act as a proxy,
594 // finding the python callback in the args callback args structure
595 args.input_callback = dtmf_callback;
596 ap = &args;
597
598
599}
f45d0601 600
47985c56 601SWITCH_DECLARE(void) CoreSession::sendEvent(Event *sendME)
59526679 602{
878bbceb
AM
603 this_check_void();
604 sanity_check_noreturn;
605
2b5f3563
AM
606 if (sendME->event) {
607 switch_event_t *new_event;
608 if (switch_event_dup(&new_event, sendME->event) == SWITCH_STATUS_SUCCESS) {
609 switch_core_session_receive_event(session, &new_event);
610 }
59526679
AM
611 }
612}
613
47985c56 614SWITCH_DECLARE(int) CoreSession::speak(char *text)
83f84876
AM
615{
616 switch_status_t status;
83f84876 617
878bbceb 618 this_check(-1);
83f84876 619 sanity_check(-1);
6f78befa 620
f45d0601 621 if (!tts_name) {
e49f38e8 622 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No TTS engine specified\n");
f45d0601
MJ
623 return SWITCH_STATUS_FALSE;
624 }
625
626 if (!voice_name) {
e49f38e8 627 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No TTS voice specified\n");
f45d0601
MJ
628 return SWITCH_STATUS_FALSE;
629 }
630
160edc55 631
fedefcb6 632 begin_allow_threads();
160edc55 633 status = switch_ivr_speak_text(session, tts_name, voice_name, text, ap);
fedefcb6 634 end_allow_threads();
83f84876
AM
635 return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
636}
637
47985c56 638SWITCH_DECLARE(void) CoreSession::set_tts_parms(char *tts_name_p, char *voice_name_p)
83f84876 639{
878bbceb 640 this_check_void();
f32f6f24 641 sanity_check_noreturn;
83f84876
AM
642 switch_safe_free(tts_name);
643 switch_safe_free(voice_name);
644 tts_name = strdup(tts_name_p);
645 voice_name = strdup(voice_name_p);
646}
647
c806a20d
TL
648
649
47985c56 650SWITCH_DECLARE(int) CoreSession::collectDigits(int timeout) {
878bbceb 651 this_check(-1);
c806a20d
TL
652 sanity_check(-1);
653 begin_allow_threads();
654 switch_ivr_collect_digits_callback(session, ap, timeout);
655 end_allow_threads();
a4301f0d 656 return SWITCH_STATUS_SUCCESS;
c806a20d
TL
657}
658
444c93c3
MJ
659SWITCH_DECLARE(char *) CoreSession::getDigits(int maxdigits, char *terminators, int timeout)
660{
661 return getDigits(maxdigits, terminators, timeout, 0);
662}
663
38038078 664SWITCH_DECLARE(char *) CoreSession::getDigits(int maxdigits,
4fda174f 665 char *terminators,
444c93c3
MJ
666 int timeout,
667 int interdigit)
83f84876
AM
668{
669 switch_status_t status;
878bbceb 670 this_check((char *)"");
d5e4046d 671 sanity_check((char *)"");
fedefcb6 672 begin_allow_threads();
4fda174f 673 char terminator;
6f78befa 674
85fc8c37 675 memset(dtmf_buf, 0, sizeof(dtmf_buf));
f45d0601
MJ
676 status = switch_ivr_collect_digits_count(session,
677 dtmf_buf,
85fc8c37 678 sizeof(dtmf_buf),
e8f7c1b4 679 maxdigits,
f45d0601 680 terminators,
4fda174f 681 &terminator,
444c93c3 682 (uint32_t) timeout, (uint32_t)interdigit, 0);
6f78befa
TL
683
684 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "getDigits dtmf_buf: %s\n", dtmf_buf);
fedefcb6 685 end_allow_threads();
85fc8c37 686 return dtmf_buf;
83f84876
AM
687}
688
47985c56 689SWITCH_DECLARE(int) CoreSession::transfer(char *extension, char *dialplan, char *context)
83f84876
AM
690{
691 switch_status_t status;
878bbceb 692 this_check(-1);
83f84876 693 sanity_check(-1);
e028f269 694 begin_allow_threads();
83f84876 695 status = switch_ivr_session_transfer(session, extension, dialplan, context);
700aa0df 696 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "transfer result: %d\n", status);
e028f269 697 end_allow_threads();
83f84876
AM
698 return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
699}
700
8e0b64a1
AM
701
702SWITCH_DECLARE(char *) CoreSession::read(int min_digits,
703 int max_digits,
704 const char *prompt_audio_file,
705 int timeout,
706 const char *valid_terminators)
707{
878bbceb
AM
708 this_check((char *)"");
709 sanity_check((char *)"");
8e0b64a1
AM
710 if (min_digits < 1) {
711 min_digits = 1;
712 }
713
714 if (max_digits < 1) {
715 max_digits = 1;
716 }
717
718 if (timeout < 1) {
719 timeout = 1;
720 }
721
722 switch_ivr_read(session, min_digits, max_digits, prompt_audio_file, NULL, dtmf_buf, sizeof(dtmf_buf), timeout, valid_terminators);
723 return dtmf_buf;
724}
725
85fc8c37 726SWITCH_DECLARE(char *) CoreSession::playAndGetDigits(int min_digits,
8b8a7f14
BW
727 int max_digits,
728 int max_tries,
729 int timeout,
730 char *terminators,
731 char *audio_files,
732 char *bad_input_audio_files,
733 char *digits_regex)
83f84876
AM
734{
735 switch_status_t status;
d5e4046d 736 sanity_check((char *)"");
878bbceb 737 this_check((char *)"");
fedefcb6 738 begin_allow_threads();
85fc8c37 739 memset(dtmf_buf, 0, sizeof(dtmf_buf));
fedefcb6
MJ
740 status = switch_play_and_get_digits( session,
741 (uint32_t) min_digits,
742 (uint32_t) max_digits,
743 (uint32_t) max_tries,
744 (uint32_t) timeout,
745 terminators,
746 audio_files,
747 bad_input_audio_files,
c806a20d 748 dtmf_buf,
85fc8c37 749 sizeof(dtmf_buf),
fedefcb6 750 digits_regex);
6f78befa
TL
751
752 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "playAndGetDigits dtmf_buf: %s\n", dtmf_buf);
753
fedefcb6 754 end_allow_threads();
85fc8c37 755 return dtmf_buf;
83f84876
AM
756}
757
40efe06a
AM
758SWITCH_DECLARE(void) CoreSession::say(const char *tosay, const char *module_name, const char *say_type, const char *say_method)
759{
878bbceb 760 this_check_void();
40efe06a
AM
761 sanity_check_noreturn;
762 if (!(tosay && module_name && say_type && say_method)) {
763 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error! invalid args.\n");
764 return;
765 }
766 begin_allow_threads();
767 switch_ivr_say(session, tosay, module_name, say_type, say_method, ap);
768 end_allow_threads();
769}
770
771SWITCH_DECLARE(void) CoreSession::sayPhrase(const char *phrase_name, const char *phrase_data, const char *phrase_lang)
772{
878bbceb 773 this_check_void();
40efe06a
AM
774 sanity_check_noreturn;
775
776 if (!(phrase_name)) {
777 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error! invalid args.\n");
778 return;
779 }
780
781 begin_allow_threads();
782 switch_ivr_phrase_macro(session, phrase_name, phrase_data, phrase_lang, ap);
783 end_allow_threads();
784}
785
47985c56 786SWITCH_DECLARE(int) CoreSession::streamFile(char *file, int starting_sample_count) {
f45d0601
MJ
787
788 switch_status_t status;
59526679 789 //switch_file_handle_t fh = { 0 };
622a2733 790 const char *prebuf;
f45d0601 791
878bbceb 792 this_check(-1);
f45d0601 793 sanity_check(-1);
59526679
AM
794
795 memset(&local_fh, 0, sizeof(local_fh));
796 fhp = &local_fh;
797 local_fh.samples = starting_sample_count;
f45d0601 798
f45d0601
MJ
799
800 if ((prebuf = switch_channel_get_variable(this->channel, "stream_prebuffer"))) {
801 int maybe = atoi(prebuf);
802 if (maybe > 0) {
59526679 803 local_fh.prebuf = maybe;
f45d0601
MJ
804 }
805 }
806
59526679
AM
807 begin_allow_threads();
808 status = switch_ivr_play_file(session, fhp, file, ap);
809 end_allow_threads();
810
a3ccefa7
AM
811 fhp = NULL;
812
f45d0601
MJ
813 return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
814
815}
816
8b8a7f14 817SWITCH_DECLARE(int) CoreSession::sleep(int ms) {
32bbdb74
AM
818
819 switch_status_t status;
820
821 this_check(-1);
822 sanity_check(-1);
823
824 begin_allow_threads();
825 status = switch_ivr_sleep(session, ms, ap);
826 end_allow_threads();
827
828 return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
829
830}
831
47985c56 832SWITCH_DECLARE(bool) CoreSession::ready() {
f45d0601 833
878bbceb 834 this_check(false);
b6d649fc 835 sanity_check(false);
482badff 836 return switch_channel_ready(channel) != 0;
fedefcb6
MJ
837}
838
830a8493
AM
839SWITCH_DECLARE(bool) CoreSession::mediaReady() {
840
841 this_check(false);
842 sanity_check(false);
843 return switch_channel_media_ready(channel) != 0;
844}
845
846SWITCH_DECLARE(bool) CoreSession::answered() {
847
848 this_check(false);
849 sanity_check(false);
850 return switch_channel_test_flag(channel, CF_ANSWERED) != 0;
851}
852
b6d649fc 853SWITCH_DECLARE(int) CoreSession::originate(CoreSession *a_leg_session, char *dest, int timeout)
e028f269
MJ
854{
855
856 switch_memory_pool_t *pool = NULL;
857 switch_core_session_t *aleg_core_session = NULL;
858 switch_call_cause_t cause;
859
878bbceb 860 this_check(0);
878bbceb 861
e028f269
MJ
862 cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
863
700aa0df
TL
864 if (a_leg_session != NULL) {
865 aleg_core_session = a_leg_session->session;
e028f269
MJ
866 }
867
700aa0df
TL
868 // this session has no valid switch_core_session_t at this point, and therefore
869 // no valid channel. since the threadstate is stored in the channel, and there
870 // is none, if we try to call begin_alllow_threads it will fail miserably.
871 // use the 'a leg session' to do the thread swapping stuff.
3d3ee88d 872 if (a_leg_session) a_leg_session->begin_allow_threads();
e028f269
MJ
873
874 if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
875 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n");
876 goto failed;
877 }
878
879 if (switch_ivr_originate(aleg_core_session,
880 &session,
881 &cause,
882 dest,
883 timeout,
884 NULL,
885 NULL,
886 NULL,
8433c7e0
AM
887 &caller_profile,
888 SOF_NONE) != SWITCH_STATUS_SUCCESS) {
e028f269
MJ
889 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Error Creating Outgoing Channel! [%s]\n", dest);
890 goto failed;
891
892 }
893
3d3ee88d 894 if (a_leg_session) a_leg_session->end_allow_threads();
d895c81d 895 channel = switch_core_session_get_channel(session);
94b22258 896 allocated = 1;
4b929592 897 switch_channel_set_state(switch_core_session_get_channel(session), CS_SOFT_EXECUTE);
ae76db7b 898
e028f269
MJ
899 return SWITCH_STATUS_SUCCESS;
900
901 failed:
3d3ee88d 902 if (a_leg_session) a_leg_session->end_allow_threads();
e028f269
MJ
903 return SWITCH_STATUS_FALSE;
904}
905
47985c56 906SWITCH_DECLARE(int) CoreSession::recordFile(char *file_name, int max_len, int silence_threshold, int silence_secs)
bd2c91b0 907{
bd2c91b0
MJ
908 switch_status_t status;
909
878bbceb
AM
910 this_check(-1);
911 sanity_check(-1);
912
a3ccefa7
AM
913 memset(&local_fh, 0, sizeof(local_fh));
914 fhp = &local_fh;
915 local_fh.thresh = silence_threshold;
916 local_fh.silence_hits = silence_secs;
917
bd2c91b0 918 begin_allow_threads();
a3ccefa7 919 status = switch_ivr_record_file(session, &local_fh, file_name, &args, max_len);
bd2c91b0 920 end_allow_threads();
a3ccefa7
AM
921
922 fhp = NULL;
923
bd2c91b0
MJ
924 return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
925
926}
e028f269 927
47985c56 928SWITCH_DECLARE(int) CoreSession::flushEvents()
6f78befa
TL
929{
930 switch_event_t *event;
931 switch_channel_t *channel;
932
878bbceb
AM
933 this_check(-1);
934 sanity_check(-1);
935
6f78befa
TL
936 if (!session) {
937 return SWITCH_STATUS_FALSE;
938 }
939 channel = switch_core_session_get_channel(session);
6f78befa
TL
940
941 while (switch_core_session_dequeue_event(session, &event) == SWITCH_STATUS_SUCCESS) {
942 switch_event_destroy(&event);
943 }
944 return SWITCH_STATUS_SUCCESS;
945}
946
47985c56 947SWITCH_DECLARE(int) CoreSession::flushDigits()
6f78befa 948{
878bbceb
AM
949 this_check(-1);
950 sanity_check(-1);
482badff 951 switch_channel_flush_dtmf(switch_core_session_get_channel(session));
6f78befa
TL
952 return SWITCH_STATUS_SUCCESS;
953}
954
47985c56 955SWITCH_DECLARE(int) CoreSession::setAutoHangup(bool val)
6f78befa 956{
878bbceb
AM
957 this_check(-1);
958 sanity_check(-1);
959
6f78befa
TL
960 if (!session) {
961 return SWITCH_STATUS_FALSE;
962 }
963 if (val) {
964 switch_set_flag(this, S_HUP);
965 } else {
966 switch_clear_flag(this, S_HUP);
967 }
968 return SWITCH_STATUS_SUCCESS;
969}
970
7f4c8a6d
AM
971SWITCH_DECLARE(void) CoreSession::waitForAnswer(CoreSession *calling_session)
972{
973 this_check_void();
974 sanity_check_noreturn;
975
976 switch_ivr_wait_for_answer(calling_session ? calling_session->session : NULL, session);
977
978}
979
47985c56 980SWITCH_DECLARE(void) CoreSession::setCallerData(char *var, char *val) {
e028f269 981
878bbceb
AM
982 this_check_void();
983 sanity_check_noreturn;
984
e028f269
MJ
985 if (strcmp(var, "dialplan") == 0) {
986 caller_profile.dialplan = val;
987 }
988 if (strcmp(var, "context") == 0) {
989 caller_profile.context = val;
990 }
991 if (strcmp(var, "caller_id_name") == 0) {
992 caller_profile.caller_id_name = val;
993 }
994 if (strcmp(var, "caller_id_number") == 0) {
995 caller_profile.caller_id_number = val;
996 }
997 if (strcmp(var, "network_addr") == 0) {
998 caller_profile.network_addr = val;
999 }
1000 if (strcmp(var, "ani") == 0) {
1001 caller_profile.ani = val;
1002 }
1003 if (strcmp(var, "aniii") == 0) {
1004 caller_profile.aniii = val;
1005 }
1006 if (strcmp(var, "rdnis") == 0) {
1007 caller_profile.rdnis = val;
1008 }
1009 if (strcmp(var, "username") == 0) {
1010 caller_profile.username = val;
1011 }
1012
1013}
1014
47985c56 1015SWITCH_DECLARE(void) CoreSession::setHangupHook(void *hangup_func) {
6f78befa 1016
878bbceb 1017 this_check_void();
a06997ee 1018 sanity_check_noreturn;
878bbceb 1019
6f78befa
TL
1020 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CoreSession::seHangupHook, hangup_func: %p\n", hangup_func);
1021 on_hangup = hangup_func;
1022 switch_channel_t *channel = switch_core_session_get_channel(session);
6f78befa
TL
1023
1024 hook_state = switch_channel_get_state(channel);
1025 switch_channel_set_private(channel, "CoreSession", this);
1026 switch_core_event_hook_add_state_change(session, hanguphook);
fedefcb6
MJ
1027}
1028
e028f269
MJ
1029/* ---- methods not bound to CoreSession instance ---- */
1030
8f5a873d
AM
1031SWITCH_DECLARE(void) consoleLog(char *level_str, char *msg)
1032{
1033 return console_log(level_str, msg);
1034}
1035
1036SWITCH_DECLARE(void) consoleCleanLog(char *msg)
1037{
1038 return console_clean_log(msg);
1039}
e028f269 1040
47985c56 1041SWITCH_DECLARE(void) console_log(char *level_str, char *msg)
e028f269
MJ
1042{
1043 switch_log_level_t level = SWITCH_LOG_DEBUG;
1044 if (level_str) {
1045 level = switch_log_str2level(level_str);
cc71ce69
MJ
1046 if (level == SWITCH_LOG_INVALID) {
1047 level = SWITCH_LOG_DEBUG;
1048 }
e028f269 1049 }
ae76db7b 1050 switch_log_printf(SWITCH_CHANNEL_LOG, level, "%s", switch_str_nil(msg));
e028f269
MJ
1051}
1052
47985c56 1053SWITCH_DECLARE(void) console_clean_log(char *msg)
e028f269 1054{
ae76db7b 1055 switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN,SWITCH_LOG_DEBUG, "%s", switch_str_nil(msg));
e028f269
MJ
1056}
1057
1058
47985c56 1059SWITCH_DECLARE(void) bridge(CoreSession &session_a, CoreSession &session_b)
e028f269
MJ
1060{
1061 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "bridge called, session_a uuid: %s\n", session_a.get_uuid());
1062 switch_input_callback_function_t dtmf_func = NULL;
1063 switch_input_args_t args;
1064
1065 session_a.begin_allow_threads();
1066 args = session_a.get_cb_args(); // get the cb_args data structure for session a
1067 dtmf_func = args.input_callback; // get the call back function
1068 switch_ivr_multi_threaded_bridge(session_a.session, session_b.session, dtmf_func, args.buf, args.buf);
1069 session_a.end_allow_threads();
1070
1071}
1072
47985c56 1073SWITCH_DECLARE_NONSTD(switch_status_t) hanguphook(switch_core_session_t *session_hungup)
6f78befa 1074{
482badff 1075 switch_channel_t *channel = switch_core_session_get_channel(session_hungup);
6f78befa 1076 CoreSession *coresession = NULL;
482badff 1077 switch_channel_state_t state = switch_channel_get_state(channel);
6f78befa
TL
1078
1079 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "hangup_hook called\n");
59526679 1080
6f78befa 1081
6f78befa
TL
1082 if ((coresession = (CoreSession *) switch_channel_get_private(channel, "CoreSession"))) {
1083 if (coresession->hook_state != state) {
1084 coresession->hook_state = state;
1085 coresession->check_hangup_hook();
1086 }
1087 }
1088
1089 return SWITCH_STATUS_SUCCESS;
1090}
1091
1092
47985c56 1093SWITCH_DECLARE_NONSTD(switch_status_t) dtmf_callback(switch_core_session_t *session_cb,
8b8a7f14
BW
1094 void *input,
1095 switch_input_type_t itype,
1096 void *buf,
1097 unsigned int buflen) {
6f78befa 1098
482badff 1099 switch_channel_t *channel = switch_core_session_get_channel(session_cb);
6f78befa
TL
1100 CoreSession *coresession = NULL;
1101 switch_status_t result;
1102
c806a20d 1103 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "dtmf_callback called\n");
6f78befa 1104
59526679
AM
1105
1106 //coresession = (CoreSession *) buf;
6f78befa 1107 coresession = (CoreSession *) switch_channel_get_private(channel, "CoreSession");
59526679 1108
6f78befa
TL
1109 if (!coresession) {
1110 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid CoreSession\n");
1111 return SWITCH_STATUS_FALSE;
1112 }
1113
1114 result = coresession->run_dtmf_callback(input, itype);
1115 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "process_callback_result returned\n");
1116 if (result) {
1117 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "process_callback_result returned: %d\n", result);
1118 }
1119 return result;
1120
1121}
1122
59526679 1123
fe854bdb 1124SWITCH_DECLARE(switch_status_t) CoreSession::process_callback_result(char *result)
e028f269
MJ
1125{
1126
878bbceb
AM
1127 this_check(SWITCH_STATUS_FALSE);
1128 sanity_check(SWITCH_STATUS_FALSE);
1129
fe854bdb 1130 if (switch_strlen_zero(result)) {
be276e0c
AM
1131 return SWITCH_STATUS_SUCCESS;
1132 }
1133
59526679 1134 if (fhp) {
8b8a7f14
BW
1135 if (!strncasecmp(result, "speed", 4)) {
1136 char *p;
1137
1138 if ((p = strchr(result, ':'))) {
1139 p++;
1140 if (*p == '+' || *p == '-') {
1141 int step;
1142 if (!(step = atoi(p))) {
1143 step = 1;
1144 }
b47382df 1145 fhp->speed += step;
8b8a7f14
BW
1146 } else {
1147 int speed = atoi(p);
b47382df 1148 fhp->speed = speed;
8b8a7f14
BW
1149 }
1150 return SWITCH_STATUS_SUCCESS;
1151 }
e028f269 1152
8b8a7f14 1153 return SWITCH_STATUS_FALSE;
e028f269 1154
8b8a7f14 1155 } else if (!strcasecmp(result, "pause")) {
b47382df
BW
1156 if (switch_test_flag(fhp, SWITCH_FILE_PAUSE)) {
1157 switch_clear_flag(fhp, SWITCH_FILE_PAUSE);
e028f269 1158 } else {
b47382df 1159 switch_set_flag(fhp, SWITCH_FILE_PAUSE);
e028f269
MJ
1160 }
1161 return SWITCH_STATUS_SUCCESS;
8b8a7f14
BW
1162 } else if (!strcasecmp(result, "stop")) {
1163 return SWITCH_STATUS_FALSE;
1164 } else if (!strcasecmp(result, "restart")) {
1165 unsigned int pos = 0;
b47382df
BW
1166 fhp->speed = 0;
1167 switch_core_file_seek(fhp, &pos, 0, SEEK_SET);
8b8a7f14
BW
1168 return SWITCH_STATUS_SUCCESS;
1169 } else if (!strncasecmp(result, "seek", 4)) {
1170 switch_codec_t *codec;
1171 unsigned int samps = 0;
1172 unsigned int pos = 0;
1173 char *p;
1174 codec = switch_core_session_get_read_codec(session);
1175 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "got codec\n");
1176 if ((p = strchr(result, ':'))) {
1177 p++;
1178 if (*p == '+' || *p == '-') {
1179 int step;
1180 if (!(step = atoi(p))) {
1181 step = 1000;
1182 }
1183 if (step > 0) {
1184 samps = step * (codec->implementation->samples_per_second / 1000);
1185 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "going to seek\n");
b47382df 1186 switch_core_file_seek(fhp, &pos, samps, SEEK_CUR);
8b8a7f14
BW
1187 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "done seek\n");
1188 } else {
1189 samps = step * (codec->implementation->samples_per_second / 1000);
1190 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "going to seek\n");
b47382df 1191 switch_core_file_seek(fhp, &pos, fhp->pos - samps, SEEK_SET);
8b8a7f14
BW
1192 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "done seek\n");
1193 }
e028f269 1194 } else {
8b8a7f14 1195 samps = atoi(p) * (codec->implementation->samples_per_second / 1000);
6f78befa 1196 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "going to seek\n");
b47382df 1197 switch_core_file_seek(fhp, &pos, samps, SEEK_SET);
6f78befa 1198 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "done seek\n");
e028f269 1199 }
e028f269 1200 }
e028f269 1201
8b8a7f14
BW
1202 return SWITCH_STATUS_SUCCESS;
1203 }
1204 }
b47382df 1205
fe854bdb 1206 if (!strcmp(result, "true") || !strcmp(result, "undefined")) {
6f78befa 1207 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "return success\n");
e028f269
MJ
1208 return SWITCH_STATUS_SUCCESS;
1209 }
1210
6f78befa 1211 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "no match, return false\n");
e028f269 1212
c815c059 1213 return SWITCH_STATUS_FALSE;
e028f269
MJ
1214}
1215
83f84876
AM
1216/* For Emacs:
1217 * Local Variables:
1218 * mode:c
1219 * indent-tabs-mode:t
1220 * tab-width:4
1221 * c-basic-offset:4
1222 * End:
1223 * For VIM:
64997c4d 1224 * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
83f84876 1225 */