mirror of https://github.com/sipwise/sems.git
The version included is 4.1.1. If you generate some files using a new version of sip4, update or remove sip.h in the apps/py_sems/sip directory. git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@231 8eb893ce-cfd4-0310-b710-fb5ebe64c474sayer/1.4-spce2.6
parent
5dbbe0e7ab
commit
2fc65e1012
@ -1,598 +0,0 @@
|
||||
/*
|
||||
* $Id: Ivr.cpp,v 1.26.2.1 2005/09/02 13:47:46 rco Exp $
|
||||
* Copyright (C) 2002-2003 Fhg Fokus
|
||||
*
|
||||
* 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 "IvrDialogBase.h"
|
||||
//#include "IvrSipDialog.h"
|
||||
#include "IvrAudio.h"
|
||||
#include "Ivr.h"
|
||||
|
||||
#include "AmConfigReader.h"
|
||||
#include "AmConfig.h"
|
||||
#include "log.h"
|
||||
#include "AmApi.h"
|
||||
#include "AmUtils.h"
|
||||
#include "AmSessionScheduler.h"
|
||||
//#include "AmSessionTimer.h"
|
||||
#include "AmPlugIn.h"
|
||||
|
||||
#include "sip/sipAPIpy_ivr.h"
|
||||
#include "sip/sippy_ivrIvrDialog.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <regex.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <set>
|
||||
using std::set;
|
||||
|
||||
|
||||
#define PYFILE_REGEX "(.+)\\.(py|pyc|pyo)$"
|
||||
|
||||
|
||||
EXPORT_SESSION_FACTORY(IvrFactory,MOD_NAME);
|
||||
|
||||
PyMODINIT_FUNC initpy_ivr();
|
||||
|
||||
struct PythonGIL
|
||||
{
|
||||
PyGILState_STATE gst;
|
||||
|
||||
PythonGIL() { gst = PyGILState_Ensure(); }
|
||||
~PythonGIL(){ PyGILState_Release(gst); }
|
||||
};
|
||||
|
||||
|
||||
// This must be the first declaration of every
|
||||
// function using Python C-API.
|
||||
// But this is not necessary in function which
|
||||
// will get called from Python
|
||||
#define PYLOCK PythonGIL _py_gil
|
||||
|
||||
extern "C" {
|
||||
|
||||
static PyObject* ivr_log(PyObject*, PyObject* args)
|
||||
{
|
||||
int level;
|
||||
char *msg;
|
||||
|
||||
if(!PyArg_ParseTuple(args,"is",&level,&msg))
|
||||
return NULL;
|
||||
|
||||
if((level)<=log_level) {
|
||||
|
||||
//if(level == L_ERR)
|
||||
//assert(0);
|
||||
|
||||
if(log_stderr)
|
||||
log_print( level, msg );
|
||||
else {
|
||||
switch(level){
|
||||
case L_ERR:
|
||||
syslog(LOG_ERR | L_FAC, "Error: %s", msg);
|
||||
break;
|
||||
case L_WARN:
|
||||
syslog(LOG_WARNING | L_FAC, "Warning: %s", msg);
|
||||
break;
|
||||
case L_INFO:
|
||||
syslog(LOG_INFO | L_FAC, "Info: %s", msg);
|
||||
break;
|
||||
case L_DBG:
|
||||
syslog(LOG_DEBUG | L_FAC, "Debug: %s", msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject* ivr_getHeader(PyObject*, PyObject* args)
|
||||
{
|
||||
char* headers;
|
||||
char* header_name;
|
||||
if(!PyArg_ParseTuple(args,"ss",&headers,&header_name))
|
||||
return NULL;
|
||||
|
||||
string res = getHeader(headers,header_name);
|
||||
return PyString_FromString(res.c_str());
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef ivr_methods[] = {
|
||||
{"log", (PyCFunction)ivr_log, METH_VARARGS,"Log a message using Sems' logging system"},
|
||||
{"getHeader", (PyCFunction)ivr_getHeader, METH_VARARGS,"Python getHeader wrapper"},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
}
|
||||
|
||||
IvrFactory::IvrFactory(const string& _app_name)
|
||||
: AmSessionFactory(_app_name),
|
||||
user_timer_fact(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void IvrFactory::setScriptPath(const string& path)
|
||||
{
|
||||
string python_path = script_path = path;
|
||||
|
||||
|
||||
if(python_path.length()){
|
||||
|
||||
python_path = AmConfig::PlugInPath + ":" + python_path;
|
||||
}
|
||||
else
|
||||
python_path = AmConfig::PlugInPath;
|
||||
|
||||
char* old_path=0;
|
||||
if((old_path = getenv("PYTHONPATH")) != 0)
|
||||
if(strlen(old_path))
|
||||
python_path += ":" + string(old_path);
|
||||
|
||||
DBG("setting PYTHONPATH to: '%s'\n",python_path.c_str());
|
||||
setenv("PYTHONPATH",python_path.c_str(),1);
|
||||
|
||||
}
|
||||
|
||||
void IvrFactory::import_object(PyObject* m, char* name, PyTypeObject* type)
|
||||
{
|
||||
if (PyType_Ready(type) < 0){
|
||||
ERROR("PyType_Ready failed !\n");
|
||||
return;
|
||||
}
|
||||
Py_INCREF(type);
|
||||
PyModule_AddObject(m, name, (PyObject *)type);
|
||||
}
|
||||
|
||||
void IvrFactory::import_ivr_builtins()
|
||||
{
|
||||
// ivr module - start
|
||||
PyImport_AddModule("ivr");
|
||||
ivr_module = Py_InitModule("ivr",ivr_methods);
|
||||
|
||||
// IvrSipDialog (= AmSipDialog)
|
||||
//import_object(ivr_module, "IvrSipDialog", &IvrSipDialogType);
|
||||
|
||||
// IvrDialogBase
|
||||
//import_object(ivr_module,"IvrDialogBase",&IvrDialogBaseType);
|
||||
|
||||
|
||||
// IvrAudioFile
|
||||
import_object(ivr_module,"IvrAudioFile",&IvrAudioFileType);
|
||||
|
||||
PyModule_AddIntConstant(ivr_module, "AUDIO_READ",AUDIO_READ);
|
||||
PyModule_AddIntConstant(ivr_module, "AUDIO_WRITE",AUDIO_WRITE);
|
||||
// ivr module - end
|
||||
|
||||
// add log level for the log module
|
||||
PyModule_AddIntConstant(ivr_module, "SEMS_LOG_LEVEL",log_level);
|
||||
|
||||
import_module("log");
|
||||
initpy_ivr();
|
||||
}
|
||||
|
||||
void IvrFactory::import_module(const char* modname)
|
||||
{
|
||||
PyObject* py_mod_name = PyString_FromString(modname);
|
||||
PyObject* py_mod = PyImport_Import(py_mod_name);
|
||||
Py_DECREF(py_mod_name);
|
||||
|
||||
if(!py_mod){
|
||||
PyErr_Print();
|
||||
ERROR("IvrFactory: could not find python module '%s'.\n",modname);
|
||||
ERROR("IvrFactory: please check your installation.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void IvrFactory::init_python_interpreter()
|
||||
{
|
||||
Py_Initialize();
|
||||
PyEval_InitThreads();
|
||||
import_ivr_builtins();
|
||||
PyEval_ReleaseLock();
|
||||
}
|
||||
|
||||
IvrDialog* IvrFactory::newDlg(const string& name)
|
||||
{
|
||||
PYLOCK;
|
||||
|
||||
map<string,IvrScriptDesc>::iterator mod_it = mod_reg.find(name);
|
||||
if(mod_it == mod_reg.end()){
|
||||
ERROR("Unknown script name '%s'\n", name.c_str());
|
||||
throw AmSession::Exception(500,"Unknown Application");
|
||||
}
|
||||
|
||||
IvrScriptDesc& mod_desc = mod_it->second;
|
||||
|
||||
AmDynInvoke* user_timer = user_timer_fact->getInstance();
|
||||
if(!user_timer){
|
||||
ERROR("could not get a user timer reference\n");
|
||||
throw AmSession::Exception(500,"could not get a user timer reference");
|
||||
}
|
||||
|
||||
PyObject* dlg_inst = PyObject_Call(mod_desc.dlg_class,PyTuple_New(0),NULL);
|
||||
if(!dlg_inst){
|
||||
|
||||
PyErr_Print();
|
||||
ERROR("IvrFactory: while loading \"%s\": could not create instance\n",
|
||||
name.c_str());
|
||||
throw AmSession::Exception(500,"Internal error in IVR plug-in.");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int err=0;
|
||||
IvrDialog* dlg = (IvrDialog*)sipForceConvertTo_IvrDialog(dlg_inst,&err);
|
||||
if(!dlg || err){
|
||||
|
||||
PyErr_Print();
|
||||
ERROR("IvrFactory: while loading \"%s\": could not retrieve IvrDialog ptr.\n",
|
||||
name.c_str());
|
||||
throw AmSession::Exception(500,"Internal error in IVR plug-in.");
|
||||
Py_DECREF(dlg_inst);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// take the ownership over dlg
|
||||
sipTransfer(dlg_inst,1);
|
||||
|
||||
return dlg;
|
||||
}
|
||||
|
||||
bool IvrFactory::loadScript(const string& path)
|
||||
{
|
||||
PYLOCK;
|
||||
|
||||
PyObject *modName,*mod,*dict, *dlg_class, *config=NULL;
|
||||
|
||||
modName = PyString_FromString(path.c_str());
|
||||
mod = PyImport_Import(modName);
|
||||
|
||||
AmConfigReader cfg;
|
||||
string cfg_file = add2path(AmConfig::ModConfigPath,1,(path + ".conf").c_str());
|
||||
|
||||
Py_DECREF(modName);
|
||||
|
||||
if(!mod){
|
||||
PyErr_Print();
|
||||
WARN("IvrFactory: Failed to load \"%s\"\n", path.c_str());
|
||||
|
||||
dict = PyImport_GetModuleDict();
|
||||
Py_INCREF(dict);
|
||||
PyDict_DelItemString(dict,path.c_str());
|
||||
Py_DECREF(dict);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
dict = PyModule_GetDict(mod);
|
||||
dlg_class = PyDict_GetItemString(dict, "IvrScript");
|
||||
|
||||
if(!dlg_class){
|
||||
|
||||
PyErr_Print();
|
||||
WARN("IvrFactory: class IvrDialog not found in \"%s\"\n", path.c_str());
|
||||
goto error1;
|
||||
}
|
||||
|
||||
Py_INCREF(dlg_class);
|
||||
|
||||
if(!PyObject_IsSubclass(dlg_class,(PyObject *)sipClass_IvrDialog)){
|
||||
|
||||
WARN("IvrFactory: in \"%s\": IvrScript is not a "
|
||||
"subtype of IvrDialog\n", path.c_str());
|
||||
|
||||
goto error2;
|
||||
}
|
||||
|
||||
if(cfg.loadFile(cfg_file)){
|
||||
ERROR("could not load config file at %s\n",cfg_file.c_str());
|
||||
goto error2;
|
||||
}
|
||||
|
||||
config = PyDict_New();
|
||||
if(!config){
|
||||
ERROR("could not allocate new dict for config\n");
|
||||
goto error2;
|
||||
}
|
||||
|
||||
for(map<string,string>::const_iterator it = cfg.begin();
|
||||
it != cfg.end(); it++){
|
||||
|
||||
PyDict_SetItem(config,
|
||||
PyString_FromString(it->first.c_str()),
|
||||
PyString_FromString(it->second.c_str()));
|
||||
}
|
||||
|
||||
PyObject_SetAttrString(mod,"config",config);
|
||||
|
||||
mod_reg.insert(make_pair(path,
|
||||
IvrScriptDesc(mod,dlg_class)));
|
||||
|
||||
return true;
|
||||
|
||||
error2:
|
||||
Py_DECREF(dlg_class);
|
||||
error1:
|
||||
Py_DECREF(mod);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads python script path and default script file from configuration file
|
||||
*/
|
||||
int IvrFactory::onLoad()
|
||||
{
|
||||
user_timer_fact = AmPlugIn::instance()->getFactory4Di("user_timer");
|
||||
if(!user_timer_fact){
|
||||
|
||||
ERROR("could not load user_timer from session_timer plug-in\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
AmConfigReader cfg;
|
||||
|
||||
if(cfg.loadFile(add2path(AmConfig::ModConfigPath,1,MOD_NAME ".conf")))
|
||||
return -1;
|
||||
|
||||
// get application specific global parameters
|
||||
configureModule(cfg);
|
||||
|
||||
setScriptPath(cfg.getParameter("script_path"));
|
||||
init_python_interpreter();
|
||||
|
||||
DBG("** IVR compile time configuration:\n");
|
||||
DBG("** built with PYTHON support.\n");
|
||||
|
||||
#ifdef IVR_WITH_TTS
|
||||
DBG("** Text-To-Speech enabled\n");
|
||||
#else
|
||||
DBG("** Text-To-Speech disabled\n");
|
||||
#endif
|
||||
|
||||
DBG("** IVR run time configuration:\n");
|
||||
DBG("** script path: \'%s\'\n", script_path.c_str());
|
||||
|
||||
regex_t reg;
|
||||
if(regcomp(®,PYFILE_REGEX,REG_EXTENDED)){
|
||||
ERROR("while compiling regular expression\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
DIR* dir = opendir(script_path.c_str());
|
||||
if(!dir){
|
||||
regfree(®);
|
||||
ERROR("Ivr: script pre-loader (%s): %s\n",
|
||||
script_path.c_str(),strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
DBG("directory '%s' opened\n",script_path.c_str());
|
||||
|
||||
set<string> unique_entries;
|
||||
regmatch_t pmatch[2];
|
||||
|
||||
struct dirent* entry=0;
|
||||
while((entry = readdir(dir)) != NULL){
|
||||
|
||||
if(!regexec(®,entry->d_name,2,pmatch,0)){
|
||||
|
||||
string name(entry->d_name + pmatch[1].rm_so,
|
||||
pmatch[1].rm_eo - pmatch[1].rm_so);
|
||||
|
||||
unique_entries.insert(name);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
regfree(®);
|
||||
|
||||
AmPlugIn* plugin = AmPlugIn::instance();
|
||||
for(set<string>::iterator it = unique_entries.begin();
|
||||
it != unique_entries.end(); it++) {
|
||||
|
||||
if(loadScript(*it)){
|
||||
bool res = plugin->registerFactory4App(*it,this);
|
||||
if(res)
|
||||
INFO("Application script registered: %s.\n",
|
||||
it->c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // don't stop sems from starting up
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a script using user name from URI.
|
||||
* Note: there is no default script.
|
||||
*/
|
||||
AmSession* IvrFactory::onInvite(const AmSipRequest& req)
|
||||
{
|
||||
if(req.cmd != MOD_NAME)
|
||||
return newDlg(req.cmd);
|
||||
else
|
||||
return newDlg(req.user);
|
||||
}
|
||||
|
||||
IvrDialog::IvrDialog()
|
||||
: py_mod(NULL),
|
||||
py_dlg(NULL),
|
||||
playlist(this),
|
||||
user_timer(NULL)
|
||||
{
|
||||
sip_relay_only = false;
|
||||
}
|
||||
|
||||
IvrDialog::IvrDialog(AmDynInvoke* user_timer)
|
||||
: py_mod(NULL),
|
||||
py_dlg(NULL),
|
||||
playlist(this),
|
||||
user_timer(user_timer)
|
||||
{
|
||||
sip_relay_only = false;
|
||||
}
|
||||
|
||||
IvrDialog::~IvrDialog()
|
||||
{
|
||||
DBG("IvrDialog::~IvrDialog()\n");
|
||||
|
||||
PYLOCK;
|
||||
Py_XDECREF(py_mod);
|
||||
Py_XDECREF(py_dlg);
|
||||
}
|
||||
|
||||
void IvrDialog::setPyPtrs(PyObject *mod, PyObject *dlg)
|
||||
{
|
||||
assert(py_mod = mod);
|
||||
assert(py_dlg = dlg);
|
||||
Py_INCREF(py_mod);
|
||||
Py_INCREF(py_dlg);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
type_error(const char *msg)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
null_error(void)
|
||||
{
|
||||
if (!PyErr_Occurred())
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"null argument to internal routine");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyObject_VaCallMethod(PyObject *o, char *name, char *format, va_list va)
|
||||
{
|
||||
PyObject *args, *func = 0, *retval;
|
||||
|
||||
if (o == NULL || name == NULL)
|
||||
return null_error();
|
||||
|
||||
func = PyObject_GetAttrString(o, name);
|
||||
if (func == NULL) {
|
||||
PyErr_SetString(PyExc_AttributeError, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!PyCallable_Check(func))
|
||||
return type_error("call of non-callable attribute");
|
||||
|
||||
if (format && *format) {
|
||||
args = Py_VaBuildValue(format, va);
|
||||
}
|
||||
else
|
||||
args = PyTuple_New(0);
|
||||
|
||||
if (!args)
|
||||
return NULL;
|
||||
|
||||
if (!PyTuple_Check(args)) {
|
||||
PyObject *a;
|
||||
|
||||
a = PyTuple_New(1);
|
||||
if (a == NULL)
|
||||
return NULL;
|
||||
if (PyTuple_SetItem(a, 0, args) < 0)
|
||||
return NULL;
|
||||
args = a;
|
||||
}
|
||||
|
||||
retval = PyObject_Call(func, args, NULL);
|
||||
|
||||
Py_DECREF(args);
|
||||
Py_DECREF(func);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool IvrDialog::callPyEventHandler(char* name, char* fmt, ...)
|
||||
{
|
||||
bool ret=false;
|
||||
va_list va;
|
||||
|
||||
PYLOCK;
|
||||
|
||||
va_start(va, fmt);
|
||||
PyObject* o = PyObject_VaCallMethod(py_dlg,name,fmt,va);
|
||||
va_end(va);
|
||||
|
||||
if(!o) {
|
||||
|
||||
if(PyErr_ExceptionMatches(PyExc_AttributeError)){
|
||||
|
||||
DBG("method %s is not implemented, trying default one\n",name);
|
||||
return true;
|
||||
}
|
||||
|
||||
PyErr_Print();
|
||||
}
|
||||
else {
|
||||
if(o && PyBool_Check(o) && (o == Py_True)) {
|
||||
|
||||
ret = true;
|
||||
}
|
||||
|
||||
Py_DECREF(o);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void IvrDialog::onSessionStart(const AmSipRequest& req)
|
||||
{
|
||||
DBG("IvrDialog::onSessionStart\n");
|
||||
setInOut(&playlist,&playlist);
|
||||
AmB2BCallerSession::onSessionStart(req);
|
||||
}
|
||||
|
||||
void IvrDialog::process(AmEvent* event)
|
||||
{
|
||||
DBG("IvrDialog::process\n");
|
||||
|
||||
AmAudioEvent* audio_event = dynamic_cast<AmAudioEvent*>(event);
|
||||
if(audio_event && audio_event->event_id == AmAudioEvent::noAudio){
|
||||
|
||||
callPyEventHandler("onEmptyQueue", NULL);
|
||||
event->processed = true;
|
||||
}
|
||||
|
||||
AmPluginEvent* plugin_event = dynamic_cast<AmPluginEvent*>(event);
|
||||
if(plugin_event && plugin_event->name == "timer_timeout") {
|
||||
|
||||
callPyEventHandler("onTimer", "i", plugin_event->data.get(0).asInt());
|
||||
event->processed = true;
|
||||
}
|
||||
|
||||
if (!event->processed)
|
||||
AmB2BCallerSession::process(event);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,128 +0,0 @@
|
||||
/*
|
||||
* $Id: Ivr.h,v 1.15.2.1 2005/09/02 13:47:46 rco Exp $
|
||||
* Copyright (C) 2002-2003 Fhg Fokus
|
||||
*
|
||||
* 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 _IVR_H_
|
||||
#define _IVR_H_
|
||||
|
||||
#define MOD_NAME "ivr"
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "AmB2BSession.h"
|
||||
#include "AmPlaylist.h"
|
||||
|
||||
#ifdef IVR_WITH_TTS
|
||||
#include "flite.h"
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
using std::string;
|
||||
using std::map;
|
||||
|
||||
class IvrDialog;
|
||||
|
||||
struct IvrScriptDesc
|
||||
{
|
||||
PyObject* mod;
|
||||
PyObject* dlg_class;
|
||||
|
||||
IvrScriptDesc()
|
||||
: mod(0),
|
||||
dlg_class(0)
|
||||
{}
|
||||
|
||||
IvrScriptDesc(const IvrScriptDesc& d)
|
||||
: mod(d.mod),
|
||||
dlg_class(d.dlg_class)
|
||||
{}
|
||||
|
||||
IvrScriptDesc(PyObject* mod,
|
||||
PyObject* dlg_class)
|
||||
: mod(mod),
|
||||
dlg_class(dlg_class)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
class IvrFactory: public AmSessionFactory
|
||||
{
|
||||
PyObject* ivr_module;
|
||||
string script_path;
|
||||
string default_script;
|
||||
|
||||
map<string,IvrScriptDesc> mod_reg;
|
||||
|
||||
AmDynInvokeFactory* user_timer_fact;
|
||||
|
||||
void init_python_interpreter();
|
||||
void import_ivr_builtins();
|
||||
|
||||
void import_module(const char* modname);
|
||||
void import_object(PyObject* m,
|
||||
char* name,
|
||||
PyTypeObject* type);
|
||||
|
||||
/** @return true if everything ok */
|
||||
bool loadScript(const string& path);
|
||||
|
||||
void setScriptPath(const string& path);
|
||||
bool checkCfg();
|
||||
|
||||
IvrDialog* newDlg(const string& name);
|
||||
|
||||
public:
|
||||
IvrFactory(const string& _app_name);
|
||||
|
||||
int onLoad();
|
||||
AmSession* onInvite(const AmSipRequest& req);
|
||||
};
|
||||
|
||||
|
||||
class IvrDialog : public AmB2BCallerSession
|
||||
{
|
||||
PyObject *py_mod;
|
||||
PyObject *py_dlg;
|
||||
|
||||
bool callPyEventHandler(char* name, char* fmt, ...);
|
||||
|
||||
void process(AmEvent* event);
|
||||
|
||||
public:
|
||||
AmDynInvoke* user_timer;
|
||||
AmPlaylist playlist;
|
||||
|
||||
IvrDialog();
|
||||
IvrDialog(AmDynInvoke* user_timer);
|
||||
~IvrDialog();
|
||||
|
||||
// must be called before everything else.
|
||||
void setPyPtrs(PyObject *mod, PyObject *dlg);
|
||||
|
||||
void onSessionStart(const AmSipRequest& req);
|
||||
/* void onBye(const AmSipRequest& req); */
|
||||
/* void onDtmf(int event, int duration_msec); */
|
||||
|
||||
/* void onOtherBye(const AmSipRequest& req); */
|
||||
/* void onOtherReply(const AmSipReply& r); */
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,321 +0,0 @@
|
||||
#include "IvrAudio.h"
|
||||
#include "AmAudio.h"
|
||||
#include "AmSession.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
#ifdef IVR_WITH_TTS
|
||||
|
||||
#define TTS_CACHE_PATH "/tmp/"
|
||||
extern "C" cst_voice *register_cmu_us_kal();
|
||||
|
||||
#endif //ivr_with_tts
|
||||
|
||||
|
||||
static PyObject* IvrAudioFile_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
DBG("---------- IvrAudioFile_alloc -----------\n");
|
||||
IvrAudioFile *self;
|
||||
|
||||
self = (IvrAudioFile *)type->tp_alloc(type, 0);
|
||||
|
||||
if (self != NULL) {
|
||||
|
||||
self->af = new AmAudioFile();
|
||||
if(!self->af){
|
||||
Py_DECREF(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef IVR_WITH_TTS
|
||||
flite_init();
|
||||
self->tts_voice = register_cmu_us_kal();
|
||||
self->filename = new string();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
static void IvrAudioFile_dealloc(IvrAudioFile* self)
|
||||
{
|
||||
DBG("---------- IvrAudioFile_dealloc -----------\n");
|
||||
delete self->af;
|
||||
self->af = NULL;
|
||||
|
||||
#ifdef IVR_WITH_TTS
|
||||
if(self->del_file && !self->filename->empty())
|
||||
unlink(self->filename->c_str());
|
||||
delete self->filename;
|
||||
#endif
|
||||
|
||||
self->ob_type->tp_free((PyObject*)self);
|
||||
}
|
||||
|
||||
static PyObject* IvrAudioFile_open(IvrAudioFile* self, PyObject* args)
|
||||
{
|
||||
int ivr_open_mode;
|
||||
char* filename;
|
||||
bool is_tmp;
|
||||
PyObject* py_is_tmp = NULL;
|
||||
AmAudioFile::OpenMode open_mode;
|
||||
|
||||
if(!PyArg_ParseTuple(args,"si|O",&filename,&ivr_open_mode,&py_is_tmp))
|
||||
return NULL;
|
||||
|
||||
switch(ivr_open_mode){
|
||||
case AUDIO_READ:
|
||||
open_mode = AmAudioFile::Read;
|
||||
break;
|
||||
case AUDIO_WRITE:
|
||||
open_mode = AmAudioFile::Write;
|
||||
break;
|
||||
default:
|
||||
PyErr_SetString(PyExc_TypeError,"Unknown open mode");
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if((py_is_tmp == NULL) || (py_is_tmp == Py_False))
|
||||
is_tmp = false;
|
||||
else if(py_is_tmp == Py_True)
|
||||
is_tmp = true;
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError,"third parameter should be of type PyBool");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(self->af->open(filename,open_mode,is_tmp)){
|
||||
PyErr_SetString(PyExc_IOError,"Could not open file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject* IvrAudioFile_fpopen(IvrAudioFile* self, PyObject* args)
|
||||
{
|
||||
int ivr_open_mode;
|
||||
char* filename;
|
||||
PyObject* py_file = NULL;
|
||||
AmAudioFile::OpenMode open_mode;
|
||||
|
||||
if(!PyArg_ParseTuple(args,"siO",&filename,&ivr_open_mode,&py_file))
|
||||
return NULL;
|
||||
|
||||
switch(ivr_open_mode){
|
||||
case AUDIO_READ:
|
||||
open_mode = AmAudioFile::Read;
|
||||
break;
|
||||
case AUDIO_WRITE:
|
||||
open_mode = AmAudioFile::Write;
|
||||
break;
|
||||
default:
|
||||
PyErr_SetString(PyExc_TypeError,"Unknown open mode");
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
FILE* fp = PyFile_AsFile(py_file);
|
||||
if(!fp){
|
||||
PyErr_SetString(PyExc_IOError,"Could not get FILE pointer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(self->af->fpopen(filename,open_mode,fp)){
|
||||
PyErr_SetString(PyExc_IOError,"Could not open file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject* IvrAudioFile_rewind(IvrAudioFile* self, PyObject* args)
|
||||
{
|
||||
self->af->rewind();
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
#ifdef IVR_WITH_TTS
|
||||
static PyObject* IvrAudioFile_tts(PyObject* cls, PyObject* args)
|
||||
{
|
||||
char* text;
|
||||
if(!PyArg_ParseTuple(args,"s",&text))
|
||||
return NULL;
|
||||
|
||||
PyObject* constr_args = Py_BuildValue("(O)",Py_None);
|
||||
PyObject* tts_file = PyObject_CallObject(cls,constr_args);
|
||||
Py_DECREF(constr_args);
|
||||
|
||||
if(tts_file == NULL){
|
||||
PyErr_Print();
|
||||
PyErr_SetString(PyExc_RuntimeError,"could not create new IvrAudioFile object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IvrAudioFile* self = (IvrAudioFile*)tts_file;
|
||||
|
||||
*self->filename = string(TTS_CACHE_PATH) + AmSession::getNewId() + string(".wav");
|
||||
self->del_file = true;
|
||||
flite_text_to_speech(text,self->tts_voice,self->filename->c_str());
|
||||
|
||||
if(self->af->open(self->filename->c_str(),AmAudioFile::Read)){
|
||||
Py_DECREF(tts_file);
|
||||
PyErr_SetString(PyExc_IOError,"could not open TTS file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tts_file;
|
||||
}
|
||||
#endif
|
||||
|
||||
static PyObject* IvrAudioFile_close(IvrAudioFile* self, PyObject*)
|
||||
{
|
||||
self->af->close();
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject* IvrAudioFile_getDataSize(IvrAudioFile* self, PyObject*)
|
||||
{
|
||||
return PyInt_FromLong(self->af->getDataSize());
|
||||
}
|
||||
|
||||
static PyObject* IvrAudioFile_setRecordTime(IvrAudioFile* self, PyObject* args)
|
||||
{
|
||||
int rec_time;
|
||||
if(!PyArg_ParseTuple(args,"i",&rec_time))
|
||||
return NULL;
|
||||
|
||||
self->af->setRecordTime(rec_time);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject* IvrAudioFile_exportRaw(IvrAudioFile* self, PyObject*)
|
||||
{
|
||||
if(self->af->getMode() == AmAudioFile::Write)
|
||||
self->af->on_close();
|
||||
|
||||
self->af->rewind();
|
||||
|
||||
return PyFile_FromFile(self->af->getfp(),"","rwb",NULL);
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef IvrAudioFile_methods[] = {
|
||||
{"open", (PyCFunction)IvrAudioFile_open, METH_VARARGS,
|
||||
"open the audio file"
|
||||
},
|
||||
{"fpopen", (PyCFunction)IvrAudioFile_fpopen, METH_VARARGS,
|
||||
"open the audio file"
|
||||
},
|
||||
{"close", (PyCFunction)IvrAudioFile_close, METH_NOARGS,
|
||||
"close the audio file"
|
||||
},
|
||||
{"rewind", (PyCFunction)IvrAudioFile_rewind, METH_NOARGS,
|
||||
"rewind the audio file"
|
||||
},
|
||||
{"getDataSize", (PyCFunction)IvrAudioFile_getDataSize, METH_NOARGS,
|
||||
"returns the recorded data size"
|
||||
},
|
||||
{"setRecordTime", (PyCFunction)IvrAudioFile_setRecordTime, METH_VARARGS,
|
||||
"set the maximum record time in millisecond"
|
||||
},
|
||||
{"exportRaw", (PyCFunction)IvrAudioFile_exportRaw, METH_NOARGS,
|
||||
"creates a new Python file with the actual file"
|
||||
" and eventually flushes headers (audio->on_stop)"
|
||||
},
|
||||
#ifdef IVR_WITH_TTS
|
||||
{"tts", (PyCFunction)IvrAudioFile_tts, METH_CLASS | METH_VARARGS,
|
||||
"text to speech"
|
||||
},
|
||||
#endif
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
static PyObject* IvrAudioFile_getloop(IvrAudioFile* self, void*)
|
||||
{
|
||||
PyObject* loop = self->af->loop.get() ? Py_True : Py_False;
|
||||
Py_INCREF(loop);
|
||||
return loop;
|
||||
}
|
||||
|
||||
static int IvrAudioFile_setloop(IvrAudioFile* self, PyObject* value, void*)
|
||||
{
|
||||
if (value == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(value == Py_True)
|
||||
self->af->loop.set(true);
|
||||
|
||||
else if(value == Py_False)
|
||||
self->af->loop.set(false);
|
||||
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"The first attribute value must be a boolean");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyGetSetDef IvrAudioFile_getseters[] = {
|
||||
{"loop",
|
||||
(getter)IvrAudioFile_getloop, (setter)IvrAudioFile_setloop,
|
||||
"repeat mode",
|
||||
NULL},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
PyTypeObject IvrAudioFileType = {
|
||||
|
||||
PyObject_HEAD_INIT(NULL)
|
||||
0, /*ob_size*/
|
||||
"ivr.IvrAudioFile", /*tp_name*/
|
||||
sizeof(IvrAudioFile), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
(destructor)IvrAudioFile_dealloc, /*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*/
|
||||
"An audio file", /*tp_doc*/
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
IvrAudioFile_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
IvrAudioFile_getseters, /* 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 */
|
||||
IvrAudioFile_new, /* tp_new */
|
||||
};
|
||||
@ -1,33 +0,0 @@
|
||||
#ifndef IvrAudio_h
|
||||
#define IvrAudio_h
|
||||
|
||||
// Python stuff
|
||||
#include <Python.h>
|
||||
#include "structmember.h"
|
||||
|
||||
#include "AmAudio.h"
|
||||
|
||||
#define AUDIO_READ 1
|
||||
#define AUDIO_WRITE 2
|
||||
|
||||
#ifdef IVR_WITH_TTS
|
||||
#include "flite.h"
|
||||
#endif
|
||||
|
||||
// Data definition
|
||||
typedef struct {
|
||||
|
||||
PyObject_HEAD
|
||||
AmAudioFile* af;
|
||||
|
||||
#ifdef IVR_WITH_TTS
|
||||
cst_voice* tts_voice;
|
||||
string* filename;
|
||||
bool del_file;
|
||||
#endif
|
||||
|
||||
} IvrAudioFile;
|
||||
|
||||
extern PyTypeObject IvrAudioFileType;
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,560 @@
|
||||
/*
|
||||
* The SIP module interface.
|
||||
*
|
||||
* Copyright (c) 2004
|
||||
* Riverbank Computing Limited <info@riverbankcomputing.co.uk>
|
||||
*
|
||||
* This file is part of SIP.
|
||||
*
|
||||
* This copy of SIP is licensed for use under the terms of the SIP License
|
||||
* Agreement. See the file LICENSE for more details.
|
||||
*
|
||||
* SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SIP_H
|
||||
#define _SIP_H
|
||||
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
/*
|
||||
* There is a mis-feature somewhere with the Borland compiler. This works
|
||||
* around it.
|
||||
*/
|
||||
#if defined(__BORLANDC__)
|
||||
#include <rpc.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* Sanity check on the Python version. */
|
||||
#if PY_VERSION_HEX < 0x02030000
|
||||
#error "This version of SIP requires Python v2.3 or later"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define the SIP version number.
|
||||
*/
|
||||
#define SIP_VERSION 0x040101
|
||||
#define SIP_VERSION_STR "4.1.1"
|
||||
#define SIP_BUILD "255"
|
||||
|
||||
|
||||
/*
|
||||
* Define the current API version number. SIP must handle modules with the
|
||||
* same major number and with the same or earlier minor number. Whenever data
|
||||
* structure elements are added they must be appended and the minor number
|
||||
* incremented. Whenever data structure elements are removed or the order
|
||||
* changed then the major number must be incremented and the minor number set
|
||||
* to 0.
|
||||
*
|
||||
* History:
|
||||
*
|
||||
* 0.2 Added the 'H' format character to sip_api_parse_args().
|
||||
*
|
||||
* 0.1 Added sip_api_add_class_instance().
|
||||
* Added the 't' format character to sip_api_parse_args().
|
||||
* Deprecated the 'J' and 'K' format characters to sip_api_parse_result().
|
||||
*
|
||||
* 0.0 Original version.
|
||||
*/
|
||||
#define SIP_API_MAJOR_NR 0
|
||||
#define SIP_API_MINOR_NR 2
|
||||
|
||||
|
||||
/* Some compatibility stuff to help with handwritten code for SIP v3. */
|
||||
#if !defined(ANY)
|
||||
#define ANY void
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* The mask that can be passed to sipTrace().
|
||||
*/
|
||||
#define SIP_TRACE_CATCHERS 0x0001
|
||||
#define SIP_TRACE_CTORS 0x0002
|
||||
#define SIP_TRACE_DTORS 0x0004
|
||||
#define SIP_TRACE_INITS 0x0008
|
||||
#define SIP_TRACE_DEALLOCS 0x0010
|
||||
#define SIP_TRACE_METHODS 0x0020
|
||||
|
||||
|
||||
/*
|
||||
* Hide some thread dependent stuff.
|
||||
*/
|
||||
#ifdef WITH_THREAD
|
||||
typedef PyGILState_STATE sip_gilstate_t;
|
||||
#define SIP_RELEASE_GIL(gs) PyGILState_Release(gs);
|
||||
#define SIP_BLOCK_THREADS {PyGILState_STATE sipGIL = PyGILState_Ensure();
|
||||
#define SIP_UNBLOCK_THREADS PyGILState_Release(sipGIL);}
|
||||
#else
|
||||
typedef int sip_gilstate_t;
|
||||
#define SIP_RELEASE_GIL(gs)
|
||||
#define SIP_BLOCK_THREADS
|
||||
#define SIP_UNBLOCK_THREADS
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* The metatype for a wrapper type.
|
||||
*/
|
||||
typedef struct _sipWrapperType {
|
||||
PyHeapTypeObject super; /* The super-metatype. */
|
||||
struct _sipTypeDef *type; /* The additional type information. */
|
||||
} sipWrapperType;
|
||||
|
||||
|
||||
/*
|
||||
* A C/C++ object wrapped as a Python object.
|
||||
*/
|
||||
typedef struct _sipWrapper {
|
||||
PyObject_HEAD
|
||||
union {
|
||||
void *cppPtr; /* C/C++ object pointer. */
|
||||
void *(*afPtr)(); /* Access function. */
|
||||
} u;
|
||||
int flags; /* Object flags. */
|
||||
PyObject *dict; /* The instance dictionary. */
|
||||
struct _sipPySig *pySigList; /* Python signal list (complex). */
|
||||
struct _sipWrapper *next; /* Next object at this address. */
|
||||
} sipWrapper;
|
||||
|
||||
|
||||
/*
|
||||
* Some convenient function pointers.
|
||||
*/
|
||||
typedef void *(*sipInitFunc)(sipWrapper *,PyObject *,int *);
|
||||
typedef void (*sipDeallocFunc)(sipWrapper *);
|
||||
typedef void *(*sipCastFunc)(void *,sipWrapperType *);
|
||||
typedef sipWrapperType *(*sipSubClassConvertFunc)(void *);
|
||||
typedef void *(*sipForceConvertToFunc)(PyObject *,int *);
|
||||
typedef int (*sipConvertToFunc)(PyObject *,void **,int *);
|
||||
typedef PyObject *(*sipConvertFromFunc)(void *);
|
||||
typedef struct _sipProxy *(*sipProxyFunc)(void);
|
||||
typedef int (*sipVirtHandlerFunc)(void *,PyObject *,...);
|
||||
typedef int (*sipEmitFunc)(sipWrapper *,PyObject *);
|
||||
|
||||
|
||||
/*
|
||||
* The information describing an enum value instance to be added to a
|
||||
* dictionary.
|
||||
*/
|
||||
typedef struct _sipEnumValueInstanceDef {
|
||||
char *evi_name; /* The enum value name. */
|
||||
int evi_val; /* The enum value value. */
|
||||
} sipEnumValueInstanceDef;
|
||||
|
||||
|
||||
/*
|
||||
* The information describing static instances.
|
||||
*/
|
||||
typedef struct _sipInstancesDef {
|
||||
struct _sipClassInstanceDef *id_class; /* The classes. */
|
||||
struct _sipVoidPtrInstanceDef *id_voidp; /* The void *. */
|
||||
struct _sipCharInstanceDef *id_char; /* The chars. */
|
||||
struct _sipStringInstanceDef *id_string; /* The strings. */
|
||||
struct _sipLongInstanceDef *id_long; /* The longs. */
|
||||
struct _sipDoubleInstanceDef *id_double; /* The doubles. */
|
||||
} sipInstancesDef;
|
||||
|
||||
|
||||
/*
|
||||
* The information describing a super-class.
|
||||
*/
|
||||
typedef struct _sipSuperClassDef {
|
||||
unsigned sc_class:16; /* The class number. */
|
||||
unsigned sc_module:8; /* The module number (255 for this one). */
|
||||
unsigned sc_last:1; /* The last in the list. */
|
||||
} sipSuperClassDef;
|
||||
|
||||
|
||||
/*
|
||||
* The information describing a sub-class convertor.
|
||||
*/
|
||||
typedef struct _sipSubClassConvertorDef {
|
||||
sipSubClassConvertFunc scc_convertor; /* The convertor. */
|
||||
sipSuperClassDef scc_base; /* The encoded base type. */
|
||||
sipWrapperType *scc_basetype; /* The base type. */
|
||||
} sipSubClassConvertorDef;
|
||||
|
||||
|
||||
/*
|
||||
* The different Python slot types.
|
||||
*/
|
||||
typedef enum {
|
||||
str_slot, /* __str__ */
|
||||
int_slot, /* __int__ */
|
||||
len_slot, /* __len__ */
|
||||
contains_slot, /* __contains__ */
|
||||
add_slot, /* __add__ for number */
|
||||
concat_slot, /* __add__ for sequence types */
|
||||
sub_slot, /* __sub__ */
|
||||
mul_slot, /* __mul__ for number types */
|
||||
repeat_slot, /* __mul__ for sequence types */
|
||||
div_slot, /* __div__ */
|
||||
mod_slot, /* __mod__ */
|
||||
and_slot, /* __and__ */
|
||||
or_slot, /* __or__ */
|
||||
xor_slot, /* __xor__ */
|
||||
lshift_slot, /* __lshift__ */
|
||||
rshift_slot, /* __rshift__ */
|
||||
iadd_slot, /* __iadd__ for number types */
|
||||
iconcat_slot, /* __iadd__ for sequence types */
|
||||
isub_slot, /* __isub__ */
|
||||
imul_slot, /* __imul__ for number types */
|
||||
irepeat_slot, /* __imul__ for sequence types */
|
||||
idiv_slot, /* __idiv__ */
|
||||
imod_slot, /* __imod__ */
|
||||
iand_slot, /* __iand__ */
|
||||
ior_slot, /* __ior__ */
|
||||
ixor_slot, /* __ixor__ */
|
||||
ilshift_slot, /* __ilshift__ */
|
||||
irshift_slot, /* __irshift__ */
|
||||
invert_slot, /* __invert__ */
|
||||
call_slot, /* __call__ */
|
||||
getitem_slot, /* __getitem__ */
|
||||
setitem_slot, /* __setitem__ */
|
||||
delitem_slot, /* __delitem__ */
|
||||
lt_slot, /* __lt__ */
|
||||
le_slot, /* __le__ */
|
||||
eq_slot, /* __eq__ */
|
||||
ne_slot, /* __ne__ */
|
||||
gt_slot, /* __gt__ */
|
||||
ge_slot, /* __ge__ */
|
||||
cmp_slot, /* __cmp__ */
|
||||
nonzero_slot, /* __nonzero__ */
|
||||
neg_slot, /* __neg__ */
|
||||
repr_slot /* __repr__ */
|
||||
} sipPySlotType;
|
||||
|
||||
|
||||
/*
|
||||
* The information describing a Python slot function.
|
||||
*/
|
||||
typedef struct _sipPySlotDef {
|
||||
void *psd_func; /* The function. */
|
||||
sipPySlotType psd_type; /* The type. */
|
||||
} sipPySlotDef;
|
||||
|
||||
|
||||
/*
|
||||
* The information describing a type.
|
||||
*/
|
||||
typedef struct _sipTypeDef {
|
||||
struct _sipExportedModuleDef *td_module; /* The module. */
|
||||
char *td_name; /* The name of the type. */
|
||||
int td_scope; /* The nr. of the scoping type. */
|
||||
sipSuperClassDef *td_supers; /* The super-types. */
|
||||
sipPySlotDef *td_pyslots; /* The table of Python slots. */
|
||||
int td_nrmethods; /* The number of lazy methods. */
|
||||
PyMethodDef *td_methods; /* The table of lazy methods. */
|
||||
int td_nrenums; /* The number of lazy enums. */
|
||||
sipEnumValueInstanceDef *td_enums; /* The table of lazy enums. */
|
||||
PyMethodDef *td_variables; /* The variable table. */
|
||||
sipInitFunc td_init; /* The initialisation function. */
|
||||
sipDeallocFunc td_dealloc; /* The deallocation function. */
|
||||
sipCastFunc td_cast; /* The cast function, 0 if a C struct. */
|
||||
sipForceConvertToFunc td_fcto; /* The force convert to function, 0 if a C++ namespace. */
|
||||
sipConvertToFunc td_cto; /* The convert to function. */
|
||||
sipProxyFunc td_proxy; /* The create proxy function. */
|
||||
struct _sipQtSignal *td_emit; /* Emit table for Qt signals. */
|
||||
sipInstancesDef td_instances; /* The static instances. */
|
||||
} sipTypeDef;
|
||||
|
||||
|
||||
/*
|
||||
* The information describing a mapped class.
|
||||
*/
|
||||
typedef struct _sipMappedTypeDef {
|
||||
sipForceConvertToFunc mt_fcto; /* The force convert to function. */
|
||||
sipConvertToFunc mt_cto; /* The convert to function. */
|
||||
sipConvertFromFunc mt_cfrom; /* The convert from function. */
|
||||
} sipMappedTypeDef;
|
||||
|
||||
|
||||
/*
|
||||
* The information describing an imported module.
|
||||
*/
|
||||
typedef struct _sipImportedModuleDef {
|
||||
char *im_name; /* The module name. */
|
||||
int im_version; /* The required version. */
|
||||
struct _sipExportedModuleDef *im_module; /* The imported module. */
|
||||
} sipImportedModuleDef;
|
||||
|
||||
|
||||
/*
|
||||
* The main client module structure.
|
||||
*/
|
||||
typedef struct _sipExportedModuleDef {
|
||||
struct _sipExportedModuleDef *em_next; /* The next in the list. */
|
||||
char *em_name; /* The module name. */
|
||||
int em_version; /* The module version. */
|
||||
sipImportedModuleDef *em_imports; /* The imported modules. */
|
||||
int em_qobject_class; /* The index of the QObject class. */
|
||||
struct _sipWrapperType **em_types; /* The table of types. */
|
||||
sipMappedTypeDef **em_mappedtypes; /* The table of mapped types. */
|
||||
sipVirtHandlerFunc *em_virthandlers; /* The table of virtual handlers. */
|
||||
sipSubClassConvertorDef *em_convertors; /* The sub-class convertors. */
|
||||
sipInstancesDef em_instances; /* The static instances. */
|
||||
struct _sipLicenseDef *em_license; /* The license. */
|
||||
} sipExportedModuleDef;
|
||||
|
||||
|
||||
/*
|
||||
* The information describing a license to be added to a dictionary.
|
||||
*/
|
||||
typedef struct _sipLicenseDef {
|
||||
char *lc_type; /* The type of license. */
|
||||
char *lc_licensee; /* The licensee. */
|
||||
char *lc_timestamp; /* The timestamp. */
|
||||
char *lc_signature; /* The signature. */
|
||||
} sipLicenseDef;
|
||||
|
||||
|
||||
/*
|
||||
* The information describing a void pointer instance to be added to a
|
||||
* dictionary.
|
||||
*/
|
||||
typedef struct _sipVoidPtrInstanceDef {
|
||||
char *vi_name; /* The void pointer name. */
|
||||
void *vi_val; /* The void pointer value. */
|
||||
} sipVoidPtrInstanceDef;
|
||||
|
||||
|
||||
/*
|
||||
* The information describing a char instance to be added to a dictionary.
|
||||
*/
|
||||
typedef struct _sipCharInstanceDef {
|
||||
char *ci_name; /* The char name. */
|
||||
char ci_val; /* The char value. */
|
||||
} sipCharInstanceDef;
|
||||
|
||||
|
||||
/*
|
||||
* The information describing a string instance to be added to a dictionary.
|
||||
*/
|
||||
typedef struct _sipStringInstanceDef {
|
||||
char *si_name; /* The string name. */
|
||||
char *si_val; /* The string value. */
|
||||
} sipStringInstanceDef;
|
||||
|
||||
|
||||
/*
|
||||
* The information describing a long instance to be added to a dictionary.
|
||||
*/
|
||||
typedef struct _sipLongInstanceDef {
|
||||
char *li_name; /* The long name. */
|
||||
long li_val; /* The long value. */
|
||||
} sipLongInstanceDef;
|
||||
|
||||
|
||||
/*
|
||||
* The information describing a double instance to be added to a dictionary.
|
||||
*/
|
||||
typedef struct _sipDoubleInstanceDef {
|
||||
char *di_name; /* The double name. */
|
||||
double di_val; /* The double value. */
|
||||
} sipDoubleInstanceDef;
|
||||
|
||||
|
||||
/*
|
||||
* The information describing a class instance to be added to a dictionary.
|
||||
*/
|
||||
typedef struct _sipClassInstanceDef {
|
||||
char *ci_name; /* The class name. */
|
||||
void *ci_ptr; /* The actual instance. */
|
||||
struct _sipWrapperType **ci_type; /* A pointer to the Python type. */
|
||||
int ci_flags; /* The wrapping flags. */
|
||||
} sipClassInstanceDef;
|
||||
|
||||
|
||||
/*
|
||||
* Define a mapping between a wrapped type identified by a string and the
|
||||
* corresponding Python type.
|
||||
*/
|
||||
typedef struct _sipStringTypeClassMap {
|
||||
char *typeString; /* The type as a string. */
|
||||
struct _sipWrapperType **pyType; /* A pointer to the Python type. */
|
||||
} sipStringTypeClassMap;
|
||||
|
||||
|
||||
/*
|
||||
* Define a mapping between a wrapped type identified by an integer and the
|
||||
* corresponding Python type.
|
||||
*/
|
||||
typedef struct _sipIntTypeClassMap {
|
||||
int typeInt; /* The type as an integer. */
|
||||
struct _sipWrapperType **pyType; /* A pointer to the Python type. */
|
||||
} sipIntTypeClassMap;
|
||||
|
||||
|
||||
/*
|
||||
* A Python method's component parts. This allows us to re-create the method
|
||||
* without changing the reference counts of the components.
|
||||
*/
|
||||
typedef struct _sipPyMethod {
|
||||
PyObject *mfunc; /* The function. */
|
||||
PyObject *mself; /* Self if it is a bound method. */
|
||||
PyObject *mclass; /* The class. */
|
||||
} sipPyMethod;
|
||||
|
||||
|
||||
/*
|
||||
* Cache a reference to a Python member function.
|
||||
*/
|
||||
typedef struct _sipMethodCache {
|
||||
int mcflags; /* Method cache flags. */
|
||||
sipPyMethod pyMethod; /* The method. */
|
||||
} sipMethodCache;
|
||||
|
||||
|
||||
/*
|
||||
* A slot (in the Qt, rather than Python, sense).
|
||||
*/
|
||||
typedef struct _sipSlot {
|
||||
char *name; /* Name if a Qt or Python signal. */
|
||||
PyObject *pyobj; /* Signal or Qt slot object. */
|
||||
sipPyMethod meth; /* Python slot method, pyobj is NULL. */
|
||||
PyObject *weakSlot; /* A weak reference to the slot. */
|
||||
} sipSlot;
|
||||
|
||||
|
||||
/*
|
||||
* A proxy slot.
|
||||
*/
|
||||
typedef struct _sipProxy {
|
||||
void *qproxy; /* The proxy QObject. */
|
||||
const char **slotTable; /* The table of slots. */
|
||||
sipSlot realSlot; /* The Python slot. */
|
||||
struct _sipWrapper *txSelf; /* The transmitter. */
|
||||
char *txSig; /* The transmitting signal. */
|
||||
const char *rxSlot; /* The receiving slot. */
|
||||
struct _sipProxy *next; /* Next in list. */
|
||||
struct _sipProxy *prev; /* Previous in list. */
|
||||
} sipProxy;
|
||||
|
||||
|
||||
/*
|
||||
* A receiver of a Python signal.
|
||||
*/
|
||||
typedef struct _sipPySigRx {
|
||||
sipSlot rx; /* The receiver. */
|
||||
struct _sipPySigRx *next; /* Next in the list. */
|
||||
} sipPySigRx;
|
||||
|
||||
|
||||
/*
|
||||
* A Python signal.
|
||||
*/
|
||||
typedef struct _sipPySig {
|
||||
char *name; /* The name of the signal. */
|
||||
sipPySigRx *rxlist; /* The list of receivers. */
|
||||
struct _sipPySig *next; /* Next in the list. */
|
||||
} sipPySig;
|
||||
|
||||
|
||||
/*
|
||||
* Maps the name of a Qt signal to a wrapper function to emit it.
|
||||
*/
|
||||
typedef struct _sipQtSignal {
|
||||
char *st_name; /* The signal name. */
|
||||
sipEmitFunc st_emitfunc; /* The emitter function. */
|
||||
} sipQtSignal;
|
||||
|
||||
|
||||
/*
|
||||
* The API exported by the SIP module, ie. pointers to all the data and
|
||||
* functions that can be used by generated code.
|
||||
*/
|
||||
typedef struct _sipAPIDef {
|
||||
/*
|
||||
* The following are part of the public API.
|
||||
*/
|
||||
void (*api_bad_catcher_result)(PyObject *method);
|
||||
void (*api_bad_length_for_slice)(int seqlen,int slicelen);
|
||||
PyObject *(*api_build_result)(int *isErr,char *fmt,...);
|
||||
PyObject *(*api_call_method)(int *isErr,PyObject *method,char *fmt,...);
|
||||
PyObject *(*api_class_name)(PyObject *self);
|
||||
PyObject *(*api_connect_rx)(PyObject *txObj,const char *sig,PyObject *rxObj,const char *slot);
|
||||
int (*api_convert_from_sequence_index)(int idx,int len);
|
||||
void *(*api_convert_to_cpp)(PyObject *sipSelf,sipWrapperType *type,int *iserrp);
|
||||
PyObject *(*api_disconnect_rx)(PyObject *txObj,const char *sig,PyObject *rxObj,const char *slot);
|
||||
int (*api_emit_signal)(PyObject *self,const char *sig,PyObject *sigargs);
|
||||
void (*api_free)(void *mem);
|
||||
void *(*api_get_sender)(void);
|
||||
PyObject *(*api_get_wrapper)(void *cppPtr,sipWrapperType *type);
|
||||
void *(*api_malloc)(size_t nbytes);
|
||||
sipWrapperType *(*api_map_int_to_class)(int typeInt,const sipIntTypeClassMap *map,int maplen);
|
||||
sipWrapperType *(*api_map_string_to_class)(const char *typeString,const sipStringTypeClassMap *map,int maplen);
|
||||
int (*api_parse_result)(int *isErr,PyObject *method,PyObject *res,char *fmt,...);
|
||||
void (*api_trace)(unsigned mask,const char *fmt,...);
|
||||
void (*api_transfer)(PyObject *self,int toCpp);
|
||||
/*
|
||||
* The following are not part of the public API.
|
||||
*/
|
||||
int (*api_export_module)(sipExportedModuleDef *client,unsigned api_major,unsigned api_minor,PyObject *mod_dict);
|
||||
int (*api_add_enum_instances)(PyObject *dict,sipEnumValueInstanceDef *evi);
|
||||
int (*api_parse_args)(int *argsParsedp,PyObject *sipArgs,char *fmt,...);
|
||||
void (*api_common_ctor)(sipMethodCache *cache,int nrmeths);
|
||||
void (*api_common_dtor)(sipWrapper *sipSelf);
|
||||
PyObject *(*api_convert_from_void_ptr)(void *val);
|
||||
void *(*api_convert_to_void_ptr)(PyObject *obj);
|
||||
void (*api_no_ctor)(int argsParsed,char *classname);
|
||||
void (*api_no_function)(int argsParsed,char *func);
|
||||
void (*api_no_method)(int argsParsed,char *classname,char *method);
|
||||
void (*api_bad_class)(const char *classname);
|
||||
void (*api_bad_set_type)(const char *classname,const char *var);
|
||||
void *(*api_get_cpp_ptr)(sipWrapper *w,sipWrapperType *type);
|
||||
void *(*api_get_complex_cpp_ptr)(sipWrapper *w);
|
||||
PyObject *(*api_is_py_method)(sip_gilstate_t *gil,sipMethodCache *pymc,sipWrapper *sipSelf,char *cname,char *mname);
|
||||
PyObject *(*api_map_cpp_to_self)(void *cppPtr,sipWrapperType *type);
|
||||
PyObject *(*api_map_cpp_to_self_sub_class)(void *cppPtr,sipWrapperType *type);
|
||||
PyObject *(*api_new_cpp_to_self)(void *cppPtr,sipWrapperType *type,int initflags);
|
||||
PyObject *(*api_new_cpp_to_self_sub_class)(void *cppPtr,sipWrapperType *type,int initflags);
|
||||
void (*api_call_hook)(char *hookname);
|
||||
void (*api_start_thread)(void);
|
||||
void (*api_end_thread)(void);
|
||||
void (*api_emit_to_slot)(void *sender,sipSlot *slot,char *fmt,...);
|
||||
void (*api_raise_unknown_exception)(void);
|
||||
void (*api_raise_class_exception)(sipWrapperType *type,void *ptr);
|
||||
void (*api_raise_sub_class_exception)(sipWrapperType *type,void *ptr);
|
||||
int (*api_add_class_instance)(PyObject *dict,char *name,void *cppPtr,sipWrapperType *wt);
|
||||
} sipAPIDef;
|
||||
|
||||
|
||||
/*
|
||||
* Useful macros, not part of the public API.
|
||||
*/
|
||||
#define SIP_PY_OWNED 0x01 /* Owned by Python. */
|
||||
#define SIP_SIMPLE 0x02 /* If the instance is simple. */
|
||||
#define SIP_INDIRECT 0x04 /* If there is a level of indirection. */
|
||||
#define SIP_ACCFUNC 0x08 /* If there is an access function. */
|
||||
#define SIP_XTRA_REF 0x10 /* If C++ has an extra reference. */
|
||||
#define SIP_NOT_IN_MAP 0x20 /* If Python object not in the map. */
|
||||
|
||||
#define sipIsPyOwned(w) ((w) -> flags & SIP_PY_OWNED)
|
||||
#define sipSetPyOwned(w) ((w) -> flags |= SIP_PY_OWNED)
|
||||
#define sipResetPyOwned(w) ((w) -> flags &= ~SIP_PY_OWNED)
|
||||
#define sipIsSimple(w) ((w) -> flags & SIP_SIMPLE)
|
||||
#define sipIsIndirect(w) ((w) -> flags & SIP_INDIRECT)
|
||||
#define sipIsAccessFunc(w) ((w) -> flags & SIP_ACCFUNC)
|
||||
#define sipIsExtraRef(w) ((w) -> flags & SIP_XTRA_REF)
|
||||
#define sipSetIsExtraRef(w) ((w) -> flags |= SIP_XTRA_REF)
|
||||
#define sipResetIsExtraRef(w) ((w) -> flags &= ~SIP_XTRA_REF)
|
||||
#define sipNotInMap(w) ((w) -> flags & SIP_NOT_IN_MAP)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
Loading…
Reference in new issue