📄 vxi.cpp
字号:
// (1.2.1) Divide raw URI into uri + fragment. exe->properties.GetFetchobjURIs(elem, fetchobj, uri, fragment); // (1.2.2) Handle the degenerate case. if (uri.empty() && fragment.empty()) { log->StartDiagnostic(0) << L"VXI::PerformTransition - invalid URI, \"" << (rawURI.empty() ? L"NULL" : rawURI.c_str()) << L"\""; log->EndDiagnostic(); throw VXIException::InterpreterEvent(EV_ERROR_BADURI); } // (1.2.3) In the fragment only case, just go to the indicated item. if (uri.empty()) { VXMLElement targetElement = FindDialog(elem, fragment); if (targetElement == 0) { log->StartDiagnostic(0) << L"VXI::PerformTransition - non-existent " L"dialog, \"" << (rawURI.empty() ? L"NULL" : rawURI.c_str()) << L"\""; log->EndDiagnostic(); throw VXIException::InterpreterEvent(EV_ERROR_BADDIALOG); } if (!isSubdialog) throw JumpDialog(targetElement); else { #pragma message("CC - temporarily pop the last field properties so that subdialog won't complain") PropertyList subprop(exe->properties); subprop.PopPropertyLevel(FIELD_PROP); vxistring absoluteURI(L""); tempStr = exe->properties.GetProperty(PropertyList::AbsoluteURI); if (tempStr) absoluteURI = tempStr; throw JumpDoc(exe->platDefaults, exe->application, exe->applicationURI, exe->document, absoluteURI, targetElement, isSubdialog, isSubmitElement, subprop); } } #pragma message ("VXI::PerformTransition - ignoring fetchhint") // (1.3) Get remaining fetch properties. At this point, we now need // to assemble seperate fetch properties for fetchaudio, up // until now all the prep work is identical. VXIMapHolder fetchAudioFetchobj(NULL); fetchAudioFetchobj = fetchobj; if (fetchAudioFetchobj.GetValue() == NULL) throw VXIException::OutOfMemory(); exe->properties.GetFetchobjCacheAttrs(elem, PropertyList::Document,fetchobj); exe->properties.GetFetchobjCacheAttrs(elem, PropertyList::Audio, fetchAudioFetchobj); if (submitData.GetValue() != NULL) { if (!exe->properties.GetFetchobjSubmitAttributes(elem, submitData, fetchobj)) { // This should never occur. log->StartDiagnostic(0) << L"VXI::PerformTransition - couldn't set " L"the submit attributes."; log->EndDiagnostic(); throw VXIException::InterpreterEvent(EV_ERROR_BADURI); } submitData.Release(); // This map is now owned by fetchobj. } // (2) Load Document. // (2.1) Start fetch audio. vxistring fetchaudio; if (!elem.GetAttribute(ATTRIBUTE_FETCHAUDIO, fetchaudio)) fetchaudio = toString(exe->properties.GetProperty(L"fetchaudio")); if (!fetchaudio.empty()) { // Get All properties for fetching audio VXIMapHolder fillerProp(VXIMapClone(fetchAudioFetchobj.GetValue())); exe->properties.GetProperties(fillerProp); pm->PlayAll(); // Finish playing already queued prompts pm->PlayFiller(fetchaudio, fillerProp); } // (2.2) Load document and verify that dialog exists. // (2.2.1) Load the VoiceXML document. VXMLDocument document; VXMLElement documentDialog; VXIMapHolder documentFetchProps; AttemptDocumentLoad(uri, fetchobj, document, documentFetchProps); // (2.2.2) If there was a fragment, does the named dialog exist? VXMLElement documentRoot = document.GetRoot(); documentDialog = FindDialog(documentRoot, fragment); if (documentDialog == 0) { if (fragment.empty()) log->StartDiagnostic(0) << L"VXI::PerformTransition - no dialog " L"element found in \"" << uri << L"\""; else log->StartDiagnostic(0) << L"VXI::PerformTransition - named dialog, " << fragment << L" not found in \"" << uri << L"\""; log->EndDiagnostic(); throw VXIException::InterpreterEvent(EV_ERROR_BADDIALOG); } // (3) Get Document language & find associated defaults. // (3.1) Create a new property list containing the document properties. PropertyList newProperties(*log); #pragma message("JC: This should set from * then override with specific") #pragma message("JC: Make sure this returns the specific (if present) at the end") // WARNING: The defaults document has multiple languages and a language-independent '*' group. // This should really read the '*' group and then overlay the set specific to the active language. // (3.2) Extract the language setting. const VXIchar * language = newProperties.GetProperty(PropertyList::Language); if (language == NULL) language = GENERIC_DEFAULTS; // (3.3) Find the language defaults. VXMLElement defaults; VXMLElement defaultsRoot = domDefaultDoc.GetRoot(); for (VXMLNodeIterator it(defaultsRoot); it; ++it) { VXMLNode child = *it; // Look for a language node. if (child.GetType() != VXMLNode::Type_VXMLElement) continue; const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(child); if (elem.GetName() != DEFAULTS_LANGUAGE) continue; vxistring id; elem.GetAttribute(ATTRIBUTE_ID, id); if (id == language || (id == GENERIC_DEFAULTS && defaults == 0)) defaults = elem; } if (defaults != 0) newProperties.SetProperties(defaults, DEFAULTS_PROP, VXIMapHolder(NULL)); newProperties.SetProperties(documentRoot, DOC_PROP, documentFetchProps); // newProperties should now contain the properties from the platform defaults plus // the properties at document level. // (3.4) Copy the document properties in and find the absolute URI. vxistring absoluteURI(L""); vxistring applicationURI(L""); newProperties.SetProperties(documentRoot, DOC_PROP, documentFetchProps); tempStr = newProperties.GetProperty(PropertyList::AbsoluteURI, DOC_PROP); if (tempStr == NULL) absoluteURI = uri.empty() ? L"" : uri.c_str(); else absoluteURI = tempStr; // (4) Load the application. VXMLDocument application; VXIMapHolder appProperties; // (4.1) Get the application URI. vxistring appuri; documentRoot.GetAttribute(ATTRIBUTE_APPLICATION, appuri); if (!appuri.empty()) { // (4.2) Initialize application fetch parameters. VXIMapHolder appFetchobj; if (appFetchobj.GetValue() == NULL) throw VXIException::OutOfMemory(); vxistring appFragment; newProperties.GetFetchobjURIs(documentRoot, appFetchobj, appuri, appFragment); if (appuri.empty()) { log->LogError(214); throw VXIException::InterpreterEvent(EV_ERROR_APP_BADURI); } newProperties.GetFetchobjCacheAttrs(documentRoot, PropertyList::Document, appFetchobj); // (4.3) Load the application and its properties (we must then restore the // document properties. AttemptDocumentLoad(appuri, appFetchobj, application, appProperties); // (4.3.1) If an application root document specifies an application root // element error.semantic is thrown. VXMLElement documentRootCheck = application.GetRoot(); vxistring appuriCheck; documentRootCheck.GetAttribute(ATTRIBUTE_APPLICATION, appuriCheck); if (!appuriCheck.empty()) throw VXIException::InterpreterEvent(EV_ERROR_SEMANTIC, L"application root element presents in application root document"); newProperties.SetProperties(application.GetRoot(), APP_PROP, appProperties); // (4.4) Get the absolute URI for the application root. tempStr = newProperties.GetProperty(PropertyList::AbsoluteURI, APP_PROP); applicationURI = (tempStr == NULL ? L"" : tempStr); } // (5) Generate the final event. throw JumpDoc(defaults, application, applicationURI, document, absoluteURI, documentDialog, isSubdialog, isSubmitElement, newProperties); } // Finds the named dialog in the document. If the name is empty, the first // item is returned. // VXMLElement VXI::FindDialog(const VXMLElement & start, const vxistring & name) { if (log->IsLogging(2)) { log->StartDiagnostic(2) << L"VXI::FindDialog(" << name << L")"; log->EndDiagnostic(); } // (0) find the root node. VXMLElement doc; for (doc = start; doc != 0 && doc.GetName() != NODE_VXML; doc = doc.GetParent()); if (doc == 0) return VXMLElement(); // (1) Walk through all elements at this level and find match. for (VXMLNodeIterator it(doc); it; ++it) { VXMLNode child = *it; // (1.1) Only <form> & <menu> elements are considered. if (child.GetType() != VXMLNode::Type_VXMLElement) continue; const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(child); VXMLElementType nodeName = elem.GetName(); if (nodeName != NODE_FORM && nodeName != NODE_MENU) continue; // (1.2) If no dialog was specified, return the first one. if (name.empty()) return elem; // (1.3) Otherwise, look for an exact match. vxistring id; if (!elem.GetAttribute(ATTRIBUTE__ITEMNAME, id)) continue; if (name == id) return elem; } // (2) User attempted to GOTO to non-existant dialog or have an empty doc! log->LogDiagnostic(2, L"VXI::FindDialog - no match found."); return VXMLElement(); } //############################################################################# // Document Loop //############################################################################# // return success/failure (can't throw error here as caller needs // a chance to clean up // Also initialize new context (session scope) bool VXI::PushExecutionContext(const vxistring & sessionScript) { log->LogDiagnostic(2, L"VXI::PushExecutionContext()"); // (1) Catch recursive <subdialog> case... if (stackDepth >= DEFAULT_MAX_EXE_STACK_DEPTH) { log->LogError(211); return false; } // (2) Create new execution context. ExecutionContext * ep = new ExecutionContext(rec, jsi, *log, exe); if (ep == NULL) throw VXIException::OutOfMemory(); exe = ep; ++stackDepth; // (3) Init new context from channel (i.e. set up 'session' scope) exe->script.PushScope(SCOPE_Session); if (!sessionScript.empty()) exe->script.EvalScript(sessionScript); exe->script.SetVarReadOnly(SCOPE_Session); log->LogDiagnostic(2, L"VXI::PushExecutionContext - session variables " L"initialized"); // (4) Init new context defaults (i.e. set up platform defaults) // (4.1) Find generic language properties. VXMLElement defaultsRoot = domDefaultDoc.GetRoot(); for (VXMLNodeIterator it(defaultsRoot); it; ++it) { VXMLNode child = *it; if (child.GetType() != VXMLNode::Type_VXMLElement) continue; const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(child); if (elem.GetName() != DEFAULTS_LANGUAGE) continue; vxistring id; elem.GetAttribute(ATTRIBUTE_ID, id); if (id != GENERIC_DEFAULTS) continue; exe->platDefaults = elem; break; } if (exe->platDefaults == 0) { log->LogError(223); PopExecutionContext(); return false; } // (4.2) Install defaults. We only need to worry about the properties (for // document load) and the ECMA variables and scripts (for catch handlers on // load failure). The grammars & prompts may be safely ignored. exe->properties.SetProperties(exe->platDefaults, DEFAULTS_PROP, VXIMapHolder()); exe->script.PushScope(SCOPE_Defaults); ProcessRootScripts(exe->platDefaults); log->LogDiagnostic(2, L"VXI::PushExecutionContext - platform defaults " L"initialized"); return true; } void VXI::PopExecutionContext() { if (exe == NULL) return; ExecutionContext * current = exe; exe = current->next; --stackDepth; delete current; } void VXI::AttemptDocumentLoad(const vxistring & uri, const VXIMapHolder & uriProperties, VXMLDocument & doc, VXIMapHolder & docProperties, bool isDefaults) { // (1) Create map to store document properties. if (docProperties.GetValue() == NULL) throw VXIException::OutOfMemory(); // (2) Fetch the document VXIbyte *cbuffer = NULL; VXIulong bufferSize = 0; int result = parser->FetchDocument(uri.c_str(), uriProperties, inet, cache, *log, doc, docProperties, isDefaults, &cbuffer, &bufferSize); // If we didn't have a parse error, dump the VoiceXML document if // configured to do so, otherwise free the content buffer if ((result != 4) && (cbuffer)) { VXIString *key = NULL, *value = NULL; if ((log->IsLogging(SimpleLogger::DOC_DUMPS)) && (log->LogContent(VXI_MIME_XML, cbuffer, bufferSize, &key, &value))) { vxistring diagUri(uri); const VXIValue * val = VXIMapGetProperty(docProperties.GetValue(), INET_INFO_ABSOLUTE_NAME); if (val != NULL && VXIValueGetType(val) == VALUE_STRING) diagUri = VXIStringCStr(reinterpret_cast<const VXIString *>(val)); vxistring temp(L"URL"); temp += L": "; temp += diagUri.c_str(); temp += L", "; temp += VXIStringCStr(key); temp += L": "; temp += VXIStringCStr(value); log->LogDiagnostic(SimpleLogger::DOC_DUMPS, temp.c_str()); } delete [] cbuffer; cbuffer = NULL; if (key) VXIStringDestroy(&key); if (value) VXIStringDestroy(&value); } // (3) Handle error conditions. switch (result) { case -1: // Out of memory throw VXIException::OutOfMemory(); case 0: // Success break; case 1: // Invalid parameter case 2: // Unable to open URI log->LogError(203); // now look at the http status code to throw the // compiliant error.badfetch.http.<response code> if (docProperties.GetValue()) { // retrieve response code VXIint iv = 0; const VXIValue *v = VXIMapGetProperty(docProperties.GetValue(), INET_INFO_HTTP_STATUS); if( v && VXIValueGetType(v) == VALUE_INTEGER && ((iv = VXIIntegerValue(reinterpret_cast<const VXIInteger *>(v))) > 0) ) { std::basic_stringstream<VXIchar> respStream; respStream << EV_ERROR_BADFETCH << L".http."; respStream << iv; throw VXIException::InterpreterEvent(respStream.str().c_str()); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -