00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <astxx/agi.h>
00022 #include <iostream>
00023 #include <sstream>
00024 #include <csignal>
00025 #include <cerrno>
00026 #include <cstring>
00027
00028 using namespace std;
00029 using namespace astxx;
00030
00031
00032
00033
00034
00035 volatile bool agi::got_sighup = false;
00036 volatile bool agi::got_sigpipe = false;
00037
00047 agi& agi::instance() {
00048 static agi instance;
00049 return instance;
00050 }
00051
00061 agi::agi() {
00062
00063 sigset_t new_set;
00064 sigset_t original_set;
00065
00066 if (sigfillset(&new_set) && sigprocmask(SIG_BLOCK, &new_set, &original_set))
00067 throw agi::error("Error blocking signals during initilization: " + string(strerror(errno)));
00068
00069
00070 if (SIG_ERR == signal(SIGHUP, agi::handle_sighup) || SIG_ERR == signal(SIGPIPE, agi::handle_sigpipe)) {
00071 sigprocmask(SIG_SETMASK, &original_set, NULL);
00072 throw agi::error("Error blocking signals during initilization: " + string(strerror(errno)));
00073 }
00074
00075
00076 read_env();
00077
00078
00079 if (sigprocmask(SIG_SETMASK, &original_set, NULL))
00080 throw agi::error("Error restoring original signal mask during initilization: " + string(strerror(errno)));
00081 }
00082
00084 void agi::read_env() {
00085
00086 while (cin.peek() != '\n') {
00087 string key;
00088 string value;
00089
00090 getline(cin, key, ':');
00091
00092 if (cin.peek() == ' ')
00093 cin.ignore(1);
00094
00095 getline(cin, value);
00096
00097 env.insert(make_pair(key, value));
00098 }
00099 }
00100
00113 string agi::operator [] (const std::string& key) {
00114 return env[key];
00115 }
00116
00121 map<string, string>::const_iterator agi::begin() const {
00122 return env.begin();
00123 }
00124
00129 map<string, string>::const_iterator agi::end() const {
00130 return env.end();
00131 }
00132
00140 void agi::send_command(const std::string& command) const {
00141 cout << command << endl;
00142 }
00143
00154 agi::result agi::execute(const std::string& command) const {
00155
00156
00157
00158
00159 test_hangup();
00160
00161 send_command(command);
00162 agi::result result = get_result();
00163
00164 if (result.data == "hangup")
00165 throw agi::hangup_result();
00166
00167 if (result.result == -1)
00168 throw agi::application_error("An error occured executing an agi command or the channel was hungup");
00169
00170 if (got_sigpipe)
00171 throw agi::io_error("Received SIGPIPE");
00172
00173 return result;
00174 }
00175
00176
00181 agi::result agi::get_result() const {
00182 agi::result result;
00183
00184 if (!(cin >> result.code)) {
00185 cin.clear();
00186 throw agi::io_error("There was a error reading from the Asterisk server");
00187 }
00188
00189 if (cin.peek() == ' ')
00190 cin.ignore(1);
00191
00192 getline(cin, result.message);
00193
00194 istringstream message(result.message);
00195
00196
00197
00198 switch (result.code) {
00199 case 200:
00200 message.ignore(32, '=');
00201
00202
00203 if (message.peek() != ' ') {
00204
00205 message >> result.result_string;
00206 istringstream ss(result.result_string);
00207 if (!(ss >> result.result))
00208 result.result = 0;
00209 }
00210 else {
00211 result.result_string = "";
00212 result.result = 0;
00213 message.ignore();
00214 }
00215
00216
00217 {
00218 string end_str;
00219 if (result.message.find("(") != string::npos) {
00220 message.ignore(32, '(');
00221 getline(message, result.data);
00222
00223 const string::size_type token = result.data.find_last_of(')');
00224 end_str = result.data.substr(token);
00225 result.data.erase(token);
00226
00227 message.str(end_str);
00228 }
00229 else {
00230 getline(message, end_str);
00231 message.str(end_str);
00232 }
00233
00234
00235 if (end_str.find("endpos=") != string::npos) {
00236 message.ignore(32, '=');
00237 message >> result.endpos;
00238 }
00239 }
00240
00241 break;
00242 case 510:
00243 throw agi::invalid_command(result.message + ". This could be a bug in Astxx, or your Asterisk installation may be too old.");
00244
00245 case 520:
00246 {
00247 string buffer;
00248 while (getline(cin, buffer)) {
00249 istringstream message(buffer);
00250 int end;
00251
00252 if (message >> end) {
00253 if (end == 520)
00254 break;
00255 }
00256 else {
00257 message.clear();
00258 result.message += buffer;
00259 }
00260 }
00261
00262 throw agi::usage_error(result.message);
00263 }
00264
00265 default:
00266 throw agi::unknown_error(result.code, result.message);
00267 }
00268
00269 return result;
00270 }
00271
00273 void agi::handle_sighup(int) {
00274 got_sighup = true;
00275 }
00276
00278 void agi::handle_sigpipe(int) {
00279 got_sigpipe = true;
00280 }
00281
00289 void agi::test_hangup() const {
00290 if (got_sighup)
00291 throw agi::hangup_signal();
00292 }
00293
00296 void agi::clear() {
00297 got_sighup = false;
00298 got_sigpipe = false;
00299 }
00300
00312 agi& agi::answer() {
00313 agi::result result = execute("ANSWER");
00314 return *this;
00315 }
00316
00338 int agi::channel_status(const std::string& channel) const {
00339 return execute("CHANNEL STATUS " + quote(channel)).result;
00340 }
00341
00354 char agi::control_stream_file(const std::string& filename, const std::string& escape_digits, int skip_time, char fastforward, char rewind, char pause) const {
00355 ostringstream ss;
00356 ss << "STREAM FILE " << quote(filename) << " " << quote(escape_digits);
00357
00358
00359
00360
00361
00362
00363 if (skip_time != control_stream_file_skip_time || fastforward || rewind || pause)
00364 ss << " " << skip_time;
00365 if (fastforward || rewind || pause)
00366 ss << " " << quote(fastforward);
00367 if (rewind || pause)
00368 ss << " " << quote(rewind);
00369 if (pause)
00370 ss << " " << quote(pause);
00371
00372 return execute(ss.str()).result;
00373 }
00374
00385 agi& agi::database_del(const std::string& family, const std::string& key) {
00386 agi::result result = execute("DATABASE DEL " + quote(family) + " " + quote(key));
00387
00388
00389 if (result.result == 0)
00390 throw agi::database_error("Error deleting database value");
00391 return *this;
00392 }
00393
00403 agi& agi::database_deltree(const std::string& family, const std::string& keytree) {
00404 agi::result result = execute("DATABASE DELTREE " + quote(family) + " " + quote(keytree));
00405
00406
00407 if (result.result == 0)
00408 throw agi::database_error("Error deleting database family/keytree");
00409 return *this;
00410 }
00411
00420 string agi::database_get(const std::string& family, const std::string& key) const {
00421 return execute("DATABASE GET " + quote(family) + " " + quote(key)).data;
00422 }
00423
00435 agi& agi::database_put(const std::string& family, const std::string& key, const std::string& value) {
00436 if (execute("DATABASE PUT " + quote(family) + " " + quote(key) + quote(value)).result == 0)
00437 throw agi::database_error("Error putting value in Asterisk database");
00438 return *this;
00439 }
00440
00453 int agi::exec(const std::string& app, const std::string& options) const {
00454 return execute("EXEC " + quote(app) + " " + quote(options)).result;
00455 }
00456
00465 string agi::get_data(const std::string& file, int timeout, int max_digits) const {
00466 ostringstream ss;
00467 ss << "GET DATA " << file;
00468
00469 if (timeout != 0 || max_digits != get_data_max_digits)
00470 ss << " " << timeout;
00471
00472 if (max_digits != get_data_max_digits)
00473 ss << " " << max_digits;
00474
00475 return execute(ss.str()).result_string;
00476 }
00477
00495 string agi::get_full_variable(const std::string& variable, const std::string& channel) const {
00496 agi::result result;
00497 try {
00498 ostringstream ss;
00499 ss << "GET FULL VARIABLE " << quote(variable);
00500
00501 if (!channel.empty())
00502 ss << " " << quote(channel);
00503
00504 result = execute(ss.str());
00505 }
00506 catch (agi::hangup_result& e) {
00507 result.data = "hangup";
00508 }
00509
00510 if (result.result == 0);
00511
00512 return result.data;
00513 }
00514
00523 char agi::get_option(const std::string& file, const std::string& escape_digits, int timeout) const {
00524 ostringstream ss;
00525 ss << "GET OPTION " << quote(file) << " " << quote(escape_digits);
00526
00527 if (timeout != 0)
00528 ss << " " << timeout;
00529
00530 agi::result result = execute(ss.str());
00531
00532 return result.result;
00533 }
00534
00543 string agi::get_variable(const std::string& variable) const {
00544 agi::result result;
00545 try {
00546 result = execute("GET VARIABLE " + quote(variable));
00547 }
00548 catch (agi::hangup_result& e) {
00549 result.data = "hangup";
00550 }
00551
00552 if (result.result == 0);
00553
00554 return result.data;
00555 }
00556
00564 agi& agi::hangup(const std::string& channel) {
00565 execute("HANGUP " + quote(channel));
00566 return *this;
00567 }
00568
00572 agi& agi::noop() {
00573 execute("NOOP");
00574 return *this;
00575 }
00576
00583 char agi::receive_char(int timeout) const {
00584 std::stringstream ss;
00585 ss << "RECEIVE CHAR " << timeout;
00586 return execute(ss.str()).result;
00587 }
00588
00596 std::string agi::receive_text(int timeout) const {
00597 std::stringstream ss;
00598 ss << "RECEIVE TEXT " << timeout;
00599 return execute(ss.str()).data;
00600 }
00601
00619 char agi::record_file(const std::string& filename, const std::string& format, const std::string& escape_digits, int timeout, int silence, bool beep, long offset) const {
00620 ostringstream ss;
00621 ss << "RECORD FILE " << quote(filename) << " " << quote(format) << " " << quote(escape_digits) << " " << timeout;
00622
00623 if (offset)
00624 ss << " " << offset;
00625
00626 if (beep)
00627 ss << " BEEP";
00628
00629 if (silence)
00630 ss << " s=" << silence;
00631
00632 return execute(ss.str()).result;
00633 }
00634
00642 char agi::say_alpha(const std::string& alphanum, const std::string& escape_digits) const {
00643 return execute("SAY ALPHA " + quote(alphanum) + " " + quote(escape_digits)).result;
00644 }
00645
00653 char agi::say_alpha(int number, const std::string& escape_digits) const {
00654 ostringstream ss;
00655 ss << "SAY ALPHA " << number << " " << quote(escape_digits);
00656 return execute(ss.str()).result;
00657 }
00658
00666 char agi::say_date(time_t date, const std::string& escape_digits) const {
00667 ostringstream ss;
00668 ss << "SAY DATE " << date << " " << quote(escape_digits);
00669 return execute(ss.str()).result;
00670 }
00671
00686 char agi::say_datetime(time_t date, const std::string& escape_digits, const std::string& format, const std::string& timezone) const {
00687 ostringstream ss;
00688 ss << "SAY DATETIME " << date << " " << quote(escape_digits);
00689
00690 if (not format.empty() or not timezone.empty())
00691 ss << " " << quote(format);
00692
00693 if (not timezone.empty())
00694 ss << " " << quote(timezone);
00695
00696 return execute(ss.str()).result;
00697 }
00698
00706 char agi::say_digits(int digits, const std::string& escape_digits) const {
00707 ostringstream ss;
00708 ss << "SAY DIGITS " << digits << " " << quote(escape_digits);
00709 return execute(ss.str()).result;
00710 }
00711
00719 char agi::say_number(int number, const std::string& escape_digits) const {
00720 ostringstream ss;
00721 ss << "SAY NUMBER " << number << " " << quote(escape_digits);
00722 return execute(ss.str()).result;
00723 }
00724
00732 char agi::say_phonetic(const std::string& characters, const std::string& escape_digits) const {
00733 return execute("SAY PHONETIC " + quote(characters) + " " + quote(escape_digits)).result;
00734 }
00735
00743 char agi::say_time(time_t time, const std::string& escape_digits) const {
00744 ostringstream ss;
00745 ss << "SAY TIME " << time << " " << quote(escape_digits);
00746 return execute(ss.str()).result;
00747 }
00748
00757 agi& agi::send_image(const std::string& image) {
00758 execute("SEND IMAGE " + quote(image));
00759 return *this;
00760 }
00761
00770 agi& agi::send_text(const std::string& text) {
00771 execute("SEND TEXT " + quote(text));
00772 return *this;
00773 }
00774
00782 agi& agi::set_autohangup(int delay) {
00783 ostringstream ss;
00784 ss << "SET AUTOHANGUP " << delay;
00785 execute(ss.str());
00786 return *this;
00787 }
00788
00795 agi& agi::set_callerid(int number) {
00796 ostringstream ss;
00797 ss << "SET CALLERID " << number;
00798 execute(ss.str());
00799 return *this;
00800 }
00801
00809 agi& agi::set_callerid(const std::string& cid) {
00810 execute("SET CALLERID " + quote(cid));
00811 return *this;
00812 }
00813
00822 agi& agi::set_context(const std::string& context) {
00823 execute("SET CONTEXT " + quote(context));
00824 return *this;
00825 }
00826
00835 agi& agi::set_extension(int extension) {
00836 ostringstream ss;
00837 ss << "SET EXTENSION " << extension;
00838 execute(ss.str());
00839 return *this;
00840 }
00841
00850 agi& agi::set_extension(const std::string& extension) {
00851 execute("SET EXTENSION " + quote(extension));
00852 return *this;
00853 }
00854
00862 agi& agi::set_music(bool enable, const std::string& music_class) {
00863 ostringstream ss;
00864 ss << "SET MUSIC ";
00865
00866 if (enable)
00867 ss << "ON";
00868 else
00869 ss << "OFF";
00870
00871 if (not music_class.empty())
00872 ss << " " << quote(music_class);
00873
00874 execute(ss.str());
00875 return *this;
00876 }
00877
00886 agi& agi::set_priority(int priority) {
00887 ostringstream ss;
00888 ss << "SET PRIORITY " << priority;
00889 execute(ss.str());
00890 return *this;
00891 }
00892
00901 agi& agi::set_priority(const std::string& priority) {
00902 execute("SET PRIORITY " + quote(priority));
00903 return *this;
00904 }
00905
00913 agi& agi::set_variable(const std::string& variable, const std::string& value) {
00914 execute("SET VARIABLE " + quote(variable) + " " + quote(value));
00915 return *this;
00916 }
00917
00926 char agi::stream_file(const std::string& filename, const std::string& escape_digits, long offset) const {
00927 ostringstream ss;
00928 ss << "STREAM FILE " << quote(filename) << " " << quote(escape_digits);
00929
00930 if (offset)
00931 ss << " " << offset;
00932
00933 return execute(ss.str()).result;
00934 }
00935
00942 agi& agi::tdd_mode(bool enable) {
00943 if (enable)
00944 execute("TDD MODE ON");
00945 else
00946 execute("TDD MODE OFF");
00947 return *this;
00948 }
00949
00958 agi& agi::tdd_mode(const std::string& mode) {
00959 execute("TDD MODE " + quote(mode));
00960 return *this;
00961 }
00962
00973 agi& agi::verbose(const std::string& text, int level) {
00974 string::size_type end_pos = 0;
00975 string::size_type start_pos = 0;
00976 while (end_pos != string::npos) {
00977 end_pos = text.find('\n', start_pos);
00978
00979 ostringstream ss;
00980 ss << "VERBOSE "
00981 << quote(text.substr(start_pos, end_pos == string::npos ? string::npos : end_pos - start_pos))
00982 << " " << level;
00983 execute(ss.str());
00984
00985 start_pos = end_pos + 1;
00986 }
00987
00988 return *this;
00989 }
00990
00998 char agi::wait_for_digit(long timeout) const {
00999 ostringstream ss;
01000 ss << "WAIT FOR DIGIT " << timeout;
01001 return execute(ss.str()).result;
01002 }
01003
01004
01005