📄 vxi.cpp
字号:
/****************License************************************************
*
* Copyright 2000-2003. ScanSoft, Inc.
*
* Use of this software is subject to notices and obligations set forth
* in the SpeechWorks Public License - Software Version 1.2 which is
* included with this software.
*
* ScanSoft is a registered trademark of ScanSoft, Inc., and OpenSpeech,
* SpeechWorks and the SpeechWorks logo are registered trademarks or
* trademarks of SpeechWorks International, Inc. in the United States
* and other countries.
*
***********************************************************************/
#include <vxibuildopts.h>
#if P_VXI
#include "VXI.hpp"
#include "DocumentParser.hpp"
#include "SimpleLogger.hpp"
#include "ValueLogging.hpp" // for VXIValue dumping
#include "Scripter.hpp" // for use in ExecutionContext
#include "GrammarManager.hpp" // for use in ExecutionContext
#include "Counters.hpp" // for EventCounter
#include "PropertyList.hpp" // for PropertyList
#include "PromptManager.hpp" // for PromptManager
#include "AnswerParser.hpp" // for AnswerParser
#include "VXML.h" // for node & attribute names
#include "vxi/VXItel.h" // for VXItelInterface
#include "vxi/VXIrec.h" // for parameters from rec answer
#include "vxi/VXIlog.h" // for event IDs
#include "vxi/VXIobject.h" // for Object type
#include "vxi/VXIinet.h"
#include <deque> // for deque (used by Prompts)
#include <sstream> // by ProcessNameList()
#include <algorithm> // for sort, set_intersection, etc.
//#pragma message ("Cleanup comments - Did FIA level functions")
static const wchar_t * const SCOPE_Session = L"session";
static const wchar_t * const SCOPE_Defaults = L"$_platDefaults_";
static const wchar_t * const SCOPE_Application = L"application";
static const wchar_t * const SCOPE_Document = L"document";
static const wchar_t * const SCOPE_Dialog = L"dialog";
static const wchar_t * const SCOPE_Local = L"local";
static const wchar_t * const SCOPE_Anonymous = L"$_execAnonymous_";
static const wchar_t * const GENERIC_DEFAULTS = L"*";
const int DEFAULT_MAX_EXE_STACK_DEPTH = 5;
const int DEFAULT_MAX_EVENT_RETHROWS = 6;
const int DEFAULT_MAX_EVENT_COUNT = 12;
#ifdef _MSC_VER
#pragma warning(disable:4505)
#endif
// ------*---------*---------*---------*---------*---------*---------*---------
static vxistring toString(const VXIString * s)
{
if (s == NULL) return L"";
const VXIchar * temp = VXIStringCStr(s);
if (temp == NULL) return L"";
return temp;
}
static vxistring toString(const VXIchar * s)
{
if (s == NULL) return L"";
return s;
}
// ------*---------*---------*---------*---------*---------*---------*---------
class VXIPromptTranslator : public PromptTranslator {
public:
virtual VXIValue * EvaluateExpression(const vxistring & expression)
{ if (expression.empty()) return NULL;
return jsi.EvalScriptToValue(expression); }
virtual void SetVariable(const vxistring & name, const vxistring & value)
{ if (name.empty()) return;
jsi.MakeVar(name, NULL);
jsi.SetString(name, value); }
VXIPromptTranslator(Scripter & j) : jsi(j) { }
virtual ~VXIPromptTranslator() { }
private:
Scripter & jsi;
};
class VXIAnswerTranslator : public AnswerTranslator {
public:
virtual void EvaluateExpression(const vxistring & expression)
{ if (expression.empty()) return;
jsi.EvalScript(expression); }
virtual void SetString(const vxistring & var, const vxistring & val)
{ jsi.SetString(var, val); }
VXIAnswerTranslator(Scripter & j) : jsi(j) { }
virtual ~VXIAnswerTranslator() { }
private:
Scripter & jsi;
};
// VXIContent wrapper that aid to
// do automated memory managment, the class take ownership of the
// passed-in content
class VXIContentHolder {
public:
VXIContentHolder() : _content(NULL), _contentSize(0),
_contentValue(NULL), _contentType(NULL) { }
VXIContentHolder(VXIContent* c)
: _content(NULL), _contentSize(0),
_contentValue(NULL), _contentType(NULL) {SetContent(c);}
virtual ~VXIContentHolder() { if (_content) VXIContentDestroy(&_content); }
const VXIbyte* GetValue() { return _contentValue; }
const VXIchar* GetType() { return _contentType; }
VXIulong GetSize() { return _contentSize; }
const VXIContent* GetContent() { return _content; }
VXIContent* Release(void)
{ VXIContent* c = _content; _content = NULL; return c; }
void SetContent(VXIContent* content)
{
_content = content;
if( _content )
VXIContentValue(_content, &_contentType, &_contentValue, &_contentSize);
}
private:
VXIContent* _content;
const VXIchar* _contentType;
const VXIbyte* _contentValue;
VXIulong _contentSize;
// do not allow these operations
VXIContentHolder(const VXIContentHolder &);
VXIContentHolder & operator=(const VXIContentHolder &);
};
// Thrown after a successful recognition.
//
class AnswerInformation {
public:
VXMLElement element;
VXMLElement dialog;
AnswerInformation(VXMLElement & e, VXMLElement & d)
: element(e), dialog(d) { }
};
class JumpReturn {
public:
JumpReturn() { }
};
class JumpItem {
public:
VXMLElement item;
JumpItem(const VXMLElement & i) : item(i) { }
};
class JumpDialog {
public:
VXMLElement dialog;
JumpDialog(const VXMLElement d) : dialog(d) { }
};
class JumpDoc {
public:
VXMLElement defaults;
VXMLDocument application;
vxistring applicationURI;
VXMLDocument document;
vxistring documentURI;
VXMLElement documentDialog;
bool isSubdialog;
bool isSubmitElement;
PropertyList properties;
JumpDoc(const VXMLElement & def, const VXMLDocument & app,
const vxistring & appURI, const VXMLDocument & doc, const vxistring & docURI,
const VXMLElement & docdial, bool issub, bool issubmit, const PropertyList & p)
: defaults(def), application(app), applicationURI(appURI),
document(doc), documentURI(docURI), documentDialog(docdial), isSubdialog(issub),
isSubmitElement(issubmit), properties(p)
{ }
~JumpDoc() { }
};
//#############################################################################
// ExecutionContext & Utilities
//#############################################################################
class ExecutionContext {
public:
// These are used by the main run loops, event handling, and subdialog.
// Each of these gets initialized by InstallDocument.
VXMLElement platDefaults;
VXMLDocument application;
vxistring applicationURI;
VXMLDocument document;
vxistring documentName;
vxistring documentURI;
VXMLElement currentDialog;
VXMLElement currentFormItem;
// Limited purpose members.
VXMLElement eventSource; // For prompting (enumerate) during events
VXMLElement lastItem; // Set by <subdialog>
public: // These are used more generally.
Scripter script;
GrammarManager gm;
PromptTracker promptcounts;
EventCounter eventcounts;
PropertyList properties;
typedef std::deque<vxistring> STRINGDEQUE;
STRINGDEQUE formitems;
bool playingPrompts;
ExecutionContext * next;
ExecutionContext(VXIrecInterface * r, VXIjsiInterface * j,
const SimpleLogger & l, ExecutionContext * n)
: script(j), gm(r, l), next(n), playingPrompts(true), properties(l) { }
// may throw VXIException::OutOfMemory()
~ExecutionContext() { }
};
typedef std::deque<vxistring> STRINGDEQUE;
static void ProcessNameList(const vxistring & namelist, STRINGDEQUE & names)
{
names.clear();
if (namelist.empty()) return;
// The namelist is a series of whitespace delimited strings. Read each in
// and insert it into the deque.
std::basic_stringstream<VXIchar> namestream(namelist);
#if (defined(__GNUC__) || defined(_decunix_))
// G++ 2.95 and 3.0.2 do not fully support istream_iterator.
while (namestream.good()) {
vxistring temp;
namestream >> temp;
if (!temp.empty()) names.push_back(temp);
}
#else
std::copy(std::istream_iterator<vxistring, VXIchar>(namestream),
std::istream_iterator<vxistring, VXIchar>(),
std::back_inserter(names));
#endif
// Now sort the deque and return the unique set of names.
if (names.empty()) return;
std::sort(names.begin(), names.end());
STRINGDEQUE::iterator i = std::unique(names.begin(), names.end());
if (i != names.end()) names.erase(i, names.end());
}
//#############################################################################
// Creation and Run
//#############################################################################
VXI::VXI()
: parser(NULL), log(NULL), inet(NULL), rec(NULL), jsi(NULL), tel(NULL),
exe(NULL), stackDepth(0), sdParams(NULL), sdResult(NULL), sdEvent(NULL),
updateDefaultDoc(true), mutex(), uriPlatDefaults(), uriBeep(),
lineHungUp(false), stopRequested(false), haveExternalEvents(false)
{
try {
parser = new DocumentParser();
}
catch (const VXIException::OutOfMemory &) {
parser = NULL;
throw;
}
try {
pm = new PromptManager();
}
catch (...) {
delete parser;
parser = NULL;
pm = NULL;
throw;
}
if (pm == NULL) {
delete parser;
parser = NULL;
throw VXIException::OutOfMemory();
}
}
VXI::~VXI()
{
while (exe != NULL) {
ExecutionContext * temp = exe->next;
delete exe;
exe = temp;
}
delete pm;
delete parser;
}
// Determine if the user has already hung-up
// if it is the case, throw the exit element to indicate
// end of call
void VXI::CheckLineStatus()
{
VXItelStatus status;
int telResult = tel->GetStatus(tel, &status);
bool needToThrow = false;
if (telResult != VXItel_RESULT_SUCCESS) {
needToThrow = true;
log->LogError(201);
}
else if (status == VXItel_STATUS_INACTIVE)
needToThrow = true;
if (needToThrow) {
mutex.Lock();
bool alreadyHungup = lineHungUp;
lineHungUp = true;
mutex.Unlock();
if (alreadyHungup) {
log->LogDiagnostic(1, L"VXI::CheckLineStatus - Call has been hung-up, "
L"exiting...");
throw VXIException::Exit(NULL);
}
else
throw VXIException::InterpreterEvent(EV_TELEPHONE_HANGUP);
}
}
bool VXI::SetRuntimeProperty(PropertyID id, const VXIchar * value)
{
mutex.Lock();
switch (id) {
case VXI::BeepURI:
if (value == NULL) uriBeep.erase();
else uriBeep = value;
break;
case VXI::PlatDefaultsURI:
if (value == NULL) uriPlatDefaults.erase();
else uriPlatDefaults = value;
updateDefaultDoc = true;
break;
default:
mutex.Unlock();
return false;
}
mutex.Unlock();
return true;
}
void VXI::GetRuntimeProperty(PropertyID id, vxistring & value) const
{
mutex.Lock();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -