Example #1
0
static VXIbool VXIrecSupportsHotwordTransfer(
  struct VXIrecInterface * pThis,
  const VXIMap  * properties,
  const VXIchar * transferDest)
{
  VXIbool result = FALSE;

  // this is really just to demonstrate how the platform could
  // support hotword for some type of transfers, but not others.
  // this could just as easily been based on other properties of
  // the transfer. i.e., destination type, required line type, etc...
  const VXIValue* dval = VXIMapGetProperty(properties, TEL_TRANSFER_TYPE);
  if( dval && VXIValueGetType(dval) == VALUE_STRING ){
    const wchar_t* hid = VXIStringCStr(reinterpret_cast<const VXIString *>(dval));
	if (wcscmp(hid, L"consultation") == 0)
      return FALSE;
  }

  dval = VXIMapGetProperty(properties, L"SupportsHotwordTransfer");
  if( dval && VXIValueGetType(dval) == VALUE_STRING ){
    const wchar_t* hid = VXIStringCStr(reinterpret_cast<const VXIString *>(dval));
	result = (wcscmp(hid, L"true") == 0) ? TRUE : FALSE;
  }

  return result;
}
Example #2
0
// Begin a session
//
   static 
VXItelResult OSBtelBeginSession(VXItelInterface * pThis, VXIMap *sessionArgs)
{
   OSBtelImpl *impl = ToOSBtelImpl(pThis);
   impl->live = -1; // not quite live yet, other threads shouldn't its access resources

   Diag(impl, DIAG_TAG_SIGNALING, NULL, L"tel BeginSession");
   const VXIchar *callId = NULL;
   const VXIValue *val;
   val = VXIMapGetProperty(sessionArgs, L"callid");

   impl->pExitGuard = new OsBSem(OsBSem::Q_PRIORITY, OsBSem::FULL);
   impl->transferred = 0;
   impl->callId = NULL;
   if ((val) && (VXIValueGetType(val) == VALUE_STRING))
   {
      callId = VXIStringCStr((const VXIString *) val);
      int len = strlen((char*)callId) + 1;

      VXIchar *vxiCallid = (VXIchar *) calloc(len, sizeof(VXIchar));
      if (vxiCallid)
      {
         strncpy((char*)vxiCallid, (char*)callId, len);
         impl->callId = vxiCallid;
      }
      else
         return VXItel_RESULT_OUT_OF_MEMORY;
   }
   else
      return VXItel_RESULT_INVALID_ARGUMENT;


   impl->live = 1; // live
   return VXItel_RESULT_SUCCESS;
}
Example #3
0
/**
 * Sample object setting the defaults document for subsequent calls
 *
 * @param properties    [IN]  See description in VXIobjectExecute() 
 *                            or VXIobjectValidate()
 * @param parameters    [IN]  See description in VXIobjectExecute() 
 *                            or VXIobjectValidate()
 * @param execute       [IN]  Specifies whether the object should be
 *                            executed (true) or simply validated (false)
 * @param result        [OUT] See description in VXIobjectExecute() 
 *                            or VXIobjectValidate()
 *
 * @result VXIobj_RESULT_SUCCESS on success
 */
static VXIobjResult 
ProcessComSpeechworksSetDefaultsObject (struct VXIobjectInterface *pThis,
					const VXIMap              *properties,
					const VXIMap              *parameters,
					VXIbool                    execute,
					VXIValue                 **result)
{
  static const wchar_t func[] = L"ProcessComSpeechworksSetDefaults";
  GET_VXIOBJECT (pThis, sbObject, log, rc);

  if((execute) && (result == NULL)) return VXIobj_RESULT_INVALID_ARGUMENT;
  if((! properties) || (! parameters)) return VXIobj_RESULT_INVALID_ARGUMENT;

  if(execute) {

    const VXIchar *defaults = NULL;

    const VXIValue *val = VXIMapGetProperty(parameters, L"defaults");
    if (! val) {
      Error(log, 202, L"%s%s", L"parameter", L"defaults");
      return VXIobj_RESULT_INVALID_PROP_VALUE;
    } else if (VXIValueGetType(val) != VALUE_STRING) {
      Error(log, 203, L"%s%s%s%d", L"parameter", L"defaults", 
	    L"type", VXIValueGetType(val));
      return VXIobj_RESULT_INVALID_PROP_VALUE;
    }
    defaults = VXIStringCStr(reinterpret_cast<const VXIString *>(val));
    if (! defaults[0]) {
      Error(log, 204, L"%s%s%s%s", L"parameter", L"defaults", L"value", defaults);
      return VXIobj_RESULT_INVALID_PROP_VALUE;
    }

    
    // Hack to set the defaults document
    VXIobjectAPI *objectAPI = (VXIobjectAPI *) pThis;
    if ( ! objectAPI ) { rc = VXIobj_RESULT_INVALID_ARGUMENT; return rc; }
    VXIplatform *plat = objectAPI->resources->platform;
    VXIMap *vxiProperties = VXIMapCreate();
    VXIString * valstr = VXIStringCreate(defaults);
    VXIMapSetProperty(vxiProperties, VXI_PLATFORM_DEFAULTS, (VXIValue *) valstr);
    plat->VXIinterpreter->SetProperties(plat->VXIinterpreter,
					vxiProperties);

    // Create the result object
    VXIMap *resultObj = VXIMapCreate();
    if(resultObj == NULL) {
      Error(log, 100, NULL);
      return VXIobj_RESULT_OUT_OF_MEMORY;
    }
    *result = reinterpret_cast<VXIValue *>(resultObj);

    // Set the result object's status field to 'success'
    VXIMapSetProperty(resultObj, L"status",
		      reinterpret_cast<VXIValue *>(VXIStringCreate(L"success")));
  }

  return VXIobj_RESULT_SUCCESS;
}
Example #4
0
static VXIrecResult VXIrecHotwordTransfer
(
  struct VXIrecInterface * pThis,
  struct VXItelInterface * tel,
  const VXIMap *properties,
  const VXIchar* transferDest,
  VXIrecTransferResult  ** transferResult
)
{
  const wchar_t* fnname = L"VXIrecHotwordTransfer";
  VXIrecData* tp = GetRecData(pThis);
  if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT;
  LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE);
  
  VXIrecResult res = VXIrec_RESULT_SUCCESS;

  // this is probably not how it would be done in real life...but for this
  // sample app it will suffice:
  // Do the transfer
  int activeGrammars = tp->GetActiveCount();

  VXIMap *xferResp = NULL;
  VXItelResult xferResult = tel->TransferBridge(tel, properties, transferDest, &xferResp);
  if (xferResult != VXItel_RESULT_SUCCESS) {
    res = VXIrec_RESULT_FAILURE;
  }
  else if (activeGrammars == 0) {
    *transferResult = new VXIrecTransferResult();
    (*transferResult)->Destroy = TransferResultDestroy;
    (*transferResult)->utterance = NULL;
    (*transferResult)->markname = NULL;
    (*transferResult)->marktime = 0;
    (*transferResult)->xmlresult = NULL;

    const VXIValue * v = VXIMapGetProperty(xferResp, TEL_TRANSFER_DURATION);
    if (v != NULL && VXIValueGetType(v) == VALUE_INTEGER)
      (*transferResult)->duration = VXIIntegerValue(reinterpret_cast<const VXIInteger*>(v));

    v = VXIMapGetProperty(xferResp, TEL_TRANSFER_STATUS);
    if (v != NULL && VXIValueGetType(v) == VALUE_INTEGER) {
      long temp = VXIIntegerValue(reinterpret_cast<const VXIInteger *>(v));
      (*transferResult)->status = VXItelTransferStatus(temp);
    }

	VXIMapDestroy(&xferResp);
  }
  else {
    // get input from the user.
    VXIrecRecognitionResult *recResult = NULL;
    VXIrecResult localRes = pThis->Recognize(pThis, properties, &recResult);
	if (localRes == VXIrec_RESULT_SUCCESS){
      *transferResult = new VXIrecTransferResult();
	  if ((*transferResult) == NULL) {
        recResult->Destroy(&recResult);
        VXIMapDestroy(&xferResp);
        return VXIrec_RESULT_OUT_OF_MEMORY;
	  }

      // setup the transfer result by first copying the 
	  // RecResult.
      (*transferResult)->Destroy = TransferResultDestroy;
      (*transferResult)->utterance = recResult->utterance;
      (*transferResult)->markname = recResult->markname;
	  (*transferResult)->marktime = recResult->marktime;
      (*transferResult)->xmlresult = recResult->xmlresult;
	  (*transferResult)->duration = 0;
	  (*transferResult)->status = VXItel_TRANSFER_FAR_END_DISCONNECT;

      // we no long need the rec result (but we don't want the VXIContent
	  // fields destroyed).
	  recResult->utterance = NULL;
	  recResult->xmlresult = NULL;
	  recResult->Destroy(&recResult);

      // translate the status and duration to the transfer result fields.
	  // since this code is simply so that Hotword transfers work, any
	  // valid recognition (ignoring noinput and nomatch) will set the
	  // transfer to "near_end_disconnect".  Otherwise, we pretend that
	  // the other end terminated the transfer.
	  if((*transferResult)->xmlresult){
	    // we're going to ignore noinput and nomatch results.
        const VXIchar * contentType;
        const VXIbyte * content;
        VXIulong contentSize = 0; 
        VXIContentValue((*transferResult)->xmlresult, &contentType, &content, &contentSize);

	    // we're going to ignore noinput and nomatch results.
        if (   !wcsstr((VXIchar*)content, L"<noinput/>")
			&& !wcsstr((VXIchar*)content, L"<nomatch/>")){
          (*transferResult)->status = VXItel_TRANSFER_NEAR_END_DISCONNECT;
        }
      }

	  const VXIValue * v = VXIMapGetProperty(xferResp, TEL_TRANSFER_DURATION);
	  if (v != NULL && VXIValueGetType(v) == VALUE_INTEGER)
	    (*transferResult)->duration = VXIIntegerValue(reinterpret_cast<const VXIInteger*>(v));

	  VXIMapDestroy(&xferResp);
	}
  }

  return res; 
}
Example #5
0
static VXIrecResult VXIrecRecognize(VXIrecInterface *pThis,
                                    const VXIMap *properties,
                                    VXIrecRecognitionResult **recogResult)
{
  const wchar_t* fnname = L"VXIrecRecognize";
  VXIrecData* tp = GetRecData(pThis);
  if (tp == NULL) return VXIrec_RESULT_INVALID_ARGUMENT;
  LogBlock logger(tp->GetLog(), gblDiagLogBase, fnname, VXIREC_MODULE);

  VXIchar* input = NULL;
  VXIMap*  res  = NULL;
  VXIchar* str  = NULL;
  VXIchar console[512];
  bool recordUtterance = false;
  bool haveUtterance = true;

  //  DEBUG
  if (voiceglue_loglevel() >= LOG_DEBUG)
  {
      std::ostringstream logstring;
      logstring << "VXIrecRecognize called with properties "
		<< VXIValue_to_Std_String ((const VXIValue *) properties);
      voiceglue_log ((char) LOG_DEBUG, logstring);
  };

  if (properties != NULL) {
    const VXIValue * ru = VXIMapGetProperty(properties, REC_RECORDUTTERANCE);
    if (ru)
      recordUtterance = wcscmp(VXIStringCStr((const VXIString*)ru), L"true") == 0;
    /*  Ignore force-feed input option
    const VXIValue * val = VXIMapGetProperty(properties, L"SpeechInput");
    if( val ) {
       logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%s", L"SpeechInput: ",
                      VXIStringCStr((const VXIString*)val));
    }
    if (val == NULL || VXIValueGetType(val) != VALUE_STRING) {
      val = VXIMapGetProperty(properties, L"DTMFInput");
      if( val ) {
        logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%s", L"DTMFInput: ",
                       VXIStringCStr((const VXIString*)val));      
      }
    }
    VXIString* vect = (VXIString*) val;
    if (vect != NULL) input = (VXIchar*) VXIStringCStr(vect);
    */

    /*  Ignore console input option
    if (input && wcscmp(input, L"-") == 0) {
      unsigned int i;
      VXIchar* cp = console;
      char lbuf[512];
      printf("Console: ");
      fgets(lbuf, 511, stdin);
      // copy to VXIchar
      for(i = 0; i < strlen(lbuf); ++i) {
        if (lbuf[i] == '\r' || lbuf[i] == '\n') continue;
        *cp++ = lbuf[i] & 0x7f;
      }
      *cp++ = 0;
      input = console;
      logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%s", L"Input: ", 
                     (input ? input : L"NULL"));
    }
    */
  }

  //  Get NLSML recognition result from perl in nlsmlresult
  vxistring nlsmlresult;
  VXIrecResult rec_res;
  rec_res = voiceglue_recognize (properties, nlsmlresult);
  if (rec_res != VXIrec_RESULT_SUCCESS)
  {
      return (rec_res);
  };

  // Create a new results structure.
  const unsigned int CHARSIZE = sizeof(VXIchar) / sizeof(VXIbyte);
  VXIContent * xmlresult = NULL;

    logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%s", L"NLSML_RESULT: ", 
                   nlsmlresult.c_str());
    
    unsigned int BUFFERSIZE = (nlsmlresult.length() + 1) * CHARSIZE;
    VXIbyte * buffer = new VXIbyte[BUFFERSIZE];
    if (buffer == NULL) return VXIrec_RESULT_OUT_OF_MEMORY;
    memcpy(buffer, nlsmlresult.c_str(), BUFFERSIZE);

    xmlresult = VXIContentCreate(VXIREC_MIMETYPE_XMLRESULT,
                                 buffer, BUFFERSIZE,
                                 DestroyNLSMLBuffer, buffer);

    if (xmlresult == NULL) {
      delete [] buffer;
      return VXIrec_RESULT_OUT_OF_MEMORY;
    }

  VXIrecRecognitionResult * result = new VXIrecRecognitionResult();
  if (result == NULL) {
    VXIContentDestroy(&xmlresult);
    return VXIrec_RESULT_OUT_OF_MEMORY;
  }

  result->Destroy = RecognitionResultDestroy;
  result->markname = NULL;
  result->marktime = 0;
  result->xmlresult = xmlresult;

  if (!haveUtterance ||!recordUtterance) {
    result->utterance = NULL;
    result->utteranceDuration = 0;
  }
  else {
    result->utteranceDuration = 5000; // 5sec
    unsigned int waveformSizeBytes = (result->utteranceDuration / 1000 ) * 8000 * sizeof(unsigned char);
    unsigned char * c_waveform = new unsigned char[waveformSizeBytes];
    if (c_waveform == NULL) {
      result->utterance = NULL;
      result->utteranceDuration = 0;
    }
    else {
      for (unsigned int i = 0; i < waveformSizeBytes; ++i)
        c_waveform[i] = i & 0x00ff;

      result->utterance = VXIContentCreate(VXIREC_MIMETYPE_ULAW,
                                           c_waveform, waveformSizeBytes,
                                           ResultContentDestroy, NULL);  
    }
  }

  *recogResult = result;

  return VXIrec_RESULT_SUCCESS;
}
Example #6
0
/**
 * Bridging Transfer.
 *
 */
static
VXItelResult OSBtelTransferBridge(VXItelInterface * vxip, 
      const VXIMap * prop,
      const VXIchar * transferDestination,
      const VXIMap * data,
      VXIMap **resp)
{
   OSBtelImpl *impl = ToOSBtelImpl(vxip);
   Diag(impl, DIAG_TAG_SIGNALING, NULL, L"TransferBridge: %s", 
         transferDestination);

   *resp = VXIMapCreate();

   VXIchar* dest = 0;
   VXIchar* xaudio = 0;
   if (prop != NULL) {
      VXIString* vect =(VXIString*)VXIMapGetProperty(prop, L"Destination");
      if (vect != NULL) 
         dest = (VXIchar*) VXIStringCStr(vect);

      vect =(VXIString*)VXIMapGetProperty(prop, TEL_TRANSFER_AUDIO);
      if (vect != NULL) 
         xaudio = (VXIchar*) VXIStringCStr(vect);
   }

   *resp = VXIMapCreate();
   if (impl->callId && transferDestination)
   {
      vxistring dest = transferDestination;
      if (! dest.empty()) 
      {
         char* str = 0;
         int len = dest.length() + 1;
         if (len > 0)
         {
            str = new char [len + 1];
            wcstombs(str, transferDestination, len);
            str[len] = 0;
         }

         if (str)
         {
            UtlString from(str);
            HttpMessage::unescape( from );

            if (impl->live == 1)
            {
                impl->pCallMgr->connect((char*)impl->callId, from.data()); 

                impl->transferred = 0;
                int state = 0;
                int status = VXItel_TRANSFER_UNKNOWN;
                int duration = 0;
                OsTime   startTime;
                OsTime   endTime;
                OsDateTimeBase::getCurTime(startTime);

                VXItelResult ret;
                do 
                {
                        ret = setTransferState(impl, prop, transferDestination, resp, &state, &status);
                }
                while (state != PtEvent::CONNECTION_DISCONNECTED &&
                          state != PtEvent::CONNECTION_FAILED &&
                          ret != VXItel_RESULT_TIMEOUT);

                OsDateTimeBase::getCurTime(endTime);
                duration = (endTime.cvtToMsecs() - startTime.cvtToMsecs())/1000;
                VXIMapSetProperty(*resp, TEL_TRANSFER_STATUS, (VXIValue *) VXIIntegerCreate(status));
                VXIMapSetProperty(*resp, TEL_TRANSFER_DURATION, (VXIValue *)VXIIntegerCreate(duration));
            }
            else
            {
                Diag(impl, DIAG_TAG_SIGNALING, NULL, L"Exiting called, live=%d, cancel TransferBridge: %s",
                        impl->live, transferDestination);
            }
         }
      }
   }

   return VXItel_RESULT_SUCCESS;
}
Example #7
0
/**
 * Blind Transfer.
 */
static
VXItelResult OSBtelTransferBlind(VXItelInterface * vxip, 
      const VXIMap * prop,
      const VXIchar * transferDestination,
      const VXIMap * data,
      VXIMap ** resp)
{
   OSBtelImpl *impl = ToOSBtelImpl(vxip);
   Diag(impl, DIAG_TAG_SIGNALING, NULL, L"TransferBlind: %s", 
         transferDestination);

   VXIchar* best = (VXIchar *) calloc(128, sizeof(VXIchar));
   if (prop != NULL) {
      VXIString* vect =(VXIString*)VXIMapGetProperty(prop, L"Destination");
      if (vect != NULL) best = (VXIchar*) VXIStringCStr(vect);
   }

   *resp = VXIMapCreate();
   if (impl->callId && transferDestination)
   {
      vxistring dest = transferDestination;
      if (! dest.empty()) 
      {
         char* str = 0;
         int len = dest.length() + 1;
         if (len > 0)
         {
            str = new char [len + 1];
            wcstombs(str, transferDestination, len);
            str[len] = 0;
         }

         if (str)
         {
            UtlString from(str);
            HttpMessage::unescape( from );
            OsSysLog::add(FAC_MEDIASERVER_VXI, PRI_DEBUG, "OSBtelTransferBlind from = '%s'", from.data());
            if (impl->live == 1) 
            {
                if (PT_SUCCESS == impl->pCallMgr->transfer_blind((char*)impl->callId,
                                                                 from.data(), // to url
                                                                 0, // target call id
                                                                 0, // target connect addr
                                                                 false // no remote hold first
                                                                 )
                    )
                {
                        impl->transferred = 0;
                        int state = 0;
                        int status = VXItel_TRANSFER_UNKNOWN;
                        int duration = 0;
                        OsTime   startTime;
                        OsTime   endTime;
                        OsDateTimeBase::getCurTime(startTime);

                        setTransferState(impl, prop, transferDestination, resp, &state, &status);

                        OsDateTimeBase::getCurTime(endTime);
                        duration = (endTime.cvtToMsecs() - startTime.cvtToMsecs())/1000;
                        VXIMapSetProperty(*resp, TEL_TRANSFER_STATUS, (VXIValue *) VXIIntegerCreate(status));
                        VXIMapSetProperty(*resp, TEL_TRANSFER_DURATION, (VXIValue *)VXIIntegerCreate(duration));
                }
            }
            else
            {
                Diag(impl, DIAG_TAG_SIGNALING, NULL, L"Exiting called, live=%d, cancel TransferBlind: %s", 
                        impl->live, transferDestination);
            }
         }
      }
   }

   return VXItel_RESULT_SUCCESS;
}
Example #8
0
/**
 * Validate an object, performing validity checks without execution
 *
 * @param properties  [IN] Map containing properties and attributes for
 *                      the <object> as specified in the VoiceXML
 *                      specification except that "expr" and "cond" are
 *                      always omitted (are handled by the interpreter).
 * @param parameters  [IN] Map containing parameters for the <object> as
 *                      specified by the VoiceXML <param> tag. The keys
 *                      of the map correspond to the parameter name ("name"
 *                      attribute) while the value of each key corresponds
 *                      to a VXIValue based type. See Execute( ) above 
 *                      for details.
 *
 * @return        VXIobj_RESULT_SUCCESS on success,
 *                VXIobj_RESULT_NON_FATAL_ERROR on error, 
 *                VXIobj_RESULT_UNSUPPORTED for unsupported object types
 *                 (this will cause interpreter to throw the correct event)
 */
static
VXIobjResult VXIobjectValidate(struct VXIobjectInterface *pThis,
                               const VXIMap              *properties,
                               const VXIMap              *parameters)
{
  static const wchar_t func[] = L"VXIobjectValidate";
  GET_VXIOBJECT (pThis, sbObject, log, rc);
  Diag (log, LOG_API, func, L"entering: 0x%p, 0x%p, 0x%p", 
  pThis, properties, parameters);

  if(properties == NULL) {
    Error (log, 201, NULL);
    return VXIobj_RESULT_INVALID_ARGUMENT;
  }

  // Get the name of the object to execute
  const VXIValue *val = VXIMapGetProperty(properties, OBJECT_CLASS_ID);
  if(val == NULL) {
    Error(log, 202, L"%s%s", L"parameter", OBJECT_CLASS_ID);
    return VXIobj_RESULT_INVALID_PROP_VALUE;
  } else if (VXIValueGetType(val) != VALUE_STRING) {
    Error(log, 203, L"%s%s%s%d", L"parameter", OBJECT_CLASS_ID,
    L"type", VXIValueGetType(val));
    return VXIobj_RESULT_INVALID_PROP_VALUE;
  }
  const VXIchar *classID = VXIStringCStr((VXIString *)val);

  // Handle the object
  if (::wcscmp(classID, L"com.vocalocity.diag") == 0) {
    //
    // Sample diagnostic logging object
    // 
    rc = ProcessComSpeechworksDiagObject(pThis, properties, parameters, false,
           NULL);
    if(rc != VXIobj_RESULT_SUCCESS) rc = VXIobj_RESULT_NON_FATAL_ERROR;
  }
  else if (::wcscmp(classID, L"com.vocalocity.echo") == 0) {
    //
    // Sample object echoing back all attributes and parameters
    // 
    rc = ProcessComSpeechworksEchoObject(pThis, properties, parameters, false,
           NULL);
    if(rc != VXIobj_RESULT_SUCCESS) rc = VXIobj_RESULT_NON_FATAL_ERROR;
  } 
  else if (::wcscmp(classID, L"com.vocalocity.saveRecording") == 0) {
    //
    // Sample object that saves a recording to a file
    // 
    rc = ProcessComSpeechworksSaveRecordingObject(pThis, properties, 
              parameters, false, NULL);
    if(rc != VXIobj_RESULT_SUCCESS) rc = VXIobj_RESULT_NON_FATAL_ERROR;
  } 
  else if (::wcscmp(classID, L"com.vocalocity.setDefaults") == 0) {
    //
    // Sample object that sets the defaults document for subsequent
    // calls. This is really a hack and not recommended. This was
    // done more for fun than any value.
    // 
    rc = ProcessComSpeechworksSetDefaultsObject(pThis, properties, 
              parameters, false, NULL);
    if(rc != VXIobj_RESULT_SUCCESS) rc = VXIobj_RESULT_NON_FATAL_ERROR;
  } 
  else {
    //
    // Unsupported object
    //
    rc = VXIobj_RESULT_UNSUPPORTED;
  }

  Diag (log, LOG_API, func, L"exiting: returned %d", rc);
  return rc;
}
Example #9
0
/**
 * Sample object to save a recording to a file
 *
 * @param properties    [IN]  See description in VXIobjectExecute() 
 *                            or VXIobjectValidate()
 * @param parameters    [IN]  See description in VXIobjectExecute() 
 *                            or VXIobjectValidate()
 * @param execute       [IN]  Specifies whether the object should be
 *                            executed (true) or simply validated (false)
 * @param result        [OUT] See description in VXIobjectExecute() 
 *                            or VXIobjectValidate()
 *
 * @result VXIobj_RESULT_SUCCESS on success
 */
static VXIobjResult 
ProcessComSpeechworksSaveRecordingObject (struct VXIobjectInterface *pThis,
            const VXIMap             *properties,
            const VXIMap             *parameters,
            VXIbool                    execute,
            VXIValue                 **result)
{
  static const wchar_t func[] = L"ProcessComSpeechworksSaveRecordingObject";
  GET_VXIOBJECT (pThis, sbObject, log, rc);

  if((execute) && (result == NULL)) return VXIobj_RESULT_INVALID_ARGUMENT;
  if((! properties) || (! parameters)) return VXIobj_RESULT_INVALID_ARGUMENT;

  // Get the recording, MIME type, size, and destination path
  const VXIbyte *recording = NULL;
  const VXIchar *type = NULL, *dest = NULL;
  VXIulong size = 0;
  const VXIValue *val = VXIMapGetProperty(parameters, L"recording");
  if (! val) {
    Error(log, 202, L"%s%s", L"parameter", L"recording");
    return VXIobj_RESULT_INVALID_PROP_VALUE;
  } else if (VXIValueGetType(val) != VALUE_CONTENT) {
    Error(log, 203, L"%s%s%s%d", L"parameter", L"recording", 
    L"type", VXIValueGetType(val));
    return VXIobj_RESULT_INVALID_PROP_VALUE;
  }
  if (VXIContentValue(reinterpret_cast<const VXIContent *>(val),
          &type, &recording, &size) != VXIvalue_RESULT_SUCCESS) {
    Error(log, 204, L"%s%s", L"parameter", L"recording");
    return VXIobj_RESULT_INVALID_PROP_VALUE;
  } else if (size < 1) {
    Error(log, 204, L"%s%s%s%d", L"parameter", L"recording.size", 
    L"value", L"size");
    return VXIobj_RESULT_INVALID_PROP_VALUE;
  }
  
  val = VXIMapGetProperty(parameters, L"dest");
  if (! val) {
    Error(log, 202, L"%s%s", L"parameter", L"dest");
    return VXIobj_RESULT_INVALID_PROP_VALUE;
  } else if (VXIValueGetType(val) != VALUE_STRING) {
    Error(log, 203, L"%s%s%s%d", L"parameter", L"dest", 
    L"type", VXIValueGetType(val));
    return VXIobj_RESULT_INVALID_PROP_VALUE;
  }
  dest = VXIStringCStr(reinterpret_cast<const VXIString *>(val));
  if (! dest[0]) {
    Error(log, 204, L"%s%s%s%s", L"parameter", L"dest", L"value", dest);
    return VXIobj_RESULT_INVALID_PROP_VALUE;
  }

  if(execute) {
    // Convert the destination to narrow characters, use an upside
    // down question mark for unsupported Unicode characters
    size_t len = wcslen(dest);
    char *ndest = new char [len + 1];
    if (! ndest) {
      Error(log, 100, NULL);
      return VXIobj_RESULT_OUT_OF_MEMORY;
    }
    for (size_t i = 0; i <= len; i++)
      ndest[i] = (dest[i] & 0xff00 ? '\277' : static_cast<char>(dest[i]));
    
    // Open the destination and save the file
    size_t totWritten = 0;
#ifdef VXIOBJECT_PERMIT_FILE_WRITES
    FILE *fp = fopen(ndest, "wb");
    delete [] ndest;
    if (fp) {
      do {
  size_t w = fwrite(&recording[totWritten], 1, 
        ((size_t) size) - totWritten, fp);
  totWritten += w;
      } while ((totWritten < (size_t) size) && (! ferror(fp)));
      
      fclose(fp);
    } else {
      Error(log, 205, L"%s%s%s%d", L"file", dest, L"errno", errno);
    }
#else
    Error(log, 206, L"%s%s", L"file", dest);
#endif

    // Create the result object
    VXIMap *resultObj = VXIMapCreate();
    if(resultObj == NULL) {
      Error(log, 100, NULL);
      return VXIobj_RESULT_OUT_OF_MEMORY;
    }
    *result = reinterpret_cast<VXIValue *>(resultObj);

    // Set the result object's status field to 'success' or 'failure'
    if (totWritten == (size_t) size)
      VXIMapSetProperty(resultObj, L"status",
               reinterpret_cast<VXIValue *>(VXIStringCreate(L"success")));
    else
      VXIMapSetProperty(resultObj, L"status", 
               reinterpret_cast<VXIValue *>(VXIStringCreate(L"failure")));
  }

  return VXIobj_RESULT_SUCCESS;
}
Example #10
0
/**
 * Sample diagnostic logging object
 *
 * @param properties    [IN]  See description in VXIobjectExecute() 
 *                            or VXIobjectValidate()
 * @param parameters    [IN]  See description in VXIobjectExecute() 
 *                            or VXIobjectValidate()
 * @param execute       [IN]  Specifies whether the object should be
 *                            executed (true) or simply validated (false)
 * @param result        [OUT] See description in VXIobjectExecute() 
 *                            or VXIobjectValidate()
 *
 * @result VXIobj_RESULT_SUCCESS on success
 */
static VXIobjResult 
ProcessComSpeechworksDiagObject (struct VXIobjectInterface *pThis,
                                 const VXIMap              *properties,
                                 const VXIMap              *parameters,
                                 VXIbool                    execute,
         VXIValue                 **result)
{
  static const wchar_t func[] = L"ProcessComSpeechworksDiagObject";
  GET_VXIOBJECT (pThis, sbObject, log, rc);

  if((execute) && (result == NULL)) return VXIobj_RESULT_INVALID_ARGUMENT;
  if((! properties) || (! parameters)) return VXIobj_RESULT_INVALID_ARGUMENT;

  // Get the tag ID
  const VXIValue *val = VXIMapGetProperty(parameters, L"tag");
  if(val == NULL) {
    Error(log, 202, L"%s%s", L"parameter", L"tag");
    return VXIobj_RESULT_INVALID_PROP_VALUE;
  } 
  VXIint tag;
  switch (VXIValueGetType(val)) {
  case VALUE_INTEGER:
    tag = VXIIntegerValue((VXIInteger *)val);
    break;
  case VALUE_STRING: {
    wchar_t *ptr;
    tag = ::wcstol(VXIStringCStr((VXIString *)val), &ptr, 10);
    } break;
  default:
    Error(log, 203, L"%s%s%s%d", L"parameter", L"tag", 
    L"type", VXIValueGetType(val));
    return VXIobj_RESULT_INVALID_PROP_VALUE;
  }

  // Get the message string
  val = VXIMapGetProperty(parameters, L"message");
  if(val == NULL) {
    Error(log, 202, L"%s%s", L"parameter", L"message");
    return VXIobj_RESULT_INVALID_PROP_VALUE;
  }

  // Check whether the message was sent in "data" or "ref" format.
  // If it is "ref", we need to retrieve it in the embedded map.
  const VXIchar *messageStr = NULL;
  switch (VXIValueGetType(val)) {
  case VALUE_MAP: {
    const VXIValue *val2 = VXIMapGetProperty((const VXIMap *)val, 
                                             OBJECT_VALUE);
    if (VXIValueGetType(val2) == VALUE_STRING)
      messageStr = VXIStringCStr((VXIString *)val2);
    } break;
  case VALUE_STRING:
    messageStr = VXIStringCStr((VXIString *)val);
    break;
  default:
    Error(log, 203, L"%s%s%s%d", L"parameter", L"message", 
    L"type", VXIValueGetType(val));
    return VXIobj_RESULT_INVALID_PROP_VALUE;
  }

  if ((! messageStr) || (! messageStr[0])) {
    Error(log, 204, L"%s%s", L"parameter", L"message");
    return VXIobj_RESULT_INVALID_PROP_VALUE;
  }
  
  if(execute) {
    // Print a diagnostic message using the retrieved arguments.
    // To see this message, you must enable client.log.diagTag.xxx
    // in your VXIclient configuration file, where 'xxx' is the 
    // value of client.object.diagLogBase defined in the same file.
    VXIlogResult rc = Diag (log, tag, NULL, messageStr);

    // Create the result object
    VXIMap *resultObj = VXIMapCreate();
    if(resultObj == NULL) {
      Error(log, 100, NULL);
      return VXIobj_RESULT_OUT_OF_MEMORY;
    }
    *result = reinterpret_cast<VXIValue *>(resultObj);

    // Set the result object's status field to 'success' or 'failure'
    if(rc == VXIlog_RESULT_SUCCESS)
      VXIMapSetProperty(resultObj, L"status",
               reinterpret_cast<VXIValue *>(VXIStringCreate(L"success")));
    else
      VXIMapSetProperty(resultObj, L"status", 
               reinterpret_cast<VXIValue *>(VXIStringCreate(L"failure")));
  }

  return VXIobj_RESULT_SUCCESS;
}
Example #11
0
// Open the entry
VXIcacheResult SBcacheEntryDetails::Open(VXIlogInterface       *log,
					 const SBcacheString   &moduleName,
					 const SBcacheKey      &key,
					 const SBcachePath     &path,
					 VXIcacheOpenMode       mode,
					 VXIint32               flags,
					 VXIulong               maxSizeBytes,
					 const VXIMap          *properties,
					 VXIMap                *streamInfo,
					 VXIcacheStream       **stream)
{
  VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  FILE *filePtr = NULL;

  // Lock and copy input data
  switch ( mode ) {
  case CACHE_MODE_WRITE:
    if ( _rwMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) {
      Error (log, 110, L"%s%s", L"mutex", L"cache entry rw mutex, writer");
      rc = VXIcache_RESULT_SYSTEM_ERROR;
    } else {
      // If the open fails due to directory not existing, call
      // path.CreateDirectories( ) to create the dir tree then open
      // again
      if ( ! _invalidated ) {
	filePtr = fopen (path.c_str( ), "wb");
        int retries = 10; // work around possible race condition w/ rmdir
	while ((retries-- > 0) &&
            ( ! filePtr ) &&
            ( path.CreateDirectories( ) == VXIcache_RESULT_SUCCESS ))
	  filePtr = fopen (path.c_str( ), "wb");
      }

      if ( ! filePtr ) {
	if ( _invalidated ) {
	  // Invalidated or another thread attempted an open for write
	  // and failed, we only got here due to a race condition
	  // where we were waiting on the mutex to start our write
	  // before the failure/invalidation happened by the previous
	  // writer
	  rc = VXIcache_RESULT_FAILURE;
	} else {
	  // File open error
	  LogIOError (log, 213, path);
	  rc = VXIcache_RESULT_IO_ERROR;
	}

	_fileExists = false;
	_rwMutex.Unlock( );
      } else {
	_fileExists = true;
	_creationCost = CACHE_CREATION_COST_DEFAULT;
	_flags = flags;
	_sizeBytes = 0;

        // Only set the path and key if they differ
        if (path != _path || key != _key) {
          _path = path;
          _key = key;
        }

	// Load properties
	if ( properties ) {
	  const VXIValue *value =
	    VXIMapGetProperty (properties, CACHE_CREATION_COST);
	  if ( value ) {
	    if ( VXIValueGetType(value) == VALUE_INTEGER )
	      _creationCost = (VXIcacheCreationCost)
		VXIIntegerValue ((const VXIInteger *) value);
	    else
	      Error (log, 301, L"%s%d", L"VXIValueType",
		     VXIValueGetType(value));
	  }
	}
      }
    }
    break;

  case CACHE_MODE_READ:
    if ( _rwMutex.StartRead( ) != VXItrd_RESULT_SUCCESS ) {
      Error (log, 110, L"%s%s", L"mutex", L"cache entry rw mutex, reader");
      rc = VXIcache_RESULT_SYSTEM_ERROR;
    } else {
      if (( _fileExists ) && ( ! _invalidated )) {
	filePtr = fopen (_path.c_str( ), "rb");
	if ( ! filePtr ) {
	  _fileExists = false;
	  LogIOError (log, 214, _path);
	  _rwMutex.EndRead( );
	  rc = VXIcache_RESULT_IO_ERROR;
	}
      } else {
	// Invalidated or another thread attempted an open for write
	// and failed, we only got here due to a race condition where
	// we were waiting on the mutex to start our read before the
	// failure/invalidation happened by the writer
	_rwMutex.EndRead( );
	rc = VXIcache_RESULT_FAILURE;
      }
    }
    break;

  default:
    Error (log, 215, L"%s%d", L"mode", mode);
    rc = VXIcache_RESULT_UNSUPPORTED;
  }

  if ( rc == VXIcache_RESULT_SUCCESS ) {
    // Update the accessed time
    _lastAccessed = time(0);
    if (mode == CACHE_MODE_WRITE)
      _lastModified = _lastAccessed;

    // Return stream information
    if ( streamInfo ) {
      if (( VXIMapSetProperty (streamInfo, CACHE_INFO_LAST_MODIFIED,
			       (VXIValue *) VXIIntegerCreate(_lastModified)) !=
	    VXIvalue_RESULT_SUCCESS ) ||
	  ( VXIMapSetProperty (streamInfo, CACHE_INFO_SIZE_BYTES,
			       (VXIValue *) VXIIntegerCreate (_sizeBytes)) !=
	    VXIvalue_RESULT_SUCCESS )) {
	Error (log, 100, NULL);
	rc = VXIcache_RESULT_OUT_OF_MEMORY;
      }
    }
  }

  // Return the stream
  if ( rc == VXIcache_RESULT_SUCCESS ) {
    SBcacheEntry entry(this);
    *stream = new SBcacheStream (log, GetDiagBase( ), moduleName, key,
				 entry, mode,
				 ((flags & CACHE_FLAG_NONBLOCKING_IO) == 0),
				 maxSizeBytes, filePtr);
    if ( ! *stream ) {
      Error (log, 100, NULL);
      fclose (filePtr);
      Close (log, mode, 0, true);
      rc = VXIcache_RESULT_OUT_OF_MEMORY;
    }
  }

  Diag (log, SBCACHE_ENTRY_TAGID, L"Open", L"%s, %S, 0x%x, 0x%x: rc = %d",
	key.c_str( ), path.c_str( ), mode, flags, rc);
  return rc;
}
Example #12
0
VXIinetResult
SBinetFileStream::Open(VXIint32                  flags,
		       const VXIMap             *properties,
		       VXIMap                   *streamInfo)
{
  VXIinetResult returnValue = VXIinet_RESULT_SUCCESS;

  /*
     Get the flag to determine whether to open local files. Also check
     the validator to see if it contains INET_INFO_VALIDATOR and if it
     does contain the modified time. */
  SBinetValidator validator(GetLog(), GetDiagBase());
  const VXIValue *validatorVal = NULL;
  if (properties)
  {
    const VXIValue *val = VXIMapGetProperty(properties, INET_OPEN_LOCAL_FILE);
    if (val != NULL)
    {
      if (VXIValueGetType(val) == VALUE_INTEGER)
      {
        if (VXIIntegerValue((const VXIInteger *) val) == FALSE)
          returnValue = VXIinet_RESULT_LOCAL_FILE;
      }
      else
      {
        Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetFileStream::Open",
             L"Passed invalid type for INET_OPEN_LOCAL_FILE property");
      }
    }

    // SBinetValidator::Create() logs errors for us
    validatorVal = VXIMapGetProperty(properties, INET_OPEN_IF_MODIFIED);
    if((validatorVal != NULL) &&
       (validator.Create(validatorVal) != VXIinet_RESULT_SUCCESS))
      validatorVal = NULL;
  }

  Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetFileStream::Open",
       _url->getAbsolute( ));

  // Stat the file to make sure it exists and to get the length and
  // last modified time
  VXIStatStruct statInfo;
  if (VXIStat(SBinetNString(_url->getPath()).c_str(), &statInfo) != 0) {
    Error(222, L"%s%s", L"File", _url->getPath());
    return(VXIinet_RESULT_NOT_FOUND);
  }

  _content_length = statInfo.st_size;

  // If there is a conditional open using a validator, see if the
  // validator is still valid (no need to re-read and re-process)
  if (validatorVal)
  {
    if (! validator.isModified(statInfo.st_mtime, statInfo.st_size))
    {
      Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetFileStream::Open",
           L"Validator OK, returning NOT_MODIFIED");
      returnValue = VXIinet_RESULT_NOT_MODIFIED;
    }
    else
    {
      Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetFileStream::Open",
           L"Validator modified, must re-fetch");
    }
  }

  if (returnValue != VXIinet_RESULT_LOCAL_FILE)
  {
    // Use fopen for now. Note: Open support reads for now
    _pFile = ::fopen( SBinetNString(_url->getPath()).c_str(), "rb" );
    if(!_pFile){
      Error(223, L"%s%s", L"File", _url->getPath());
      return(VXIinet_RESULT_NOT_FOUND);
    }
    _ReadSoFar = 0;
  }

  if (streamInfo != NULL)
  {
    // Set FILE data source information   
    VXIMapSetProperty(streamInfo, INET_INFO_DATA_SOURCE, 
                     (VXIValue*) VXIIntegerCreate(INET_DATA_SOURCE_FILE));
    
    // Use extension mapping algorithm to determine MIME content type
    VXIString *guessContent = _url->getContentTypeFromUrl();
    if (guessContent == NULL) {
      guessContent = VXIStringCreate(_channel->getDefaultMimeType());
      // This error message is useful, but unfortunately it gets printed
      // for all the grammar files etc. whose extensions are unknown...
      //Error (303, L"%s%s", L"URL", _url->getPath());
    }
    VXIMapSetProperty(streamInfo, INET_INFO_MIME_TYPE, (VXIValue*) guessContent);

    // Set the absolute path, any file:// prefix and host name is
    // already stripped prior to this method being invoked
    VXIMapSetProperty(streamInfo, INET_INFO_ABSOLUTE_NAME,
		      (VXIValue*)VXIStringCreate( _url->getPath() ));

    // Set the validator property
    VXIValue *newValidator = NULL;
    if (returnValue == VXIinet_RESULT_NOT_MODIFIED) {
      newValidator = VXIValueClone(validatorVal);
    } else {
      SBinetValidator validator(GetLog(), GetDiagBase());
      if (validator.Create(_url->getPath(), statInfo.st_size,
                           statInfo.st_mtime) == VXIinet_RESULT_SUCCESS)
      {
	newValidator = (VXIValue *) validator.serialize();
      }
    }

    if (newValidator)
      VXIMapSetProperty(streamInfo, INET_INFO_VALIDATOR, newValidator);
    else {
      Error(103, NULL);
      returnValue = VXIinet_RESULT_OUT_OF_MEMORY;
    }

    // Set the size
    VXIMapSetProperty(streamInfo, INET_INFO_SIZE_BYTES,
		      (VXIValue*)VXIIntegerCreate( _content_length));
  }

  if (!validatorVal && (returnValue == VXIinet_RESULT_NOT_MODIFIED))
    return VXIinet_RESULT_SUCCESS;

  return returnValue;
}
Example #13
0
// This function is responsible for calling the VXIrec level Recognize function
// and then mapping the grammar back to the corresponding VXML node.
//
int GrammarManager::Recognize(const VXIMapHolder & properties,
                              RecognitionAnswer & recAnswer,
                              VXMLElement & recNode)
{
  recNode = VXMLElement();
  VXIrecRecognitionResult * answer = NULL;

  // (1) Do VXIrec level Recognitize and process return value.

  // (1.1) Recognize.
  VXIrecResult err = vxirec->Recognize(vxirec, properties.GetValue(),
                                       &answer);
  if (err == VXIrec_RESULT_OUT_OF_MEMORY) {
    log.LogDiagnostic(0,L"GrammarManager::InternalRecognize - Out of memory.");
    return GrammarManager::OutOfMemory;
  }

  if (err == VXIrec_RESULT_DISCONNECT) {
    // Here is the case that the call is being disconnected before the 
    // recognition even starts
    return GrammarManager::Disconnect;
  }

  // (1.2) Anything other than success indicates that recognition failed
  // (badly).  The normal error conditions are returned through the recogntion
  // result structure.
  if (err != VXIrec_RESULT_SUCCESS) {
    log.StartDiagnostic(0) << L"GrammarManager::InternalRecognize - "
      L"VXIrecInterface::Recognize returned " << int (err);
    log.EndDiagnostic();
    log.LogError(420, SimpleLogger::MESSAGE,
                 L"function did not return the expected VXIrecSUCCESS result");
    return GrammarManager::InternalError;
  }

  // (1.3) The answer structure must be defined.
  if (answer == NULL) {
    // Here is the case that the call is being disconnected before the recording even starts
    return GrammarManager::Disconnect;
  }

  // (1.4) Attach the answer structure returned by VXIrec and the waveform to
  // the recAnswer class.
  recAnswer.Bind(answer);
  recAnswer.waveform = answer->waveform;

  // (2) Process all non-Successful results.

  // (2.1) First the status code.

  switch (answer->status) {
  case REC_STATUS_SUCCESS:    // Recognition returned a hypothesis
  case REC_STATUS_DTMFSUCCESS:    // Recognition returned a hypothesis
    break;
  case REC_STATUS_FAILURE:    // Speech detected, no likely hypothesis
    return GrammarManager::Failure;
  case REC_STATUS_TIMEOUT:    // No speech was detected
    return GrammarManager::Timeout;
  case REC_STATUS_DISCONNECT: // Caller has disconnected; no hypothesis
    return GrammarManager::Disconnect;
  case REC_STATUS_ERROR:      // An error aborted recognition
    return GrammarManager::Error;
  default:
    log.StartDiagnostic(0) << L"GrammarManager::InternalRecognize - "
      L"VXIrecInterface::Recognize returned status " << int(answer->status);
    log.EndDiagnostic();
    log.LogError(420, SimpleLogger::MESSAGE,
                 L"function returned an invalid VXIrecStatus code");
    return GrammarManager::InternalError;
  }

  // (2.2) Recognition success. Verify that the input mode was set correctly.

  switch (answer->mode) {
  case REC_INPUT_MODE_DTMF:
  case REC_INPUT_MODE_SPEECH:
    break;
  default:
    log.StartDiagnostic(0) << L"GrammarManager::InternalRecognize - "
      L"VXIrecInterface::Recognize returned mode " << int(answer->mode);
    log.EndDiagnostic();
    log.LogError(420, SimpleLogger::MESSAGE,
                 L"function returned an invalid VXIrecInputMode value");
    return GrammarManager::InternalError;
  }

  // (3) Walk through results array and sanity check the results.

  // (3.1) How many answers are there?

  if (answer->results == NULL) {
    log.LogError(420, SimpleLogger::MESSAGE,
                 L"function returned a null results vector");
    return GrammarManager::InternalError;
  }

  unsigned int NUM_ANSWERS = VXIVectorLength(answer->results);
  if (NUM_ANSWERS == 0) {
    log.LogError(420, SimpleLogger::MESSAGE,
                 L"function returned an empty results vector");
    return GrammarManager::InternalError;
  }

  const VXIMap * bestAnswer = NULL;

  for (unsigned int i = 0; i < NUM_ANSWERS; ++i) {
    // (3.2) Find each element in the result vector.
    
    const VXIValue * temp = VXIVectorGetElement(answer->results, i);
    if (temp == NULL) {
      log.LogError(400, SimpleLogger::MESSAGE,
                   L"VXIVectorGetElement failed to return answer.");
      return GrammarManager::InternalError;
    }
    
    if (VXIValueGetType(temp) != VALUE_MAP) {
      log.LogError(420, SimpleLogger::MESSAGE,
                   L"function returned an invalid results vector");
      return GrammarManager::InternalError;
    }

    const VXIMap * nthAnswer = reinterpret_cast<const VXIMap*>(temp);
    if (i == 0) bestAnswer = nthAnswer;

    // (3.3) Validate types of member keys.

    temp = VXIMapGetProperty(nthAnswer, REC_KEYS);
    if (temp == NULL || VXIValueGetType(temp) != VALUE_VECTOR) {
      log.LogError(420, SimpleLogger::MESSAGE,
                   L"REC_KEYS must be defined with type vector");
      return GrammarManager::InternalError;
    }
    const VXIVector * keys = reinterpret_cast<const VXIVector *>(temp);

    temp = VXIMapGetProperty(nthAnswer, REC_VALUES);
    if (temp == NULL || VXIValueGetType(temp) != VALUE_VECTOR) {
      log.LogError(420, SimpleLogger::MESSAGE,
                   L"REC_VALUES must be defined with type vector");
      return GrammarManager::InternalError;
    }
    const VXIVector * values = reinterpret_cast<const VXIVector *>(temp);

    temp = VXIMapGetProperty(nthAnswer, REC_CONF);
    if (temp == NULL || VXIValueGetType(temp) != VALUE_VECTOR) {
      log.LogError(420, SimpleLogger::MESSAGE,
                   L"REC_CONF must be defined with type vector");
      return GrammarManager::InternalError;
    }
    const VXIVector * scores = reinterpret_cast<const VXIVector *>(temp);

    temp = VXIMapGetProperty(nthAnswer, REC_RAW);
    if (temp == NULL || VXIValueGetType(temp) != VALUE_VECTOR) {
      log.LogError(420, SimpleLogger::MESSAGE,
                   L"REC_RAW must be defined with type vector");
      return GrammarManager::InternalError;
    }
    const VXIVector * utts = reinterpret_cast<const VXIVector *>(temp);

    // (3.4) Validate vector lengths.

    const VXIunsigned length = VXIVectorLength(keys);
    if (length < 1) {
      log.LogError(420, SimpleLogger::MESSAGE,
                   L"result vector must have length of at least one");
      throw VXIException::Fatal();
    }
    if (length != VXIVectorLength(values) ||
        length != VXIVectorLength(scores) ||
        length != VXIVectorLength(utts))
    {
      log.LogError(420, SimpleLogger::MESSAGE,
                   L"result vector length must all match");
      return GrammarManager::InternalError;
    }

    temp = VXIVectorGetElement(keys, 0);
    if (temp == NULL || VXIValueGetType(temp) != VALUE_STRING) {
      log.LogError(420, SimpleLogger::MESSAGE,
                   L"first REC_KEYS must be defined with type string");
      return GrammarManager::InternalError;
    }

    // (3.5) Copy into results class.

    recAnswer.keys.push_back(keys);
    recAnswer.values.push_back(values);
    recAnswer.scores.push_back(scores);
    recAnswer.utts.push_back(utts);
  }

  recAnswer.numAnswers = NUM_ANSWERS;

  // (4) Find the VXML element associated with the matched grammar.

  // (4.1) Find the grammar corresponding to the best answer.

  const VXIValue * temp = VXIMapGetProperty(bestAnswer, REC_GRAMMAR);
  if (temp == NULL || VXIValueGetType(temp) != VALUE_PTR) {
    log.LogError(420, SimpleLogger::MESSAGE,
                 L"unable to obtain grammar key from 'results' #0");
    return GrammarManager::InternalError;
  }

  const VXIPtr * tempptr = reinterpret_cast<const VXIPtr *>(temp);
  const VXIrecGrammar * bestGrammar =
    reinterpret_cast<const VXIrecGrammar*>(VXIPtrValue(tempptr));

  // (4.2) Map the VXIrecGrammar pointer back to the source VXMLElement.

  for (GRAMMARS::iterator j = grammars.begin(); j != grammars.end(); ++j) 
  {
    if ((answer->mode == REC_INPUT_MODE_DTMF && REC_STATUS_DTMFSUCCESS != answer->status) 
      && (*j)->GetRecGrammar() != bestGrammar) continue;

    if (!(*j)->IsEnabled()) 
    {
      if (j == grammars.end()) {
        log.LogError(420, SimpleLogger::MESSAGE,
                     L"function returned an inactive grammar");
        return GrammarManager::InternalError;
      }
      continue;
    }

    (*j)->GetElement(recNode);

    if (answer->mode == REC_INPUT_MODE_DTMF)
      return GrammarManager::SuccessDTMF;

    return GrammarManager::Success;
  }

  log.LogError(420, SimpleLogger::MESSAGE,
               L"function returned a non-existent grammar");
  return GrammarManager::InternalError;
}