RedirectPlugin::LookUpStatus SipRedirectorRegDB::lookUp( const SipMessage& message, const UtlString& requestString, const Url& requestUri, const UtlString& method, ContactList& contactList, RequestSeqNo requestSeqNo, int redirectorNo, SipRedirectorPrivateStorage*& privateStorage, ErrorDescriptor& errorDescriptor) { unsigned long timeNow = OsDateTime::getSecsSinceEpoch(); // Local copy of requestUri Url requestUriCopy = requestUri; // Look for any grid parameter and remove it. UtlString gridParameter; UtlBoolean gridPresent = requestUriCopy.getUrlParameter("grid", gridParameter, 0); if (gridPresent) { requestUriCopy.removeUrlParameter("grid"); } if (Os::Logger::instance().willLog(FAC_SIP, PRI_DEBUG)) { UtlString temp; requestUriCopy.getUri(temp); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp gridPresent = %d, gridParameter = '%s', " "requestUriCopy after removing grid = '%s'", mLogName.data(), gridPresent, gridParameter.data(), temp.data()); } RegDB::Bindings registrations; // Give the ~~in~ URIs separate processing. UtlString user; requestUriCopy.getUserId(user); if (user.index(URI_IN_PREFIX) == 0) { // This is a ~~in~ URI. // Check for an '&' separator. ssize_t s = user.last('&'); if (s != UTL_NOT_FOUND) { // This is a ~~in~[user]&[instrument] URI. const char* instrumentp = user.data() + s + 1; UtlString u; u.append(user, sizeof (URI_IN_PREFIX) - 1, s - (sizeof (URI_IN_PREFIX) - 1)); requestUriCopy.setUserId(u); //regDB-> // getUnexpiredContactsUserInstrument(requestUriCopy, instrumentp, timeNow, registrations); UtlString identity; requestUriCopy.getIdentity(identity); _dataStore.regDB().getUnexpiredContactsUserInstrument(identity.str(), instrumentp, timeNow, registrations); } else { // This is a ~~in~[instrument] URI. const char* instrumentp = user.data() + sizeof (URI_IN_PREFIX) - 1; _dataStore.regDB().getUnexpiredContactsInstrument(instrumentp, timeNow, registrations); } } else { // Note that getUnexpiredContactsUser will reduce the requestUri to its // identity (user/host/port) part before searching in the // database. The requestUri identity is matched against the // "identity" column of the database, which is the identity part of // the "uri" column which is stored in registration.xml. UtlString identity; requestUriCopy.getIdentity(identity); _dataStore.regDB().getUnexpiredContactsUser(identity.str(), timeNow, registrations); } int numUnexpiredContacts = registrations.size(); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp got %d unexpired contacts", mLogName.data(), numUnexpiredContacts); // Check for a per-user call forward timer. // Don't set timer if we're not going to forward to voicemail. std::ostringstream userCfwdTimer; bool foundUserCfwdTimer = false; if (method.compareTo(SIP_INVITE_METHOD) == 0) { UtlString noRoute; requestUriCopy.getUrlParameter("sipx-noroute", noRoute); if ((!noRoute.isNull()) && (noRoute.compareTo("Voicemail") == 0)) { // This is not a call scenerio controlled by this users "forward to voicemail" timer } else { UtlString identity; requestUriCopy.getIdentity(identity); EntityRecord entity; foundUserCfwdTimer = _dataStore.entityDB().findByIdentity(identity.str(), entity); if (foundUserCfwdTimer) userCfwdTimer << entity.callForwardTime(); } } for (RegDB::Bindings::const_iterator iter = registrations.begin(); iter != registrations.end(); iter++) { // Query the Registration DB for the contact, expires and qvalue columns. Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "%s::lookUp contact = '%s', qvalue = '%s', path = '%s'", mLogName.data(), iter->getContact().c_str(), iter->getQvalue().c_str(), iter->getPath().c_str() ); Url contactUri(iter->getContact().c_str()); // If available set the per-user call forward timer. if (foundUserCfwdTimer) { contactUri.setHeaderParameter("expires", userCfwdTimer.str().c_str()); } // If the contact URI is the same as the request URI, ignore it. if (!contactUri.isUserHostPortEqual(requestUriCopy)) { // Check if the q-value from the database is valid, and if so, // add it into contactUri. if (!iter->getQvalue().empty()) { // :TODO: (XPL-3) need a RegEx copy constructor here // Check if q value is numeric and between the range 0.0 and 1.0. static RegEx qValueValid("^(0(\\.\\d{0,3})?|1(\\.0{0,3})?)$"); if (qValueValid.Search(iter->getQvalue().c_str())) { contactUri.setFieldParameter(SIP_Q_FIELD, iter->getQvalue().c_str()); } } // Re-apply any grid parameter. if (gridPresent) { contactUri.setUrlParameter("grid", gridParameter); } contactUri.setUrlParameter(SIP_SIPX_CALL_DEST_FIELD, "INT"); // Check if database contained a Path value. If so, add a Route // header parameter to the contact with the Path vector taken from // the registration data. if (!iter->getPath().empty()) { UtlString existingRouteValue; std::string pathVector = iter->getPath(); if ( contactUri.getHeaderParameter(SIP_ROUTE_FIELD, existingRouteValue)) { // there is already a Route header parameter in the contact; append it to the // Route derived from the Path vector. pathVector += SIP_MULTIFIELD_SEPARATOR; pathVector += existingRouteValue.str(); } contactUri.setHeaderParameter(SIP_ROUTE_FIELD, pathVector.c_str()); } // Add the contact. contactList.add( contactUri, *this ); } } return RedirectPlugin::SUCCESS; }
void HttpFileAccess::sendFile(const UtlString& path, const UtlString& peerName, const HttpRequestContext& requestContext, const HttpMessage& request, HttpMessage*& response ) { UtlString message; int file = open(path.data(), O_RDONLY); if (0 <= file) { UtlString fileBuffer; if (fileBuffer.capacity(MAX_FILE_CHUNK_SIZE + 1) >= MAX_FILE_CHUNK_SIZE + 1) { response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION_1_1, HTTP_OK_CODE, HTTP_OK_TEXT); response->useChunkedBody(true); // @TODO Annotate file resources with a mime type? // add a Content-Disposition header to suggest saving as the basename of the file response->setContentType("application/octet-stream"); UtlString dispositionValue; UtlString basename; ssize_t finalSlash = path.last('/'); if (UTL_NOT_FOUND != finalSlash) { basename.append(path, finalSlash+1, path.length()-finalSlash); } else { basename.append(path); // don't think this should ever be true.... } dispositionValue.append("attachment; filename=\""); dispositionValue.append(basename); dispositionValue.append("\""); response->setHeaderValue(HTTP_CONTENT_DISPOSITION_FIELD,dispositionValue.data()); bool writtenOk = response->writeHeaders(requestContext.socket()); ssize_t bytes; Int64 totalBytes = 0; Int64 chunks = 0; while ( writtenOk && (bytes = read(file, (void*)fileBuffer.data(), MAX_FILE_CHUNK_SIZE))) { fileBuffer.setLength(bytes); writtenOk = response->writeChunk(requestContext.socket(), fileBuffer); if (writtenOk) { totalBytes += bytes; chunks++; } OsSysLog::add(FAC_SUPERVISOR, PRI_DEBUG, "file block %"FORMAT_INTLL"d %zd %s", chunks, bytes, writtenOk ? "ok" : "failed"); } if (writtenOk) { response->writeEndOfChunks(requestContext.socket()); message.append(" sent file '"); message.append(path); message.append("' ("); message.appendNumber(totalBytes,"%"FORMAT_INTLL"d"); message.append(" bytes in "); message.appendNumber(chunks,"%"FORMAT_INTLL"d"); message.append(" chunks) to peer "); message.append(peerName); OsSysLog::add(FAC_SUPERVISOR, PRI_INFO, "HttpFileAccess::processRequest %s", message.data()); } else { message.append("error writing response after "); message.appendNumber(totalBytes,"%"FORMAT_INTLL"d"); message.append(" body bytes in "); message.appendNumber(chunks,"%"FORMAT_INTLL"d"); message.append(" chunks) to peer "); message.append(peerName); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest %s", message.data()); } /* * We've already written the response, so prevent HttpServer from sending it by * not passing it back. */ delete response; response = NULL; } else { // Send out-of-resources message message.append("Supervisor Buffer Exhausted"); response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION, HTTP_OUT_OF_RESOURCES_CODE, message.data()); response->setContentType(CONTENT_TYPE_TEXT_PLAIN); response->setBody(new HttpBody(message.data(),message.length())); response->setContentLength(message.length()); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest from %s %s", peerName.data(), message.data()); } } else { int httpStatusCode; UtlString httpStatusText; switch (errno) { case EACCES: httpStatusCode = HTTP_FORBIDDEN_CODE; httpStatusText = "File Access Denied"; break; case ENOENT: httpStatusCode = HTTP_FILE_NOT_FOUND_CODE; httpStatusText = HTTP_FILE_NOT_FOUND_TEXT; break; default: httpStatusCode = HTTP_SERVER_ERROR_CODE; httpStatusText = HTTP_SERVER_ERROR_TEXT; break; } message.append("File '"); message.append(path); message.append("' errno "); message.appendNumber(errno); message.append(" "); char errnoMsg[1024]; strerror_r(errno, errnoMsg, sizeof(errnoMsg)); message.append(errnoMsg); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest from %s %s", peerName.data(), message.data()); response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION, httpStatusCode, httpStatusText); response->setBody(new HttpBody(message.data(),message.length())); response->setContentType(CONTENT_TYPE_TEXT_PLAIN); response->setContentLength(message.length()); } }