From 14489dd1258ea2b83cb4a19f48cbb51dec81e842 Mon Sep 17 00:00:00 2001 From: Stefan Sayer Date: Fri, 12 Jan 2007 21:08:30 +0000 Subject: [PATCH] some extensions to ivr * new methods onSipRequest/onSipReply, the whole AmSipReply/AmSipRequest structure is passed to python SipDialog * state is changed only on reply to INVITE, not other requests * made pin_collect work git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@189 8eb893ce-cfd4-0310-b710-fb5ebe64c474 --- apps/early_announce/EarlyAnnounce.cpp | 2 +- apps/ivr/Ivr.cpp | 28 +++++ apps/ivr/Ivr.h | 5 + apps/ivr/IvrDialogBase.cpp | 12 ++ apps/ivr/IvrSipDialog.cpp | 16 ++- apps/ivr/IvrSipReply.cpp | 174 ++++++++++++++++++++++++++ apps/ivr/IvrSipReply.h | 34 +++++ apps/ivr/IvrSipRequest.cpp | 92 ++++++++++---- apps/ivr/IvrSipRequest.h | 25 ++++ apps/pin_collect/pin_collect.py | 36 +++++- core/AmApi.cpp | 5 + core/AmApi.h | 10 ++ core/AmInterfaceHandler.cpp | 82 ++++++------ core/AmSession.cpp | 2 +- core/AmSessionContainer.cpp | 9 +- core/AmSipDialog.cpp | 11 +- core/AmSipDialog.h | 1 + 17 files changed, 467 insertions(+), 77 deletions(-) create mode 100644 apps/ivr/IvrSipReply.cpp create mode 100644 apps/ivr/IvrSipReply.h diff --git a/apps/early_announce/EarlyAnnounce.cpp b/apps/early_announce/EarlyAnnounce.cpp index ac49587e..2942cc03 100644 --- a/apps/early_announce/EarlyAnnounce.cpp +++ b/apps/early_announce/EarlyAnnounce.cpp @@ -101,7 +101,7 @@ AmSession* EarlyAnnounceFactory::onInvite(const AmSipRequest& req) { string announce_path = AnnouncePath; string announce_file = announce_path + req.domain - + "/" + req.user + ".wav"; + + "/" + get_header_param(req.r_uri, "play") + ".wav"; DBG("trying '%s'\n",announce_file.c_str()); if(file_exists(announce_file)) diff --git a/apps/ivr/Ivr.cpp b/apps/ivr/Ivr.cpp index 8b29aa35..15598671 100644 --- a/apps/ivr/Ivr.cpp +++ b/apps/ivr/Ivr.cpp @@ -21,6 +21,8 @@ #include "IvrDialogBase.h" #include "IvrSipDialog.h" +#include "IvrSipRequest.h" +#include "IvrSipReply.h" #include "IvrAudio.h" #include "IvrUAC.h" #include "Ivr.h" @@ -206,6 +208,11 @@ void IvrFactory::import_ivr_builtins() // IvrDialogBase import_object(ivr_module,"IvrDialogBase",&IvrDialogBaseType); + // IvrSipRequest + import_object(ivr_module,"IvrSipRequest",&IvrSipRequestType); + + // IvrSipReply + import_object(ivr_module,"IvrSipReply",&IvrSipReplyType); // IvrAudioFile import_object(ivr_module,"IvrAudioFile",&IvrAudioFileType); @@ -469,6 +476,15 @@ int IvrDialog::transfer(const string& target) return dlg.transfer(target); } +int IvrDialog::drop() +{ + int res = dlg.drop(); + if (res) + setStopped(); + + return res; +} + /** * Load a script using user name from URI. * Note: there is no default script. @@ -633,6 +649,18 @@ void IvrDialog::onOtherReply(const AmSipReply& r) AmB2BSession::onOtherReply(r); } +void IvrDialog::onSipReply(const AmSipReply& r) { + AmSipReply* rep_cpy = new AmSipReply(r); + callPyEventHandler("onSipReply","O",IvrSipReply_FromPtr(rep_cpy)); + AmB2BSession::onSipReply(r); +} + +void IvrDialog::onSipRequest(const AmSipRequest& r){ + AmSipRequest* req_cpy = new AmSipRequest(r); + callPyEventHandler("onSipRequest","O", IvrSipRequest_FromPtr(req_cpy)); + AmB2BSession::onSipRequest(r); +} + void IvrDialog::process(AmEvent* event) { DBG("IvrDialog::process\n"); diff --git a/apps/ivr/Ivr.h b/apps/ivr/Ivr.h index 9533163b..40ef1ea3 100644 --- a/apps/ivr/Ivr.h +++ b/apps/ivr/Ivr.h @@ -132,6 +132,7 @@ public: void setPyPtrs(PyObject *mod, PyObject *dlg); int transfer(const string& target); + int drop(); void onSessionStart(const AmSipRequest& req); void onBye(const AmSipRequest& req); @@ -139,6 +140,10 @@ public: void onOtherBye(const AmSipRequest& req); void onOtherReply(const AmSipReply& r); + + void onSipReply(const AmSipReply& r); + void onSipRequest(const AmSipRequest& r); + }; #endif diff --git a/apps/ivr/IvrDialogBase.cpp b/apps/ivr/IvrDialogBase.cpp index 1b64d0b7..1a4b02cc 100644 --- a/apps/ivr/IvrDialogBase.cpp +++ b/apps/ivr/IvrDialogBase.cpp @@ -145,6 +145,15 @@ static PyObject* IvrDialogBase_stopSession(IvrDialogBase* self, PyObject*) return Py_None; } +static PyObject* IvrDialogBase_dropSession(IvrDialogBase* self, PyObject*) +{ + assert(self->p_dlg); + self->p_dlg->drop(); + self->p_dlg->postEvent(0); + Py_INCREF(Py_None); + return Py_None; +} + static PyObject* IvrDialogBase_bye(IvrDialogBase* self, PyObject*) { assert(self->p_dlg); @@ -434,6 +443,9 @@ static PyMethodDef IvrDialogBase_methods[] = { {"redirect", (PyCFunction)IvrDialogBase_redirect, METH_VARARGS, "Refers the remote party to some third party." }, + {"dropSession", (PyCFunction)IvrDialogBase_dropSession, METH_NOARGS, + "Drop the session and forget it without replying" + }, // Media control {"enqueue", (PyCFunction)IvrDialogBase_enqueue, METH_VARARGS, "Add some audio to the queue (mostly IvrAudioFile)" diff --git a/apps/ivr/IvrSipDialog.cpp b/apps/ivr/IvrSipDialog.cpp index 7d581dad..6dbc4d96 100644 --- a/apps/ivr/IvrSipDialog.cpp +++ b/apps/ivr/IvrSipDialog.cpp @@ -67,6 +67,20 @@ def_IvrSipDialog_GETTER(IvrSipDialog_getlocal_party, local_party) def_IvrSipDialog_GETTER(IvrSipDialog_getroute, getRoute()) def_IvrSipDialog_GETTER(IvrSipDialog_getnext_hop, next_hop) +#define def_IvrSipDialog_SETTER(setter_name, attr) \ +static int \ +setter_name(IvrSipDialog *self, PyObject* value, void *closure) \ +{ \ + char* text; \ + if(!PyArg_Parse(value,"s",&text))\ + return -1;\ + \ + self->p_dlg->attr = text; \ + return 0; \ +} + +def_IvrSipDialog_SETTER(IvrSipDialog_setremote_uri, remote_uri) + // static PyObject* // IvrSipDialog_getuser(IvrSipDialog *self, void *closure) // { @@ -85,7 +99,7 @@ static PyGetSetDef IvrSipDialog_getset[] = { {"sip_ip", (getter)IvrSipDialog_getsip_ip, NULL, "destination IP of first received message", NULL}, {"sip_port", (getter)IvrSipDialog_getsip_port, NULL, "optional: SIP port", NULL}, {"local_uri", (getter)IvrSipDialog_getlocal_uri, NULL, "local uri", NULL}, - {"remote_uri", (getter)IvrSipDialog_getremote_uri, NULL, "remote uri", NULL}, + {"remote_uri", (getter)IvrSipDialog_getremote_uri, (setter)IvrSipDialog_setremote_uri, "remote uri", NULL}, {"contact_uri", (getter)IvrSipDialog_getcontact_uri, NULL, "pre-calculated contact uri", NULL}, {"callid", (getter)IvrSipDialog_getcallid, NULL, "call id", NULL}, {"remote_tag", (getter)IvrSipDialog_getremote_tag, NULL, "remote tag", NULL}, diff --git a/apps/ivr/IvrSipReply.cpp b/apps/ivr/IvrSipReply.cpp new file mode 100644 index 00000000..ca720ad3 --- /dev/null +++ b/apps/ivr/IvrSipReply.cpp @@ -0,0 +1,174 @@ +/* + * $Id: IvrSipReply.cpp,v 1.15.2.1 2005/09/02 13:47:46 sayer Exp $ + * + * Copyright (C) 2007 iptego GmbH + * + * This file is part of sems, a free SIP media server. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "IvrSipReply.h" + +#include "log.h" + +// Data definition +typedef struct { + + PyObject_HEAD + AmSipReply* p_req; +} IvrSipReply; + + +// Constructor +static PyObject* IvrSipReply_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"ivr_req", NULL}; + IvrSipReply *self; + + self = (IvrSipReply *)type->tp_alloc(type, 0); + if (self != NULL) { + + PyObject* o_req = NULL; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &o_req)){ + + Py_DECREF(self); + return NULL; + } + + if (!PyCObject_Check(o_req)){ + + Py_DECREF(self); + return NULL; + } + + self->p_req = (AmSipReply*)PyCObject_AsVoidPtr(o_req); + } + + DBG("IvrSipReply_new\n"); + return (PyObject *)self; +} + +// static void +// IvrSipRequest_dealloc(IvrSipRequest* self) +// { +// self->ob_type->tp_free((PyObject*)self); +// } + +#define def_IvrSipReply_GETTER(getter_name, attr) \ +static PyObject* \ +getter_name(IvrSipReply *self, void *closure) \ +{ \ + return PyString_FromString(self->p_req->attr.c_str()); \ +} \ + + +def_IvrSipReply_GETTER(IvrSipReply_getreason, reason) +def_IvrSipReply_GETTER(IvrSipReply_getnext_request_uri, next_request_uri) +def_IvrSipReply_GETTER(IvrSipReply_gethdrs, hdrs) +def_IvrSipReply_GETTER(IvrSipReply_getremote_tag, remote_tag) +def_IvrSipReply_GETTER(IvrSipReply_getlocal_tag, local_tag) +def_IvrSipReply_GETTER(IvrSipReply_getroute, route) +def_IvrSipReply_GETTER(IvrSipReply_getnext_hop, next_hop) +def_IvrSipReply_GETTER(IvrSipReply_getbody, body) + +// static PyObject* +// IvrSipReply_getuser(IvrSipReply *self, void *closure) +// { +// return PyString_FromString(self->p_req->user.c_str()); +// } + +static PyObject* +IvrSipReply_getcseq(IvrSipReply *self, void *closure) +{ + return PyInt_FromLong(self->p_req->cseq); +} + +static PyObject* +IvrSipReply_getcode(IvrSipReply *self, void *closure) +{ + return PyInt_FromLong(self->p_req->code); +} + +static PyGetSetDef IvrSipReply_getset[] = { + {"code", (getter)IvrSipReply_getcode, NULL, "code", NULL}, + {"reason", (getter)IvrSipReply_getreason, NULL, "reason", NULL}, + {"next_request_uri", (getter)IvrSipReply_getnext_request_uri, NULL, "next_request_uri", NULL}, + {"next_hop", (getter)IvrSipReply_getnext_hop, NULL, "next_hop", NULL}, + {"route", (getter)IvrSipReply_getroute, NULL, "route", NULL}, + {"hdrs", (getter)IvrSipReply_gethdrs, NULL, "hdrs", NULL}, + {"body", (getter)IvrSipReply_getbody, NULL, "body", NULL}, + {"remote_tag", (getter)IvrSipReply_getremote_tag, NULL, "remote_tag", NULL}, + {"local_tag", (getter)IvrSipReply_getlocal_tag, NULL, "local_tag", NULL}, + {"cseq", (getter)IvrSipReply_getcseq, NULL, "CSeq for next request", NULL}, + {NULL} /* Sentinel */ +}; + +PyTypeObject IvrSipReplyType = { + + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "ivr.IvrSipReply", /*tp_name*/ + sizeof(IvrSipReply), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "Wrapper class for AmSipReply", /*tp_doc*/ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + IvrSipReply_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + IvrSipReply_new, /* tp_new */ +}; + + +PyObject* IvrSipReply_FromPtr(AmSipReply* req) +{ + PyObject* c_req = PyCObject_FromVoidPtr(req,NULL); + PyObject* args = Py_BuildValue("(O)",c_req); + + PyObject* py_req = IvrSipReply_new(&IvrSipReplyType,args,NULL); + + Py_DECREF(args); + Py_DECREF(c_req); + + return py_req; +} diff --git a/apps/ivr/IvrSipReply.h b/apps/ivr/IvrSipReply.h new file mode 100644 index 00000000..bfe14baf --- /dev/null +++ b/apps/ivr/IvrSipReply.h @@ -0,0 +1,34 @@ +/* + * $Id: IvrSipReply.cpp,v 1.15.2.1 2005/09/02 13:47:46 sayer Exp $ + * Copyright (C) 2007 iptego GmbH + * + * This file is part of sems, a free SIP media server. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef IvrSipReply_h +#define IvrSipReply_h + +// Python stuff +#include +#include "structmember.h" + +#include "AmSipReply.h" + +extern PyTypeObject IvrSipReplyType; +PyObject* IvrSipReply_FromPtr(AmSipReply* req); + +#endif diff --git a/apps/ivr/IvrSipRequest.cpp b/apps/ivr/IvrSipRequest.cpp index 100decc4..93f4ceec 100644 --- a/apps/ivr/IvrSipRequest.cpp +++ b/apps/ivr/IvrSipRequest.cpp @@ -1,8 +1,29 @@ +/* + * $Id$ + * Copyright (C) 2002-2003 Fhg Fokus + * Copyright (C) 2007 iptego GmbH + * + * This file is part of sems, a free SIP media server. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + #include "IvrSipRequest.h" -//#include "AmSessionTimer.h" #include "AmSipRequest.h" +#include "log.h" -#if 0 // Data definition typedef struct { @@ -53,21 +74,27 @@ getter_name(IvrSipRequest *self, void *closure) \ return PyString_FromString(self->p_req->attr.c_str()); \ } \ +def_IvrSipRequest_GETTER(IvrSipRequest_getmethod, method) def_IvrSipRequest_GETTER(IvrSipRequest_getuser, user) def_IvrSipRequest_GETTER(IvrSipRequest_getdomain, domain) -def_IvrSipRequest_GETTER(IvrSipRequest_getsip_ip, sip_ip) -def_IvrSipRequest_GETTER(IvrSipRequest_getsip_port, sip_port) -def_IvrSipRequest_GETTER(IvrSipRequest_getlocal_uri, local_uri) -def_IvrSipRequest_GETTER(IvrSipRequest_getremote_uri, remote_uri) -def_IvrSipRequest_GETTER(IvrSipRequest_getcontact_uri, contact_uri) +def_IvrSipRequest_GETTER(IvrSipRequest_getdstip, dstip) +def_IvrSipRequest_GETTER(IvrSipRequest_getport, port) +def_IvrSipRequest_GETTER(IvrSipRequest_getr_uri, r_uri) +def_IvrSipRequest_GETTER(IvrSipRequest_getfrom_uri, from_uri) +def_IvrSipRequest_GETTER(IvrSipRequest_getfrom, from) +def_IvrSipRequest_GETTER(IvrSipRequest_getto, to) def_IvrSipRequest_GETTER(IvrSipRequest_getcallid, callid) -def_IvrSipRequest_GETTER(IvrSipRequest_getremote_tag, remote_tag) -def_IvrSipRequest_GETTER(IvrSipRequest_getlocal_tag, local_tag) -def_IvrSipRequest_GETTER(IvrSipRequest_getremote_party, remote_party) -def_IvrSipRequest_GETTER(IvrSipRequest_getlocal_party, local_party) +def_IvrSipRequest_GETTER(IvrSipRequest_getfrom_tag, from_tag) +def_IvrSipRequest_GETTER(IvrSipRequest_getto_tag, to_tag) + def_IvrSipRequest_GETTER(IvrSipRequest_getroute, route) def_IvrSipRequest_GETTER(IvrSipRequest_getnext_hop, next_hop) +def_IvrSipRequest_GETTER(IvrSipRequest_getkey, key) + +def_IvrSipRequest_GETTER(IvrSipRequest_getbody, body) + + // static PyObject* // IvrSipRequest_getuser(IvrSipRequest *self, void *closure) // { @@ -81,21 +108,26 @@ IvrSipRequest_getcseq(IvrSipRequest *self, void *closure) } static PyGetSetDef IvrSipRequest_getset[] = { - {"user", (getter)IvrSipRequest_getuser, NULL, "local user", NULL}, - {"domain", (getter)IvrSipRequest_getdomain, NULL, "local domain", NULL}, - {"sip_ip", (getter)IvrSipRequest_getsip_ip, NULL, "destination IP of first received message", NULL}, - {"sip_port", (getter)IvrSipRequest_getsip_port, NULL, "optional: SIP port", NULL}, - {"local_uri", (getter)IvrSipRequest_getlocal_uri, NULL, "local uri", NULL}, - {"remote_uri", (getter)IvrSipRequest_getremote_uri, NULL, "remote uri", NULL}, - {"contact_uri", (getter)IvrSipRequest_getcontact_uri, NULL, "pre-calculated contact uri", NULL}, - {"callid", (getter)IvrSipRequest_getcallid, NULL, "call id", NULL}, - {"remote_tag", (getter)IvrSipRequest_getremote_tag, NULL, "remote tag", NULL}, - {"local_tag", (getter)IvrSipRequest_getlocal_tag, NULL, "local tag", NULL}, - {"remote_party",(getter)IvrSipRequest_getremote_party, NULL, "To/From", NULL}, - {"local_party", (getter)IvrSipRequest_getlocal_party, NULL, "To/From", NULL}, + {"method", (getter)IvrSipRequest_getmethod, NULL, "method", NULL}, + {"user", (getter)IvrSipRequest_getuser, NULL, "local user", NULL}, + {"domain", (getter)IvrSipRequest_getdomain, NULL, "local domain", NULL}, + {"dstip", (getter)IvrSipRequest_getdstip, NULL, "dstip", NULL}, + {"port", (getter)IvrSipRequest_getport, NULL, "port", NULL}, + + {"r_uri", (getter)IvrSipRequest_getr_uri, NULL, "port", NULL}, + {"from_uri", (getter)IvrSipRequest_getfrom_uri, NULL, "port", NULL}, + {"from", (getter)IvrSipRequest_getfrom, NULL, "port", NULL}, + {"to", (getter)IvrSipRequest_getto, NULL, "port", NULL}, + + + {"callid", (getter)IvrSipRequest_getcallid, NULL, "call id", NULL}, + {"from_tag", (getter)IvrSipRequest_getfrom_tag, NULL, "remote tag", NULL}, + {"to_tag", (getter)IvrSipRequest_getto_tag, NULL, "local tag", NULL}, {"route", (getter)IvrSipRequest_getroute, NULL, "record routing", NULL}, {"next_hop", (getter)IvrSipRequest_getnext_hop, NULL, "next_hop for t_uac_dlg", NULL}, {"cseq", (getter)IvrSipRequest_getcseq, NULL, "CSeq for next request", NULL}, + {"key", (getter)IvrSipRequest_getkey, NULL, "CSeq for next request", NULL}, + {"body", (getter)IvrSipRequest_getbody, NULL, "CSeq for next request", NULL}, {NULL} /* Sentinel */ }; @@ -142,4 +174,16 @@ PyTypeObject IvrSipRequestType = { IvrSipRequest_new, /* tp_new */ }; -#endif + +PyObject* IvrSipRequest_FromPtr(AmSipRequest* req) +{ + PyObject* c_req = PyCObject_FromVoidPtr(req,NULL); + PyObject* args = Py_BuildValue("(O)",c_req); + + PyObject* py_req = IvrSipRequest_new(&IvrSipRequestType,args,NULL); + + Py_DECREF(args); + Py_DECREF(c_req); + + return py_req; +} diff --git a/apps/ivr/IvrSipRequest.h b/apps/ivr/IvrSipRequest.h index 7ea2138c..e8395f17 100644 --- a/apps/ivr/IvrSipRequest.h +++ b/apps/ivr/IvrSipRequest.h @@ -1,3 +1,25 @@ +/* + * $Id$ + * Copyright (C) 2002-2003 Fhg Fokus + * Copyright (C) 2007 iptego GmbH + * + * This file is part of sems, a free SIP media server. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + #ifndef IvrSipRequest_h #define IvrSipRequest_h @@ -5,6 +27,9 @@ #include #include "structmember.h" +#include "AmSipRequest.h" + extern PyTypeObject IvrSipRequestType; +PyObject* IvrSipRequest_FromPtr(AmSipRequest* req); #endif diff --git a/apps/pin_collect/pin_collect.py b/apps/pin_collect/pin_collect.py index 86fa132a..ab06a01d 100644 --- a/apps/pin_collect/pin_collect.py +++ b/apps/pin_collect/pin_collect.py @@ -1,9 +1,10 @@ from log import * from ivr import * -collect = 0 -connect = 1 -connected = 2 +collect = 0 +connect = 1 +connect_failed = 2 + HINT_TIMER = 1 HINT_TIMEOUT = 10 # seconds until hint msg is played @@ -22,6 +23,9 @@ class IvrDialog(IvrDialogBase): auth_fail_msg = None pin_msg = None + transfer_cseq = None + dlg_remote_uri = None + state = collect keys = '' @@ -73,15 +77,35 @@ class IvrDialog(IvrDialogBase): elif key == 10: self.state = connect self.removeTimer(HINT_TIMER) - self.redirect("sip:" + self.dialog.user + \ - self.keys + "@" + \ + self.dlg_remote_uri = self.dialog.remote_uri + debug("saved remote_uri "+ self.dlg_remote_uri) + self.transfer_cseq = self.dialog.cseq + self.redirect("sip:" + self.dialog.user + "@" + \ self.dialog.domain) - self.stopSession() def onEmptyQueue(self): if self.state == collect: self.setTimer(HINT_TIMER, HINT_TIMEOUT) + elif self.state == connect_failed: + debug("transfer failed. stopping session.") + debug("restoring remote_uri to " + self.dlg_remote_uri) + self.dialog.remote_uri = self.dlg_remote_uri + self.bye() + self.stopSession() def onTimer(self, id): if id == HINT_TIMER and self.state == collect: self.enqueue(self.pin_msg, None) + + def onSipReply(self, reply): + if reply.cseq == self.transfer_cseq: + # restore remote uri of dialog + if reply.code >= 200 and reply.code < 300: + debug("received positive reply to transfer request. dropping session.") + self.dropSession() + elif reply.code >= 300: + debug("transfer failed. notifying user") + self.state = connect_failed + self.fail_msg = IvrAudioFile() + self.fail_msg.open(config['fail_msg'],AUDIO_READ) + self.enqueue(self.fail_msg,None) diff --git a/core/AmApi.cpp b/core/AmApi.cpp index 1feb3f61..84eecf0b 100644 --- a/core/AmApi.cpp +++ b/core/AmApi.cpp @@ -48,6 +48,11 @@ AmSessionFactory::AmSessionFactory(const string& name) { } +AmSession* AmSessionFactory::onRefer(const AmSipRequest& req) +{ + throw AmSession::Exception(488,"Not accepted here"); +} + int AmSessionFactory::configureModule(AmConfigReader& cfg) { return mod_conf.readFromConfig(cfg); } diff --git a/core/AmApi.h b/core/AmApi.h index 3937b3b2..7a573c07 100644 --- a/core/AmApi.h +++ b/core/AmApi.h @@ -144,6 +144,16 @@ public: */ virtual AmSession* onInvite(const AmSipRequest& req)=0; + /** + * Creates a dialog state on new REFER with local-tag. + * @return 0 if the request is not acceptable. + * + * Warning: + * This method should not make any expensive + * processing as it would block the server. + */ + virtual AmSession* onRefer(const AmSipRequest& req); + /** * method to receive an Event that is posted * to the factory diff --git a/core/AmInterfaceHandler.cpp b/core/AmInterfaceHandler.cpp index 6b8880c6..d491dd1d 100644 --- a/core/AmInterfaceHandler.cpp +++ b/core/AmInterfaceHandler.cpp @@ -309,47 +309,47 @@ void AmRequestHandler::dispatch(AmSipRequest& req) sess_exists = sess_cont->postEvent(local_tag,ev); if(!sess_exists){ - - if(req.method == "INVITE"){ - - sess_cont->startSessionUAS(req); - - } else if(req.method == "REFER"){ - // Out-of-dialog REFER - AmSipRequest n_req; - n_req.method = "INVITE"; - n_req.dstip = AmConfig::LocalIP; - - n_req.from = req.to; - n_req.from_uri = req.r_uri; - n_req.from_tag = AmSession::getNewId(); - n_req.user = req.user; - n_req.r_uri = uri_from_name_addr(getHeader(req.hdrs, "Refer-To")); - n_req.to = getHeader(req.hdrs, "Refer-To"); - n_req.to_tag = ""; - n_req.cmd = req.cmd; // application from REFER - - n_req.callid = AmSession::getNewId() + "@" + AmConfig::LocalIP; - - if (AmSessionContainer::instance()->startSessionUAC(n_req) - != NULL) - AmSipDialog::reply_error(req,202,"Accepted"); - else - AmSipDialog::reply_error(req,500,"Not supported here"); - - } else { - - if(!local_tag.empty() || req.method == "CANCEL"){ - AmSipDialog::reply_error(req,481,"Call leg/Transaction does not exist"); - } - else { - //TODO: reply some 4xx. - ERROR("sorry, we don't support beginning a new session with a '%s' message\n", - req.method.c_str()); - AmSipDialog::reply_error(req,500,"Not supported here"); - return; - } - } + if((req.method == "INVITE")|| + ((req.method == "REFER") && !local_tag.empty())){ + sess_cont->startSessionUAS(req); + + } else if(req.method == "REFER"){ + // Out-of-dialog REFER + AmSipRequest n_req; + n_req.method = "INVITE"; + n_req.dstip = AmConfig::LocalIP; + + n_req.from = req.to; + n_req.from_uri = req.r_uri; + n_req.from_tag = AmSession::getNewId(); + n_req.user = req.user; + + n_req.r_uri = uri_from_name_addr(getHeader(req.hdrs, "Refer-To")); + n_req.to = getHeader(req.hdrs, "Refer-To"); + n_req.to_tag = ""; + n_req.cmd = req.cmd; // application from REFER + + n_req.callid = AmSession::getNewId() + "@" + AmConfig::LocalIP; + + if (AmSessionContainer::instance()->startSessionUAC(n_req) + != NULL) + AmSipDialog::reply_error(req,202,"Accepted"); + else + AmSipDialog::reply_error(req,500,"Not supported here"); + + } else { + + if(!local_tag.empty() || req.method == "CANCEL"){ + AmSipDialog::reply_error(req,481,"Call leg/Transaction does not exist"); + } + else { + //TODO: reply some 4xx. + ERROR("sorry, we don't support beginning a new session with a '%s' message\n", + req.method.c_str()); + AmSipDialog::reply_error(req,500,"Not supported here"); + return; + } + } } } diff --git a/core/AmSession.cpp b/core/AmSession.cpp index cc3af15d..78a3d1d1 100644 --- a/core/AmSession.cpp +++ b/core/AmSession.cpp @@ -286,7 +286,7 @@ void AmSession::run() (dlg.getStatus() == AmSipDialog::Disconnecting)// || // (dlg.getUACTransPending()) ){ - + waitForEvent(); processEvents(); diff --git a/core/AmSessionContainer.cpp b/core/AmSessionContainer.cpp index e52fc81e..e3233a98 100644 --- a/core/AmSessionContainer.cpp +++ b/core/AmSessionContainer.cpp @@ -334,7 +334,14 @@ AmSession* AmSessionContainer::createSession(AmSipRequest& req) throw string("application '" + plugin_name + "' not found !"); } - AmSession* session = state_factory->onInvite(req); + AmSession* session = 0; + if (req.method == "INVITE") + session = state_factory->onInvite(req); + else if (req.method == "REFER") + session = state_factory->onRefer(req); + + + if(!session) { // State creation failed: // application denied session creation diff --git a/core/AmSipDialog.cpp b/core/AmSipDialog.cpp index 63e8328a..a5e16802 100644 --- a/core/AmSipDialog.cpp +++ b/core/AmSipDialog.cpp @@ -180,8 +180,9 @@ void AmSipDialog::updateStatus(const AmSipReply& reply) case Pending: case Disconnected: - if(t.method != "BYE"){ - + // only change status of dialog if reply + // to INVITE received + if(t.method == "INVITE"){ if(reply.code < 200) status = Pending; else if(reply.code >= 300) @@ -615,3 +616,9 @@ void AmSipDialog::setRoute(const string& n_route) m_route = ""; } } + +int AmSipDialog::drop() +{ + status = Disconnected; + return 1; +} diff --git a/core/AmSipDialog.h b/core/AmSipDialog.h index ab41bd45..b53fcd6e 100644 --- a/core/AmSipDialog.h +++ b/core/AmSipDialog.h @@ -143,6 +143,7 @@ public: const string& body); int refer(const string& refer_to); int transfer(const string& target); + int drop(); /** * @return true if a transaction could be found that