BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask)
{
	// Note: we don't bother sending the event to the children (the arrow buttons)
	// because they'll capture the mouse whenever they need hover events.
	
	BOOL handled = FALSE;
	if( hasMouseCapture() )
	{
		S32 height = getRect().getHeight();
		S32 width = getRect().getWidth();

		if( VERTICAL == mOrientation )
		{
//			S32 old_pos = mThumbRect.mTop;

			S32 delta_pixels = y - mDragStartY;
			if( mOrigRect.mBottom + delta_pixels < mThickness )
			{
				delta_pixels = mThickness - mOrigRect.mBottom - 1;
			}
			else
			if( mOrigRect.mTop + delta_pixels > height - mThickness )
			{
				delta_pixels = height - mThickness - mOrigRect.mTop + 1;
			}

			mThumbRect.mTop = mOrigRect.mTop + delta_pixels;
			mThumbRect.mBottom = mOrigRect.mBottom + delta_pixels;

			S32 thumb_length = mThumbRect.getHeight();
			S32 thumb_track_length = height - 2 * mThickness;


			if( delta_pixels != mLastDelta || mDocChanged)
			{	
				// Note: delta_pixels increases as you go up.  mDocPos increases down (line 0 is at the top of the page).
				S32 usable_track_length = thumb_track_length - thumb_length;
				if( 0 < usable_track_length )
				{
					S32 variable_lines = getDocPosMax();
					S32 pos = mThumbRect.mTop;
					F32 ratio = F32(pos - mThickness - thumb_length) / usable_track_length;	
	
					S32 new_pos = llclamp( S32(variable_lines - ratio * variable_lines + 0.5f), 0, variable_lines );
					// Note: we do not call updateThumbRect() here.  Instead we let the thumb and the document go slightly
					// out of sync (less than a line's worth) to make the thumb feel responsive.
					changeLine( new_pos - mDocPos, FALSE );
				}
			}

			mLastDelta = delta_pixels;
		
		}
		else
		{
			// Horizontal
//			S32 old_pos = mThumbRect.mLeft;

			S32 delta_pixels = x - mDragStartX;

			if( mOrigRect.mLeft + delta_pixels < mThickness )
			{
				delta_pixels = mThickness - mOrigRect.mLeft - 1;
			}
			else
			if( mOrigRect.mRight + delta_pixels > width - mThickness )
			{
				delta_pixels = width - mThickness - mOrigRect.mRight + 1;
			}

			mThumbRect.mLeft = mOrigRect.mLeft + delta_pixels;
			mThumbRect.mRight = mOrigRect.mRight + delta_pixels;
			
			S32 thumb_length = mThumbRect.getWidth();
			S32 thumb_track_length = width - 2 * mThickness;

			if( delta_pixels != mLastDelta || mDocChanged)
			{	
				// Note: delta_pixels increases as you go up.  mDocPos increases down (line 0 is at the top of the page).
				S32 usable_track_length = thumb_track_length - thumb_length;
				if( 0 < usable_track_length )
				{
					S32 variable_lines = getDocPosMax();
					S32 pos = mThumbRect.mLeft;
					F32 ratio = F32(pos - mThickness) / usable_track_length;	
	
					S32 new_pos = llclamp( S32(ratio * variable_lines + 0.5f), 0, variable_lines);
	
					// Note: we do not call updateThumbRect() here.  Instead we let the thumb and the document go slightly
					// out of sync (less than a line's worth) to make the thumb feel responsive.
					changeLine( new_pos - mDocPos, FALSE );
				}
			}

			mLastDelta = delta_pixels;
		}

		getWindow()->setCursor(UI_CURSOR_ARROW);
		LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL;		
		handled = TRUE;
	}
	else
	{
		handled = childrenHandleHover( x, y, mask ) != NULL;
	}

	// Opaque
	if( !handled )
	{
		getWindow()->setCursor(UI_CURSOR_ARROW);
		LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)"  << LL_ENDL;		
		handled = TRUE;
	}

	mDocChanged = FALSE;
	return handled;
} // end handleHover
void LLPluginProcessParent::updatePollset()
{
	if(!sInstancesMutex)
	{
		// No instances have been created yet.  There's no work to do.
		return;
	}
		
	LLMutexLock lock(sInstancesMutex);

	if(sPollSet)
	{
		LL_DEBUGS("PluginPoll") << "destroying pollset " << sPollSet << LL_ENDL;
		// delete the existing pollset.
		apr_pollset_destroy(sPollSet);
		sPollSet = NULL;
	}
	
	std::list<LLPluginProcessParent*>::iterator iter;
	int count = 0;
	
	// Count the number of instances that want to be in the pollset
	for(iter = sInstances.begin(); iter != sInstances.end(); iter++)
	{
		(*iter)->mPolledInput = false;
		if((*iter)->mPollFD.client_data)
		{
			// This instance has a socket that needs to be polled.
			++count;
		}
	}

	if(sUseReadThread && sReadThread && !sReadThread->isQuitting())
	{
		if(!sPollSet && (count > 0))
		{
#ifdef APR_POLLSET_NOCOPY
			// The pollset doesn't exist yet.  Create it now.
			apr_status_t status = apr_pollset_create(&sPollSet, count, gAPRPoolp, APR_POLLSET_NOCOPY);
			if(status != APR_SUCCESS)
			{
#endif // APR_POLLSET_NOCOPY
				LL_WARNS("PluginPoll") << "Couldn't create pollset.  Falling back to non-pollset mode." << LL_ENDL;
				sPollSet = NULL;
#ifdef APR_POLLSET_NOCOPY
			}
			else
			{
				LL_DEBUGS("PluginPoll") << "created pollset " << sPollSet << LL_ENDL;
				
				// Pollset was created, add all instances to it.
				for(iter = sInstances.begin(); iter != sInstances.end(); iter++)
				{
					if((*iter)->mPollFD.client_data)
					{
						status = apr_pollset_add(sPollSet, &((*iter)->mPollFD));
						if(status == APR_SUCCESS)
						{
							(*iter)->mPolledInput = true;
						}
						else
						{
							LL_WARNS("PluginPoll") << "apr_pollset_add failed with status " << status << LL_ENDL;
						}
					}
				}
			}
#endif // APR_POLLSET_NOCOPY
		}
	}
}
void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message)
{
	std::string message_class = message.getClass();
	if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL)
	{
		// internal messages should be handled here
		std::string message_name = message.getName();
		if(message_name == "hello")
		{
			if(mState == STATE_CONNECTED)
			{
				// Plugin host has launched.  Tell it which plugin to load.
				setState(STATE_HELLO);
			}
			else
			{
				LL_WARNS("Plugin") << "received hello message in wrong state -- bailing out" << LL_ENDL;
				errorState();
			}
			
		}
		else if(message_name == "load_plugin_response")
		{
			if(mState == STATE_LOADING)
			{
				// Plugin has been loaded. 
				
				mPluginVersionString = message.getValue("plugin_version");
				LL_INFOS("Plugin") << "plugin version string: " << mPluginVersionString << LL_ENDL;

				// Check which message classes/versions the plugin supports.
				// TODO: check against current versions
				// TODO: kill plugin on major mismatches?
				mMessageClassVersions = message.getValueLLSD("versions");
				LLSD::map_iterator iter;
				for(iter = mMessageClassVersions.beginMap(); iter != mMessageClassVersions.endMap(); iter++)
				{
					LL_INFOS("Plugin") << "message class: " << iter->first << " -> version: " << iter->second.asString() << LL_ENDL;
				}
				
				// Send initial sleep time
				llassert_always(mSleepTime != 0.f);
				setSleepTime(mSleepTime, true);			

				setState(STATE_RUNNING);
			}
			else
			{
				LL_WARNS("Plugin") << "received load_plugin_response message in wrong state -- bailing out" << LL_ENDL;
				errorState();
			}
		}
		else if(message_name == "heartbeat")
		{
			// this resets our timer.
			mHeartbeat.setTimerExpirySec(mPluginLockupTimeout);

			mCPUUsage = message.getValueReal("cpu_usage");

			LL_DEBUGS("Plugin") << "cpu usage reported as " << mCPUUsage << LL_ENDL;
			
		}
		else if(message_name == "shm_add_response")
		{
			// Nothing to do here.
		}
		else if(message_name == "shm_remove_response")
		{
			std::string name = message.getValue("name");
			sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
			
			if(iter != mSharedMemoryRegions.end())
			{
				// destroy the shared memory region
				iter->second->destroy();
				delete iter->second;
				iter->second = NULL;
				
				// and remove it from our map
				mSharedMemoryRegions.erase(iter);
			}
		}
		else
		{
			LL_WARNS("Plugin") << "Unknown internal message from child: " << message_name << LL_ENDL;
		}
	}
	else
	{
		if(mOwner != NULL)
		{
			mOwner->receivePluginMessage(message);
		}
	}
}
Example #4
0
BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask)
{
	if (gDebugClicks)
	{
		llinfos << "LLToolPie handleDoubleClick (becoming mouseDown)" << llendl;
	}

	LLViewerObject *object = mPick.getObject();
	if(object)
	{
		//Zwagoth: No more teleport to HUD attachments. >:o
		if (object->isHUDAttachment())
		{
			LL_DEBUGS("DoubleClicks") << "Double clicked HUD" << LL_ENDL;
			return FALSE;
		}

		//Armin: No more teleport to other attachments or Avatars including self ...
		if (object->isAttachment())
		{
			LL_DEBUGS("DoubleClicks") << "Double clicked attachment (not HUD)" << LL_ENDL;
			return FALSE;
		}

		if (object->isAvatar()&& object == gAgent.getAvatarObject() )
		{
			LL_DEBUGS("DoubleClicks") << "Double clicked self" << LL_ENDL;
			return FALSE;
		}

		if (object->isAvatar())
		{
			LL_DEBUGS("DoubleClicks") << "Double clicked other Avatar" << LL_ENDL;
			return FALSE;// or what about open profile or IM session or ...
		}

		if (final_click_action(object))
		{
			LL_DEBUGS("DoubleClicks") << "Double clicked an object with a click action" << LL_ENDL;
			return FALSE;
		}

		LLViewerObject* parent = object->getRootEdit();
		if (object->flagHandleTouch() || (parent && parent->flagHandleTouch()))
		{
			LL_DEBUGS("DoubleClicks") << "Double clicked a touch-scripted object" << LL_ENDL;
			return FALSE;
		}

		const LLTextureEntry* tep = object->getTE(mPick.mObjectFace);
		viewer_media_t media_impl = tep ? LLViewerMedia::getMediaImplFromTextureID(tep->getID()) : NULL;
		if (media_impl.notNull() && media_impl->hasMedia())
		{
			LL_DEBUGS("DoubleClicks") << "Double clicked running parcel media" << LL_ENDL;
			return FALSE;
		}
	}

	std::string action = gSavedSettings.getString("DoubleClickAction");
	LLStringUtil::toLower(action);
	if (action == "none")
	{
		return FALSE;
	}
	else if (action == "go")
	{
		if (mPick.mPickType == LLPickInfo::PICK_LAND
			&& !mPick.mPosGlobal.isExactlyZero())
		{
			handle_go_to_confirm();
			return TRUE;
		}
		else if (mPick.mObjectID.notNull()
				 && !mPick.mPosGlobal.isExactlyZero())
		{
			handle_go_to_confirm();
			return TRUE;
		}
	}
	else
	{
		llwarns << "Unhandled DoubleClickAction setting: " << action << llendl;
	}

	return FALSE;
}
void LLPluginProcessParent::setState(EState state)
{
	LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL;
	mState = state; 
};
void LLMaterialMgr::processPutQueue()
{
	typedef std::map<LLViewerRegion*, LLSD> regionput_request_map;
	regionput_request_map requests;

	put_queue_t::iterator loopQueue = mPutQueue.begin();
	while (mPutQueue.end() != loopQueue)
	{
		put_queue_t::iterator itQueue = loopQueue++;

		const LLUUID& object_id = itQueue->first;
		const LLViewerObject* objectp = gObjectList.findObject(object_id);
		if ( !objectp )
		{
			LL_WARNS("Materials") << "Object is NULL" << LL_ENDL;
			mPutQueue.erase(itQueue);
		}
		else
		{
			LLViewerRegion* regionp = objectp->getRegion();
			if ( !regionp )
		{
				LL_WARNS("Materials") << "Object region is NULL" << LL_ENDL;
				mPutQueue.erase(itQueue);
		}
			else if ( regionp->capabilitiesReceived() && !regionp->materialsCapThrottled())
			{
		LLSD& facesData = requests[regionp];

		facematerial_map_t& face_map = itQueue->second;
				U32 max_entries = regionp->getMaxMaterialsPerTransaction();
		facematerial_map_t::iterator itFace = face_map.begin();
				while ( (face_map.end() != itFace) && (facesData.size() < (int)max_entries) )
		{
			LLSD faceData = LLSD::emptyMap();
			faceData[MATERIALS_CAP_FACE_FIELD] = static_cast<LLSD::Integer>(itFace->first);
			faceData[MATERIALS_CAP_OBJECT_ID_FIELD] = static_cast<LLSD::Integer>(objectp->getLocalID());
			if (!itFace->second.isNull())
			{
				faceData[MATERIALS_CAP_MATERIAL_FIELD] = itFace->second.asLLSD();
			}
			facesData.append(faceData);
			face_map.erase(itFace++);
		}
		if (face_map.empty())
		{
			mPutQueue.erase(itQueue);
		}
	}
		}
	}

	for (regionput_request_map::const_iterator itRequest = requests.begin(); itRequest != requests.end(); ++itRequest)
	{
		LLViewerRegion* regionp = itRequest->first;
		std::string capURL = regionp->getCapability(MATERIALS_CAPABILITY_NAME);
		if (capURL.empty())
		{
			LL_WARNS("Materials") << "Capability '" << MATERIALS_CAPABILITY_NAME
				<< "' is not defined on region '" << regionp->getName() << "'" << LL_ENDL;
			continue;
		}

		LLSD materialsData = LLSD::emptyMap();
		materialsData[MATERIALS_CAP_FULL_PER_FACE_FIELD] = itRequest->second;

		std::string materialString = zip_llsd(materialsData);

		S32 materialSize = materialString.size();

		if (materialSize > 0)
		{
			LLSD::Binary materialBinary;
			materialBinary.resize(materialSize);
			memcpy(materialBinary.data(), materialString.data(), materialSize);

			LLSD putData = LLSD::emptyMap();
			putData[MATERIALS_CAP_ZIP_FIELD] = materialBinary;

			LL_DEBUGS("Materials") << "put for " << itRequest->second.size() << " faces to region " << itRequest->first->getName() << LL_ENDL;
			LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("PUT", capURL, boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2));
			LLHTTPClient::put(capURL, putData, materialsResponder);
			regionp->resetMaterialsCapThrottle();
		}
		else
		{
			LL_ERRS("debugMaterials") << "cannot zip LLSD binary content" << LL_ENDL;
		}
	}
}
// virtual static
void LLWaterParamManager::initSingleton()
{
	LL_DEBUGS("Windlight") << "Initializing water" << LL_ENDL;
	loadAllPresets();
	LLEnvManagerNew::instance().usePrefs();
}
// virtual
void LLButton::draw()
{
	static LLCachedControl<bool> sEnableButtonFlashing(*LLUI::sSettingGroups["config"], "EnableButtonFlashing", true);
	F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency();

	bool pressed_by_keyboard = FALSE;
	if (hasFocus())
	{
		pressed_by_keyboard = gKeyboard->getKeyDown(' ') || (mCommitOnReturn && gKeyboard->getKeyDown(KEY_RETURN));
	}

	bool mouse_pressed_and_over = false;
	if (hasMouseCapture())
	{
		S32 local_mouse_x ;
		S32 local_mouse_y;
		LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y);
		mouse_pressed_and_over = pointInView(local_mouse_x, local_mouse_y);
	}

	bool enabled = isInEnabledChain();

	bool pressed = pressed_by_keyboard 
					|| mouse_pressed_and_over
					|| mForcePressedState;
	bool selected = getToggleState();
	
	bool use_glow_effect = FALSE;
	LLColor4 highlighting_color = LLColor4::white;
	LLColor4 glow_color = LLColor4::white;
	LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA;
	LLUIImage* imagep = NULL;

    //  Cancel sticking of color, if the button is pressed,
	//  or when a flashing of the previously selected button is ended
	if (mFlashingTimer
		&& ((selected && !mFlashingTimer->isFlashingInProgress() && !mForceFlashing) || pressed))
	{
		mFlashing = false;
	}

	bool flash = mFlashing && sEnableButtonFlashing;

	if (pressed && mDisplayPressedState)
	{
		imagep = selected ? mImagePressedSelected : mImagePressed;
	}
	else if ( mNeedsHighlight )
	{
		if (selected)
		{
			if (mImageHoverSelected)
			{
				imagep = mImageHoverSelected;
			}
			else
			{
				imagep = mImageSelected;
				use_glow_effect = TRUE;
			}
		}
		else
		{
			if (mImageHoverUnselected)
			{
				imagep = mImageHoverUnselected;
			}
			else
			{
				imagep = mImageUnselected;
				use_glow_effect = TRUE;
			}
		}
	}
	else 
	{
		imagep = selected ? mImageSelected : mImageUnselected;
	}

	// Override if more data is available
	// HACK: Use gray checked state to mean either:
	//   enabled and tentative
	// or
	//   disabled but checked
	if (!mImageDisabledSelected.isNull() 
		&& 
			( (enabled && getTentative()) 
			|| (!enabled && selected ) ) )
	{
		imagep = mImageDisabledSelected;
	}
	else if (!mImageDisabled.isNull() 
		&& !enabled 
		&& !selected)
	{
		imagep = mImageDisabled;
	}

	if (mFlashing)
	{
		// if button should flash and we have icon for flashing, use it as image for button
		if(flash && mImageFlash)
		{
			// setting flash to false to avoid its further influence on glow
			flash = false;
			imagep = mImageFlash;
		}
		// else use usual flashing via flash_color
		else if (mFlashingTimer)
		{
			LLColor4 flash_color = mFlashBgColor.get();
			use_glow_effect = TRUE;
			glow_type = LLRender::BT_ALPHA; // blend the glow

			if (mFlashingTimer->isCurrentlyHighlighted() || !mFlashingTimer->isFlashingInProgress())
			{
				glow_color = flash_color;
			}
			else if (mNeedsHighlight)
			{
                glow_color = highlighting_color;
			}
		}
	}

	if (mNeedsHighlight && !imagep)
	{
		use_glow_effect = TRUE;
	}

	// Figure out appropriate color for the text
	LLColor4 label_color;

	// label changes when button state changes, not when pressed
	if ( enabled )
	{
		if ( getToggleState() )
		{
			label_color = mSelectedLabelColor.get();
		}
		else
		{
			label_color = mUnselectedLabelColor.get();
		}
	}
	else
	{
		if ( getToggleState() )
		{
			label_color = mDisabledSelectedLabelColor.get();
		}
		else
		{
			label_color = mDisabledLabelColor.get();
		}
	}

	// <FS::ND> Highlight if needed
	if( nd::ui::SearchableControl::getHighlighted() )
		label_color = nd::ui::SearchableControl::getHighlightColor();
	// </FS:ND>

	// Unselected label assignments
	LLWString label = getCurrentLabel();

	// overlay with keyboard focus border
	if (hasFocus())
	{
		F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
		drawBorder(imagep, gFocusMgr.getFocusColor() % alpha, ll_round(lerp(1.f, 3.f, lerp_amt)));
	}
	
	if (use_glow_effect)
	{
		mCurGlowStrength = lerp(mCurGlowStrength,
					// <FS:Ansariel> Crash fix; Calling setFlashing can cause mFlashing being true while is mFlashingTimer is NULL
					//mFlashing ? (mFlashingTimer->isCurrentlyHighlighted() || !mFlashingTimer->isFlashingInProgress() || mNeedsHighlight? 1.0 : 0.0) : mHoverGlowStrength,
					(mFlashing && mFlashingTimer) ? (mFlashingTimer->isCurrentlyHighlighted() || !mFlashingTimer->isFlashingInProgress() || mNeedsHighlight? 1.0 : 0.0) : mHoverGlowStrength,
					LLSmoothInterpolation::getInterpolant(0.05f));
	}
	else
	{
		mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLSmoothInterpolation::getInterpolant(0.05f));
	}

	// Draw button image, if available.
	// Otherwise draw basic rectangular button.
	if (imagep != NULL)
	{
		// apply automatic 50% alpha fade to disabled image
		LLColor4 disabled_color = mFadeWhenDisabled ? mDisabledImageColor.get() % 0.5f : mDisabledImageColor.get();
		if ( mScaleImage)
		{
			imagep->draw(getLocalRect(), (enabled ? mImageColor.get() : disabled_color) % alpha  );
			if (mCurGlowStrength > 0.01f)
			{
				gGL.setSceneBlendType(glow_type);
				imagep->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha));
				gGL.setSceneBlendType(LLRender::BT_ALPHA);
			}
		}
		else
		{
			imagep->draw(0, 0, (enabled ? mImageColor.get() : disabled_color) % alpha );
			if (mCurGlowStrength > 0.01f)
			{
				gGL.setSceneBlendType(glow_type);
				imagep->drawSolid(0, 0, glow_color % (mCurGlowStrength * alpha));
				gGL.setSceneBlendType(LLRender::BT_ALPHA);
			}
		}
	}
	else
	{
		// no image
		LL_DEBUGS() << "No image for button " << getName() << LL_ENDL;
		// draw it in pink so we can find it
		gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4::pink1 % alpha, FALSE);
	}

	// let overlay image and text play well together
	S32 text_left = mLeftHPad;
	S32 text_right = getRect().getWidth() - mRightHPad;
	S32 text_width = getRect().getWidth() - mLeftHPad - mRightHPad;

	// draw overlay image
	if (mImageOverlay.notNull())
	{
		// get max width and height (discard level 0)
		S32 overlay_width;
		S32 overlay_height;

		getOverlayImageSize(overlay_width, overlay_height);

		S32 center_x = getLocalRect().getCenterX();
		S32 center_y = getLocalRect().getCenterY();

		//FUGLY HACK FOR "DEPRESSED" BUTTONS
		if (pressed && mDisplayPressedState)
		{
			center_y--;
			center_x++;
		}

		center_y += (mImageOverlayBottomPad - mImageOverlayTopPad);
		// fade out overlay images on disabled buttons
		LLColor4 overlay_color = mImageOverlayColor.get();
		if (!enabled)
		{
			overlay_color = mImageOverlayDisabledColor.get();
		}
		else if (getToggleState())
		{
			overlay_color = mImageOverlaySelectedColor.get();
		}
		overlay_color.mV[VALPHA] *= alpha;

		switch(mImageOverlayAlignment)
		{
		case LLFontGL::LEFT:
			text_left += overlay_width + mImgOverlayLabelSpace;
			text_width -= overlay_width + mImgOverlayLabelSpace;
			mImageOverlay->draw(
				mLeftHPad,
				center_y - (overlay_height / 2), 
				overlay_width, 
				overlay_height, 
				overlay_color);
			break;
		case LLFontGL::HCENTER:
			mImageOverlay->draw(
				center_x - (overlay_width / 2), 
				center_y - (overlay_height / 2), 
				overlay_width, 
				overlay_height, 
				overlay_color);
			break;
		case LLFontGL::RIGHT:
			text_right -= overlay_width + mImgOverlayLabelSpace;
			text_width -= overlay_width + mImgOverlayLabelSpace;
			mImageOverlay->draw(
				getRect().getWidth() - mRightHPad - overlay_width,
				center_y - (overlay_height / 2), 
				overlay_width, 
				overlay_height, 
				overlay_color);
			break;
		default:
			// draw nothing
			break;
		}
	}

	// Draw label
	if( !label.empty() )
	{
		LLWStringUtil::trim(label);

		S32 x;
		switch( mHAlign )
		{
		case LLFontGL::RIGHT:
			x = text_right;
			break;
		case LLFontGL::HCENTER:
			x = text_left + (text_width / 2);
			break;
		case LLFontGL::LEFT:
		default:
			x = text_left;
			break;
		}

		S32 y_offset = 2 + (getRect().getHeight() - 20)/2;
	
		if (pressed && mDisplayPressedState)
		{
			y_offset--;
			x++;
		}

		// *NOTE: mantipov: before mUseEllipses is implemented in EXT-279 U32_MAX has been passed as
		// max_chars.
		// LLFontGL::render expects S32 max_chars variable but process in a separate way -1 value.
		// Due to U32_MAX is equal to S32 -1 value I have rest this value for non-ellipses mode.
		// Not sure if it is really needed. Probably S32_MAX should be always passed as max_chars.
		mLastDrawCharsCount = mGLFont->render(label, 0,
			(F32)x,
			(F32)(getRect().getHeight() / 2 + mBottomVPad),
			label_color % alpha,
			mHAlign, LLFontGL::VCENTER,
			LLFontGL::NORMAL,
			mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW,
			S32_MAX, text_width,
			NULL, mUseEllipses);
	}

	// <FS:Zi> Add checkbox control toggle
	if(mCheckboxControlPanel)
	{
		mCheckboxControlPanel->setOrigin(0,0);
		mCheckboxControlPanel->reshape(getRect().getWidth(),getRect().getHeight());
		mCheckboxControlPanel->draw();
	}
	// <FS:Zi>

	LLUICtrl::draw();
}
	//virtual 
	virtual void uploadComplete(const LLSD& content)
	{
		LL_DEBUGS("ObjectBackup") << "LLNewAgentInventoryResponder::result from capabilities" << LL_ENDL;

		LLAssetType::EType asset_type = LLAssetType::lookup(mPostData["asset_type"].asString());
		LLInventoryType::EType inventory_type = LLInventoryType::lookup(mPostData["inventory_type"].asString());

		// Update L$ and ownership credit information
		// since it probably changed on the server
		if (asset_type == LLAssetType::AT_TEXTURE ||
			asset_type == LLAssetType::AT_SOUND ||
			asset_type == LLAssetType::AT_ANIMATION)
		{
			gMessageSystem->newMessageFast(_PREHASH_MoneyBalanceRequest);
			gMessageSystem->nextBlockFast(_PREHASH_AgentData);
			gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
			gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
			gMessageSystem->nextBlockFast(_PREHASH_MoneyData);
			gMessageSystem->addUUIDFast(_PREHASH_TransactionID, LLUUID::null );
			gAgent.sendReliableMessage();

//			LLStringUtil::format_map_t args;
//			args["[AMOUNT]"] = llformat("%d",LLGlobalEconomy::Singleton::getInstance()->getPriceUpload());
//			LLNotifyBox::showXml("UploadPayment", args);
		}

		// Actually add the upload to viewer inventory
		LL_INFOS("ObjectBackup") << "Adding " << content["new_inventory_item"].asUUID() << " "
				<< content["new_asset"].asUUID() << " to inventory." << LL_ENDL;
		if (mPostData["folder_id"].asUUID().notNull())
		{
			LLPermissions perm;
			U32 next_owner_perm;
			perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null);
			if (mPostData["inventory_type"].asString() == "snapshot")
			{
				next_owner_perm = PERM_ALL;
			}
			else
			{
				next_owner_perm = PERM_MOVE | PERM_TRANSFER;
			}
			perm.initMasks(PERM_ALL, PERM_ALL, PERM_NONE, PERM_NONE, next_owner_perm);
			S32 creation_date_now = time_corrected();
			LLPointer<LLViewerInventoryItem> item
				= new LLViewerInventoryItem(content["new_inventory_item"].asUUID(),
										mPostData["folder_id"].asUUID(),
										perm,
										content["new_asset"].asUUID(),
										asset_type,
										inventory_type,
										mPostData["name"].asString(),
										mPostData["description"].asString(),
										LLSaleInfo::DEFAULT,
										LLInventoryItemFlags::II_FLAGS_NONE,
										creation_date_now);
			gInventory.updateItem(item);
			gInventory.notifyObservers();
		}
		else
		{
			LL_WARNS("ObjectBackup") << "Can't find a folder to put it into" << LL_ENDL;
		}

		// remove the "Uploading..." message
		LLUploadDialog::modalUploadFinished();

		LLObjectBackup::getInstance()->updateMap(content["new_asset"].asUUID());
		LLObjectBackup::getInstance()->uploadNextAsset();
	}
bool FSFloaterObjectExport::exportTexture(const LLUUID& texture_id)
{
	if(texture_id.isNull())
	{
		LL_WARNS("export") << "Attempted to export NULL texture." << LL_ENDL;
		return false;
	}
	
	if (mTextureChecked.count(texture_id) != 0)
	{
		return mTextureChecked[texture_id];
	}
	
	if (gAssetStorage->mStaticVFS->getExists(texture_id, LLAssetType::AT_TEXTURE))
	{
		LL_DEBUGS("export") << "Texture " << texture_id.asString() << " is local static." << LL_ENDL;
		// no need to save the texture data as the viewer already has it in a local file.
		mTextureChecked[texture_id] = true;
		return true;
	}
	
	//TODO: check for local file static texture. The above will only get the static texture in the static db, not individual textures.

	LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(texture_id);
	bool texture_export = false;
	std::string name;
	std::string description;
	
	if (LLGridManager::getInstance()->isInSecondLife())
	{
		if (imagep->mComment.find("a") != imagep->mComment.end())
		{
			if (LLUUID(imagep->mComment["a"]) == gAgentID)
			{
				texture_export = true;
				LL_DEBUGS("export") << texture_id <<  " pass texture export comment check." << LL_ENDL;
			}
		}
	}

	if (texture_export)
	{
		FSExportPermsCheck::canExportAsset(texture_id, &name, &description);
	}
	else
	{
		texture_export = FSExportPermsCheck::canExportAsset(texture_id, &name, &description);
	}

	mTextureChecked[texture_id] = texture_export;
	
	if (!texture_export)
	{
		LL_DEBUGS("export") << "Texture " << texture_id << " failed export check." << LL_ENDL;
		return false;
	}

	LL_DEBUGS("export") << "Loading image texture " << texture_id << LL_ENDL;
	mRequestedTexture[texture_id].name = name;
	mRequestedTexture[texture_id].description = description;
	LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(texture_id, FTT_DEFAULT, MIPMAP_TRUE);
	image->setBoostLevel(LLViewerTexture::BOOST_MAX_LEVEL);
	image->forceToSaveRawImage(0);
	image->setLoadedCallback(FSFloaterObjectExport::onImageLoaded, 0, TRUE, FALSE, this, &mCallbackTextureList);

	return true;
}
void FSFloaterObjectExport::onIdle()
{
	switch(mExportState)
	{
	case IDLE:
		break;
	case INVENTORY_DOWNLOAD:
		if (gDisconnected)
		{
			return;
		}
		
		if (mInventoryRequests.empty())
		{
			mLastRequest = mAssetRequests.size();
			mWaitTimer.start();
			mExportState = ASSET_DOWNLOAD;
		}
		else if (mLastRequest != mInventoryRequests.size())
		{
			mWaitTimer.start();
			mLastRequest = mInventoryRequests.size();
			updateTitleProgress(INVENTORY_DOWNLOAD);
		}
		else if (mWaitTimer.getElapsedTimeF32() > MAX_INVENTORY_WAIT_TIME)
		{
			mWaitTimer.start();
			for (uuid_vec_t::const_iterator iter = mInventoryRequests.begin(); iter != mInventoryRequests.end(); ++iter)
			{
				LLViewerObject* object = gObjectList.findObject((*iter));
				object->dirtyInventory();
				object->requestInventory();
				
				LL_DEBUGS("export") << "re-requested inventory of " << (*iter).asString() << LL_ENDL;
			}
		}
		break;
	case ASSET_DOWNLOAD:
		if (gDisconnected)
		{
			return;
		}
		
		if (mAssetRequests.empty())
		{
			mLastRequest = mRequestedTexture.size();
			mWaitTimer.start();
			mExportState = TEXTURE_DOWNLOAD;
		}
		else if (mLastRequest != mAssetRequests.size())
		{
			mWaitTimer.start();
			mLastRequest = mAssetRequests.size();
			updateTitleProgress(ASSET_DOWNLOAD);
		}
		else if (mWaitTimer.getElapsedTimeF32() > MAX_ASSET_WAIT_TIME)
		{
			//abort for now
			LL_DEBUGS("export") << "Asset timeout with " << (S32)mAssetRequests.size() << " requests left." << LL_ENDL;
			for (uuid_vec_t::iterator iter = mAssetRequests.begin(); iter != mAssetRequests.end(); ++iter)
			{
				LL_DEBUGS("export") << "Asset: " << (*iter).asString() << LL_ENDL;
			}
			mAssetRequests.clear();
		}
		break;
	case TEXTURE_DOWNLOAD:
		if (gDisconnected)
		{
			return;
		}

		if(mRequestedTexture.empty())
		{
			mExportState = IDLE;
			if (!gIdleCallbacks.deleteFunction(onIdle, this))
			{
				LL_WARNS("export") << "Failed to delete idle callback" << LL_ENDL;
			}
			mWaitTimer.stop();

			llofstream file;
			file.open(mFilename.c_str(), std::ios_base::out | std::ios_base::binary);
			std::string zip_data = zip_llsd(mManifest);
			file.write(zip_data.data(), zip_data.size());
			file.close();
			LL_DEBUGS("export") << "Export finished and written to " << mFilename << LL_ENDL;
			
			LLSD args;
			args["FILENAME"] = mFilename;
			LLNotificationsUtil::add("ExportFinished", args);
			closeFloater();
		}
		else if (mLastRequest != mRequestedTexture.size())
		{
			mWaitTimer.start();
			mLastRequest = mRequestedTexture.size();
			updateTitleProgress(TEXTURE_DOWNLOAD);
		}
		else if (mWaitTimer.getElapsedTimeF32() > MAX_TEXTURE_WAIT_TIME)
		{
			mWaitTimer.start();
			for (std::map<LLUUID, FSAssetResourceData>::iterator iter = mRequestedTexture.begin(); iter != mRequestedTexture.end(); ++iter)
			{
				LLUUID texture_id = iter->first;
				LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(texture_id, FTT_DEFAULT, MIPMAP_TRUE);
				image->setBoostLevel(LLViewerTexture::BOOST_MAX_LEVEL);
				image->forceToSaveRawImage(0);
				image->setLoadedCallback(FSFloaterObjectExport::onImageLoaded, 0, TRUE, FALSE, this, &mCallbackTextureList);

				LL_DEBUGS("export") << "re-requested texture " << texture_id.asString() << LL_ENDL;
			}
		}
		break;
	default:
		break;
	}
}
void FSFloaterObjectExport::addPrim(LLViewerObject* object, bool root)
{
	LLSD prim;
	LLUUID object_id = object->getID();
	bool default_prim = true;

	struct f : public LLSelectedNodeFunctor
	{
		LLUUID mID;
		f(const LLUUID& id) : mID(id) {}
		virtual bool apply(LLSelectNode* node)
		{
			return (node->getObject() && node->getObject()->mID == mID);
		}
	} func(object_id);
	
	LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(&func);
	default_prim = (!FSExportPermsCheck::canExportNode(node, false));

	if (root)
	{
		if (object->isAttachment())
		{
			prim["attachment_point"] = ATTACHMENT_ID_FROM_STATE(object->getState());
		}
	}
	else
	{
		LLViewerObject* parent_object = (LLViewerObject*)object->getParent();
		prim["parent"] = parent_object->getID();
	}
	prim["position"] = object->getPosition().getValue();
	prim["scale"] = object->getScale().getValue();
	prim["rotation"] = ll_sd_from_quaternion(object->getRotation());

	if (default_prim)
	{
		LL_DEBUGS("export") << object_id.asString() << " failed export check. Using default prim" << LL_ENDL;
		prim["flags"] = ll_sd_from_U32((U32)0);
		prim["volume"]["path"] = LLPathParams().asLLSD();
		prim["volume"]["profile"] = LLProfileParams().asLLSD();
		prim["material"] = (S32)LL_MCODE_WOOD;
	}
	else
	{
		mExported = true;
		prim["flags"] = ll_sd_from_U32(object->getFlags());
		prim["volume"]["path"] = object->getVolume()->getParams().getPathParams().asLLSD();
		prim["volume"]["profile"] = object->getVolume()->getParams().getProfileParams().asLLSD();
		prim["material"] = (S32)object->getMaterial();
		if (object->getClickAction() != 0)
		{
			prim["clickaction"] = (S32)object->getClickAction();
		}

		LLVOVolume *volobjp = NULL;
		if (object->getPCode() == LL_PCODE_VOLUME)
		{
			volobjp = (LLVOVolume *)object;
		}
		if(volobjp)
		{
			if(volobjp->isSculpted())
			{
				const LLSculptParams *sculpt_params = (const LLSculptParams *)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
				if (sculpt_params)
				{
					if(volobjp->isMesh())
					{
						if (!mAborted)
						{
							mAborted = true;
						}
						return;
					}
					else
					{
						if (exportTexture(sculpt_params->getSculptTexture()))
						{
							prim["sculpt"] = sculpt_params->asLLSD();
						}
						else
						{
							LLSculptParams default_sculpt;
							prim["sculpt"] = default_sculpt.asLLSD();
						}
					}
				}
			}

			if(volobjp->isFlexible())
			{
				const LLFlexibleObjectData *flexible_param_block = (const LLFlexibleObjectData *)object->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE);
				if (flexible_param_block)
				{
					prim["flexible"] = flexible_param_block->asLLSD();
				}
			}

			if (volobjp->getIsLight())
			{
				const LLLightParams *light_param_block = (const LLLightParams *)object->getParameterEntry(LLNetworkData::PARAMS_LIGHT);
				if (light_param_block)
				{
					prim["light"] = light_param_block->asLLSD();
				}
			}

			if (volobjp->hasLightTexture())
			{
				const LLLightImageParams* light_image_param_block = (const LLLightImageParams*)object->getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
				if (light_image_param_block)
				{
					prim["light_texture"] = light_image_param_block->asLLSD();
				}
			}
			
		}

		if(object->isParticleSource())
		{
			LLViewerPartSourceScript* partSourceScript = object->getPartSourceScript();
			prim["particle"] = partSourceScript->mPartSysData.asLLSD();
			if (!exportTexture(partSourceScript->mPartSysData.mPartImageID))
			{
				prim["particle"]["PartImageID"] = LLUUID::null.asString();
			}
		}

		U8 texture_count = object->getNumTEs();
		for(U8 i = 0; i < texture_count; ++i)
		{
			LLTextureEntry *checkTE = object->getTE(i);
			LL_DEBUGS("export") << "Checking texture number " << (S32)i
				<< ", ID " << checkTE->getID() << LL_ENDL;
			if (FSCommon::isDefaultTexture(checkTE->getID()))	// <FS:CR> Check against default textures
			{
				LL_DEBUGS("export") << "...is a default texture." << LL_ENDL;
				prim["texture"].append(checkTE->asLLSD());
			}
			else if (exportTexture(checkTE->getID()))
			{
				LL_DEBUGS("export") << "...export check passed." << LL_ENDL;
				prim["texture"].append(checkTE->asLLSD());
			}
			else
			{
				LL_DEBUGS("export") << "...export check failed." << LL_ENDL;
				checkTE->setID(LL_DEFAULT_WOOD_UUID); // TODO: use user option of default texture.
				prim["texture"].append(checkTE->asLLSD());
			}
			
			// [FS:CR] Materials support
			if (checkTE->getMaterialParams().notNull())
			{
				LL_DEBUGS("export") << "found materials. Checking permissions..." << LL_ENDL;
				LLSD params = checkTE->getMaterialParams().get()->asLLSD();
				/// *TODO: Feeling lazy so I made it check both. This is incorrect and needs to be expanded
				/// to retain exportable textures not just failing both when one is non-exportable (or unset).
				if (exportTexture(params["NormMap"].asUUID()) &&
					exportTexture(params["SpecMap"].asUUID()))
				{
					LL_DEBUGS("export") << "...passed check." << LL_ENDL;
					prim["materials"].append(params);
				}
			}
		}

		if (!object->getPhysicsShapeUnknown())
		{
			prim["ExtraPhysics"]["PhysicsShapeType"] = (S32)object->getPhysicsShapeType();
			prim["ExtraPhysics"]["Density"] = (F64)object->getPhysicsDensity();
			prim["ExtraPhysics"]["Friction"] = (F64)object->getPhysicsFriction();
			prim["ExtraPhysics"]["Restitution"] = (F64)object->getPhysicsRestitution();
			prim["ExtraPhysics"]["GravityMultiplier"] = (F64)object->getPhysicsGravity();
		}

		prim["name"] = node->mName;
		prim["description"] = node->mDescription;
		prim["creation_date"] = ll_sd_from_U64(node->mCreationDate);

		LLAvatarName avatar_name;
		LLUUID creator_id = node->mPermissions->getCreator();
		if (creator_id.notNull())
		{
			prim["creator_id"] = creator_id;
			if (LLAvatarNameCache::get(creator_id, &avatar_name))
			{
				prim["creator_name"] = avatar_name.asLLSD();
			}
		}
		LLUUID owner_id = node->mPermissions->getOwner();
		if (owner_id.notNull())
		{
			prim["owner_id"] = owner_id;
			if (LLAvatarNameCache::get(owner_id, &avatar_name))
			{
				prim["owner_name"] = avatar_name.asLLSD();
			}
		}
		LLUUID group_id = node->mPermissions->getGroup();
		if (group_id.notNull())
		{
			prim["group_id"] = group_id;
			if (LLAvatarNameCache::get(group_id, &avatar_name))
			{
				prim["group_name"] = avatar_name.asLLSD();
			}
		}
		LLUUID last_owner_id = node->mPermissions->getLastOwner();
		if (last_owner_id.notNull())
		{
			prim["last_owner_id"] = last_owner_id;
			if (LLAvatarNameCache::get(last_owner_id, &avatar_name))
			{
				prim["last_owner_name"] = avatar_name.asLLSD();
			}
		}
		prim["base_mask"] = ll_sd_from_U32(node->mPermissions->getMaskBase());
		prim["owner_mask"] = ll_sd_from_U32(node->mPermissions->getMaskOwner());
		prim["group_mask"] = ll_sd_from_U32(node->mPermissions->getMaskGroup());
		prim["everyone_mask"] = ll_sd_from_U32(node->mPermissions->getMaskEveryone());
		prim["next_owner_mask"] = ll_sd_from_U32(node->mPermissions->getMaskNextOwner());
		
		prim["sale_info"] = node->mSaleInfo.asLLSD();
		prim["touch_name"] = node->mTouchName;
		prim["sit_name"] = node->mSitName;

		static LLCachedControl<bool> sExportContents(gSavedSettings, "FSExportContents");
		if (sExportContents)
		{
			mInventoryRequests.push_back(object_id);
			object->registerInventoryListener(this, NULL);
			object->dirtyInventory();
			object->requestInventory();
		}
	}

	mManifest["prim"][object_id.asString()] = prim;
}
// validate the certificate chain against a store.
// There are many aspects of cert validatioin policy involved in
// trust validation.  The policies in this validation algorithm include
// * Hostname matching for SSL certs
// * Expiration time matching
// * Signature validation
// * Chain trust (is the cert chain trusted against the store)
// * Basic constraints
// * key usage and extended key usage
// TODO: We should add 'authority key identifier' for chaining.
// This algorithm doesn't simply validate the chain by itself
// and verify the last cert is in the certificate store, or points
// to a cert in the store.  It validates whether any cert in the chain
// is trusted in the store, even if it's not the last one.
void LLBasicCertificateStore::validate(int validation_policy,
									   LLPointer<LLCertificateChain> cert_chain,
									   const LLSD& validation_params)
{
	// If --no-verify-ssl-cert was passed on the command line, stop right now.
	if (gSavedSettings.getBOOL("NoVerifySSLCert")) return;

	if(cert_chain->size() < 1)
	{
		throw LLCertException(NULL, "No certs in chain");
	}
	iterator current_cert = cert_chain->begin();
	LLSD 	current_cert_info;
	LLSD validation_date;
	if (validation_params.has(CERT_VALIDATION_DATE))
	{
		validation_date = validation_params[CERT_VALIDATION_DATE];
	}

	if (validation_policy & VALIDATION_POLICY_HOSTNAME)
	{
		(*current_cert)->getLLSD(current_cert_info);
		if(!validation_params.has(CERT_HOSTNAME))
		{
			throw LLCertException((*current_cert), "No hostname passed in for validation");			
		}
		if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info[CERT_SUBJECT_NAME].has(CERT_NAME_CN))
		{
			throw LLInvalidCertificate((*current_cert));				
		}
		
		LL_DEBUGS("SECAPI") << "Validating the hostname " << validation_params[CERT_HOSTNAME].asString() << 
		     "against the cert CN " << current_cert_info[CERT_SUBJECT_NAME][CERT_NAME_CN].asString() << LL_ENDL;
		if(!_cert_hostname_wildcard_match(validation_params[CERT_HOSTNAME].asString(),
										  current_cert_info[CERT_SUBJECT_NAME][CERT_NAME_CN].asString()))
		{
			throw LLCertValidationHostnameException(validation_params[CERT_HOSTNAME].asString(),
													(*current_cert));
		}
	}

	// check the cache of already validated certs
	X509* cert_x509 = (*current_cert)->getOpenSSLX509();
	if(!cert_x509)
	{
		throw LLInvalidCertificate((*current_cert));			
	}
	std::string sha1_hash((const char *)cert_x509->sha1_hash, SHA_DIGEST_LENGTH);
	t_cert_cache::iterator cache_entry = mTrustedCertCache.find(sha1_hash);
	if(cache_entry != mTrustedCertCache.end())
	{
		LL_DEBUGS("SECAPI") << "Found cert in cache" << LL_ENDL;	
		// this cert is in the cache, so validate the time.
		if (validation_policy & VALIDATION_POLICY_TIME)
		{
			LLDate validation_date(time(NULL));
			if(validation_params.has(CERT_VALIDATION_DATE))
			{
				validation_date = validation_params[CERT_VALIDATION_DATE];
			}
			
			if((validation_date < cache_entry->second.first) ||
			   (validation_date > cache_entry->second.second))
			{
				throw LLCertValidationExpirationException((*current_cert), validation_date);
			}
		}
		// successfully found in cache
		return;
	}
	if(current_cert_info.isUndefined())
	{
		(*current_cert)->getLLSD(current_cert_info);
	}
	LLDate from_time = current_cert_info[CERT_VALID_FROM].asDate();
	LLDate to_time = current_cert_info[CERT_VALID_TO].asDate();
	int depth = 0;
	LLPointer<LLCertificate> previous_cert;
	// loop through the cert chain, validating the current cert against the next one.
	while(current_cert != cert_chain->end())
	{
		
		int local_validation_policy = validation_policy;
		if(current_cert == cert_chain->begin())
		{
			// for the child cert, we don't validate CA stuff
			local_validation_policy &= ~(VALIDATION_POLICY_CA_KU | 
										 VALIDATION_POLICY_CA_BASIC_CONSTRAINTS);
		}
		else
		{
			// for non-child certs, we don't validate SSL Key usage
			local_validation_policy &= ~VALIDATION_POLICY_SSL_KU;				
			if(!_verify_signature((*current_cert),
								  previous_cert))
			{
			   throw LLCertValidationInvalidSignatureException(previous_cert);
			}
		}
		_validateCert(local_validation_policy,
					  (*current_cert),
					  validation_params,
					  depth);
		
		// look for a CA in the CA store that may belong to this chain.
		LLSD cert_search_params = LLSD::emptyMap();		
		// is the cert itself in the store?
		cert_search_params[CERT_SHA1_DIGEST] = current_cert_info[CERT_SHA1_DIGEST];
		LLCertificateStore::iterator found_store_cert = find(cert_search_params);
		if(found_store_cert != end())
		{
			mTrustedCertCache[sha1_hash] = std::pair<LLDate, LLDate>(from_time, to_time);
			return;
		}
		
		// is the parent in the cert store?
			
		cert_search_params = LLSD::emptyMap();
		cert_search_params[CERT_SUBJECT_NAME_STRING] = current_cert_info[CERT_ISSUER_NAME_STRING];
		if (current_cert_info.has(CERT_AUTHORITY_KEY_IDENTIFIER))
		{
			LLSD cert_aki = current_cert_info[CERT_AUTHORITY_KEY_IDENTIFIER];
			if(cert_aki.has(CERT_AUTHORITY_KEY_IDENTIFIER_ID))
			{
				cert_search_params[CERT_SUBJECT_KEY_IDENTFIER] = cert_aki[CERT_AUTHORITY_KEY_IDENTIFIER_ID];
			}
			if(cert_aki.has(CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL))
			{
				cert_search_params[CERT_SERIAL_NUMBER] = cert_aki[CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL];
			}
		}
		found_store_cert = find(cert_search_params);
		
		if(found_store_cert != end())
		{
			// validate the store cert against the depth
			_validateCert(validation_policy & VALIDATION_POLICY_CA_BASIC_CONSTRAINTS,
						  (*found_store_cert),
						  LLSD(),
						  depth);
			
			// verify the signature of the CA
			if(!_verify_signature((*found_store_cert),
								  (*current_cert)))
			{
				throw LLCertValidationInvalidSignatureException(*current_cert);
			}			
			// successfully validated.
			mTrustedCertCache[sha1_hash] = std::pair<LLDate, LLDate>(from_time, to_time);		
			return;
		}
		previous_cert = (*current_cert);
		current_cert++;
		depth++;
		if(current_cert != cert_chain->end())
		{
			(*current_cert)->getLLSD(current_cert_info);
		}
	}
	if (validation_policy & VALIDATION_POLICY_TRUSTED)
	{
		// we reached the end without finding a trusted cert.
		throw LLCertValidationTrustException((*cert_chain)[cert_chain->size()-1]);

	}
	mTrustedCertCache[sha1_hash] = std::pair<LLDate, LLDate>(from_time, to_time);	
}
Example #14
0
//--------------------------------------------------------------------
// LLPolyMeshSharedData::loadMesh()
//--------------------------------------------------------------------
BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName )
{
        //-------------------------------------------------------------------------
        // Open the file
        //-------------------------------------------------------------------------
        if(fileName.empty())
        {
                LL_ERRS() << "Filename is Empty!" << LL_ENDL;
                return FALSE;
        }
        LLFILE* fp = LLFile::fopen(fileName, "rb");                     /*Flawfinder: ignore*/
        if (!fp)
        {
                LL_ERRS() << "can't open: " << fileName << LL_ENDL;
                return FALSE;
        }

        //-------------------------------------------------------------------------
        // Read a chunk
        //-------------------------------------------------------------------------
        char header[128];               /*Flawfinder: ignore*/
        if (fread(header, sizeof(char), 128, fp) != 128)
        {
                LL_WARNS() << "Short read" << LL_ENDL;
        }

        //-------------------------------------------------------------------------
        // Check for proper binary header
        //-------------------------------------------------------------------------
        BOOL status = FALSE;
        if ( strncmp(header, HEADER_BINARY, strlen(HEADER_BINARY)) == 0 )       /*Flawfinder: ignore*/
        {
                LL_DEBUGS() << "Loading " << fileName << LL_ENDL;

                //----------------------------------------------------------------
                // File Header (seek past it)
                //----------------------------------------------------------------
                fseek(fp, 24, SEEK_SET);

                //----------------------------------------------------------------
                // HasWeights
                //----------------------------------------------------------------
                U8 hasWeights;
                size_t numRead = fread(&hasWeights, sizeof(U8), 1, fp);
                if (numRead != 1)
                {
                        LL_ERRS() << "can't read HasWeights flag from " << fileName << LL_ENDL;
                        return FALSE;
                }
                if (!isLOD())
                {
                        mHasWeights = (hasWeights==0) ? FALSE : TRUE;
                }

                //----------------------------------------------------------------
                // HasDetailTexCoords
                //----------------------------------------------------------------
                U8 hasDetailTexCoords;
                numRead = fread(&hasDetailTexCoords, sizeof(U8), 1, fp);
                if (numRead != 1)
                {
                        LL_ERRS() << "can't read HasDetailTexCoords flag from " << fileName << LL_ENDL;
                        return FALSE;
                }

                //----------------------------------------------------------------
                // Position
                //----------------------------------------------------------------
                LLVector3 position;
                numRead = fread(position.mV, sizeof(float), 3, fp);
                llendianswizzle(position.mV, sizeof(float), 3);
                if (numRead != 3)
                {
                        LL_ERRS() << "can't read Position from " << fileName << LL_ENDL;
                        return FALSE;
                }
                setPosition( position );

                //----------------------------------------------------------------
                // Rotation
                //----------------------------------------------------------------
                LLVector3 rotationAngles;
                numRead = fread(rotationAngles.mV, sizeof(float), 3, fp);
                llendianswizzle(rotationAngles.mV, sizeof(float), 3);
                if (numRead != 3)
                {
                        LL_ERRS() << "can't read RotationAngles from " << fileName << LL_ENDL;
                        return FALSE;
                }

                U8 rotationOrder;
                numRead = fread(&rotationOrder, sizeof(U8), 1, fp);

                if (numRead != 1)
                {
                        LL_ERRS() << "can't read RotationOrder from " << fileName << LL_ENDL;
                        return FALSE;
                }

                rotationOrder = 0;

                setRotation( mayaQ(     rotationAngles.mV[0],
                                        rotationAngles.mV[1],
                                        rotationAngles.mV[2],
                                        (LLQuaternion::Order)rotationOrder ) );

                //----------------------------------------------------------------
                // Scale
                //----------------------------------------------------------------
                LLVector3 scale;
                numRead = fread(scale.mV, sizeof(float), 3, fp);
                llendianswizzle(scale.mV, sizeof(float), 3);
                if (numRead != 3)
                {
                        LL_ERRS() << "can't read Scale from " << fileName << LL_ENDL;
                        return FALSE;
                }
                setScale( scale );

                //-------------------------------------------------------------------------
                // Release any existing mesh geometry
                //-------------------------------------------------------------------------
                freeMeshData();

                U16 numVertices = 0;

                //----------------------------------------------------------------
                // NumVertices
                //----------------------------------------------------------------
                if (!isLOD())
                {
                        numRead = fread(&numVertices, sizeof(U16), 1, fp);
                        llendianswizzle(&numVertices, sizeof(U16), 1);
                        if (numRead != 1)
                        {
                                LL_ERRS() << "can't read NumVertices from " << fileName << LL_ENDL;
                                return FALSE;
                        }

                        allocateVertexData( numVertices );      

						for (U16 i = 0; i < numVertices; ++i)
						{
							//----------------------------------------------------------------
							// Coords
							//----------------------------------------------------------------
							numRead = fread(&mBaseCoords[i], sizeof(float), 3, fp);
							llendianswizzle(&mBaseCoords[i], sizeof(float), 3);
							if (numRead != 3)
							{
									LL_ERRS() << "can't read Coordinates from " << fileName << LL_ENDL;
									return FALSE;
							}
						}

						for (U16 i = 0; i < numVertices; ++i)
						{
							//----------------------------------------------------------------
							// Normals
							//----------------------------------------------------------------
							numRead = fread(&mBaseNormals[i], sizeof(float), 3, fp);
							llendianswizzle(&mBaseNormals[i], sizeof(float), 3);
							if (numRead != 3)
							{
									LL_ERRS() << " can't read Normals from " << fileName << LL_ENDL;
									return FALSE;
							}
						}

						for (U16 i = 0; i < numVertices; ++i)
						{
							//----------------------------------------------------------------
							// Binormals
							//----------------------------------------------------------------
							numRead = fread(&mBaseBinormals[i], sizeof(float), 3, fp);
							llendianswizzle(&mBaseBinormals[i], sizeof(float), 3);
							if (numRead != 3)
							{
									LL_ERRS() << " can't read Binormals from " << fileName << LL_ENDL;
									return FALSE;
							}
						}

                        //----------------------------------------------------------------
                        // TexCoords
                        //----------------------------------------------------------------
                        numRead = fread(mTexCoords, 2*sizeof(float), numVertices, fp);
                        llendianswizzle(mTexCoords, sizeof(float), 2*numVertices);
                        if (numRead != numVertices)
                        {
                                LL_ERRS() << "can't read TexCoords from " << fileName << LL_ENDL;
                                return FALSE;
                        }

                        //----------------------------------------------------------------
                        // DetailTexCoords
                        //----------------------------------------------------------------
                        if (mHasDetailTexCoords)
                        {
                                numRead = fread(mDetailTexCoords, 2*sizeof(float), numVertices, fp);
                                llendianswizzle(mDetailTexCoords, sizeof(float), 2*numVertices);
                                if (numRead != numVertices)
                                {
                                        LL_ERRS() << "can't read DetailTexCoords from " << fileName << LL_ENDL;
                                        return FALSE;
                                }
                        }

                        //----------------------------------------------------------------
                        // Weights
                        //----------------------------------------------------------------
                        if (mHasWeights)
                        {
                                numRead = fread(mWeights, sizeof(float), numVertices, fp);
                                llendianswizzle(mWeights, sizeof(float), numVertices);
                                if (numRead != numVertices)
                                {
                                        LL_ERRS() << "can't read Weights from " << fileName << LL_ENDL;
                                        return FALSE;
                                }
                        }
                }

                //----------------------------------------------------------------
                // NumFaces
                //----------------------------------------------------------------
                U16 numFaces;
                numRead = fread(&numFaces, sizeof(U16), 1, fp);
                llendianswizzle(&numFaces, sizeof(U16), 1);
                if (numRead != 1)
                {
                        LL_ERRS() << "can't read NumFaces from " << fileName << LL_ENDL;
                        return FALSE;
                }
                allocateFaceData( numFaces );


                //----------------------------------------------------------------
                // Faces
                //----------------------------------------------------------------
                U32 i;
                U32 numTris = 0;
                for (i = 0; i < numFaces; i++)
                {
                        S16 face[3];
                        numRead = fread(face, sizeof(U16), 3, fp);
                        llendianswizzle(face, sizeof(U16), 3);
                        if (numRead != 3)
                        {
                                LL_ERRS() << "can't read Face[" << i << "] from " << fileName << LL_ENDL;
                                return FALSE;
                        }
                        if (mReferenceData)
                        {
                                llassert(face[0] < mReferenceData->mNumVertices);
                                llassert(face[1] < mReferenceData->mNumVertices);
                                llassert(face[2] < mReferenceData->mNumVertices);
                        }
                        
                        if (isLOD())
                        {
                                // store largest index in case of LODs
                                for (S32 j = 0; j < 3; j++)
                                {
                                        if (face[j] > mNumVertices - 1)
                                        {
                                                mNumVertices = face[j] + 1;
                                        }
                                }
                        }
                        mFaces[i][0] = face[0];
                        mFaces[i][1] = face[1];
                        mFaces[i][2] = face[2];

//                      S32 j;
//                      for(j = 0; j < 3; j++)
//                      {
//                              std::vector<S32> *face_list = mVertFaceMap.getIfThere(face[j]);
//                              if (!face_list)
//                              {
//                                      face_list = new std::vector<S32>;
//                                      mVertFaceMap.addData(face[j], face_list);
//                              }
//                              face_list->put(i);
//                      }

                        numTris++;
                }

                LL_DEBUGS() << "verts: " << numVertices 
                         << ", faces: "   << numFaces
                         << ", tris: "    << numTris
                         << LL_ENDL;

                //----------------------------------------------------------------
                // NumSkinJoints
                //----------------------------------------------------------------
                if (!isLOD())
                {
                        U16 numSkinJoints = 0;
                        if ( mHasWeights )
                        {
                                numRead = fread(&numSkinJoints, sizeof(U16), 1, fp);
                                llendianswizzle(&numSkinJoints, sizeof(U16), 1);
                                if (numRead != 1)
                                {
                                        LL_ERRS() << "can't read NumSkinJoints from " << fileName << LL_ENDL;
                                        return FALSE;
                                }
                                allocateJointNames( numSkinJoints );
                        }

                        //----------------------------------------------------------------
                        // SkinJoints
                        //----------------------------------------------------------------
                        for (i=0; i < numSkinJoints; i++)
                        {
                                char jointName[64+1];
                                numRead = fread(jointName, sizeof(jointName)-1, 1, fp);
                                jointName[sizeof(jointName)-1] = '\0'; // ensure nul-termination
                                if (numRead != 1)
                                {
                                        LL_ERRS() << "can't read Skin[" << i << "].Name from " << fileName << LL_ENDL;
                                        return FALSE;
                                }

                                std::string *jn = &mJointNames[i];
                                *jn = jointName;
                        }

                        //-------------------------------------------------------------------------
                        // look for morph section
                        //-------------------------------------------------------------------------
                        char morphName[64+1];
                        morphName[sizeof(morphName)-1] = '\0'; // ensure nul-termination
                        while(fread(&morphName, sizeof(char), 64, fp) == 64)
                        {
                                if (!strcmp(morphName, "End Morphs"))
                                {
                                        // we reached the end of the morphs
                                        break;
                                }
                                LLPolyMorphData* morph_data = new LLPolyMorphData(std::string(morphName));

                                BOOL result = morph_data->loadBinary(fp, this);

                                if (!result)
                                {
                                        delete morph_data;
                                        continue;
                                }

                                mMorphData.insert(morph_data);

                                if (!strcmp(morphName, "Breast_Female_Cleavage"))
                                {
                                        mMorphData.insert(clone_morph_param_cleavage(morph_data,
                                                                                     .75f,
                                                                                     "Breast_Physics_LeftRight_Driven"));
                                }

                                if (!strcmp(morphName, "Breast_Female_Cleavage"))
                                {
                                        mMorphData.insert(clone_morph_param_duplicate(morph_data,
										      "Breast_Physics_InOut_Driven"));
                                }
                                if (!strcmp(morphName, "Breast_Gravity"))
                                {
                                        mMorphData.insert(clone_morph_param_duplicate(morph_data,
										      "Breast_Physics_UpDown_Driven"));
                                }

                                if (!strcmp(morphName, "Big_Belly_Torso"))
                                {
                                        mMorphData.insert(clone_morph_param_direction(morph_data,
										      LLVector3(0,0,0.05f),
										      "Belly_Physics_Torso_UpDown_Driven"));
                                }

                                if (!strcmp(morphName, "Big_Belly_Legs"))
                                {
                                        mMorphData.insert(clone_morph_param_direction(morph_data,
										      LLVector3(0,0,0.05f),
										      "Belly_Physics_Legs_UpDown_Driven"));
                                }

                                if (!strcmp(morphName, "skirt_belly"))
                                {
                                        mMorphData.insert(clone_morph_param_direction(morph_data,
										      LLVector3(0,0,0.05f),
										      "Belly_Physics_Skirt_UpDown_Driven"));
                                }

                                if (!strcmp(morphName, "Small_Butt"))
                                {
                                        mMorphData.insert(clone_morph_param_direction(morph_data,
										      LLVector3(0,0,0.05f),
										      "Butt_Physics_UpDown_Driven"));
                                }
                                if (!strcmp(morphName, "Small_Butt"))
                                {
                                        mMorphData.insert(clone_morph_param_direction(morph_data,
										      LLVector3(0,0.03f,0),
										      "Butt_Physics_LeftRight_Driven"));
                                }
                        }

                        S32 numRemaps;
                        if (fread(&numRemaps, sizeof(S32), 1, fp) == 1)
                        {
                                llendianswizzle(&numRemaps, sizeof(S32), 1);
                                for (S32 i = 0; i < numRemaps; i++)
                                {
                                        S32 remapSrc;
                                        S32 remapDst;
                                        if (fread(&remapSrc, sizeof(S32), 1, fp) != 1)
                                        {
                                                LL_ERRS() << "can't read source vertex in vertex remap data" << LL_ENDL;
                                                break;
                                        }
                                        if (fread(&remapDst, sizeof(S32), 1, fp) != 1)
                                        {
                                                LL_ERRS() << "can't read destination vertex in vertex remap data" << LL_ENDL;
                                                break;
                                        }
                                        llendianswizzle(&remapSrc, sizeof(S32), 1);
                                        llendianswizzle(&remapDst, sizeof(S32), 1);

                                        mSharedVerts[remapSrc] = remapDst;
                                }
                        }
                }

                status = TRUE;
        }
        else
        {
                LL_ERRS() << "invalid mesh file header: " << fileName << LL_ENDL;
                status = FALSE;
        }

        if (0 == mNumJointNames)
        {
                allocateJointNames(1);
        }

        fclose( fp );

        return status;
}
void LLMaterialMgr::onGetAllResponse(bool success, const LLSD& content, const LLUUID& region_id)
{
	if (!success)
	{
		// *TODO: is there any kind of error handling we can do here?
		LL_WARNS("Materials")<< "failed"<<LL_ENDL;
		return;
	}

	llassert(content.isMap());
	llassert(content.has(MATERIALS_CAP_ZIP_FIELD));
	llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary());

	LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();
	std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size());
	std::istringstream content_stream(content_string);

	LLSD response_data;
	if (!unzip_llsd(response_data, content_stream, content_binary.size()))
	{
		LL_WARNS("Materials") << "Cannot unzip LLSD binary content" << LL_ENDL;
		return;
	}

	get_queue_t::iterator itQueue = mGetQueue.find(region_id);
	material_map_t materials;

	llassert(response_data.isArray());
	LL_DEBUGS("Materials") << "response has "<< response_data.size() << " materials" << LL_ENDL;
	for (LLSD::array_const_iterator itMaterial = response_data.beginArray(); itMaterial != response_data.endArray(); ++itMaterial)
	{
		const LLSD& material_data = *itMaterial;
		llassert(material_data.isMap());

		llassert(material_data.has(MATERIALS_CAP_OBJECT_ID_FIELD));
		llassert(material_data[MATERIALS_CAP_OBJECT_ID_FIELD].isBinary());
		LLMaterialID material_id(material_data[MATERIALS_CAP_OBJECT_ID_FIELD].asBinary());
		if (mGetQueue.end() != itQueue)
		{
			itQueue->second.erase(material_id);
		}

		llassert(material_data.has(MATERIALS_CAP_MATERIAL_FIELD));
		llassert(material_data[MATERIALS_CAP_MATERIAL_FIELD].isMap());
		LLMaterialPtr material = setMaterial(region_id, material_id, material_data[MATERIALS_CAP_MATERIAL_FIELD]);
		
		materials[material_id] = material;
	}

	getall_callback_map_t::iterator itCallback = mGetAllCallbacks.find(region_id);
	if (itCallback != mGetAllCallbacks.end())
	{
		(*itCallback->second)(region_id, materials);

		delete itCallback->second;
		mGetAllCallbacks.erase(itCallback);
	}

	if ( (mGetQueue.end() != itQueue) && (itQueue->second.empty()) )
	{
		mGetQueue.erase(itQueue);
	}

	LL_DEBUGS("Materials")<< "recording that getAll has been done for region id " << region_id << LL_ENDL;	
	mGetAllRequested.insert(region_id); // prevents subsequent getAll requests for this region
	mGetAllPending.erase(region_id);	// Invalidates region_id
}
void LLInventoryPanel::buildNewViews(const LLUUID& id)
{
	LLFolderViewItem* itemp = NULL;
	LLInventoryObject* objectp = gInventory.getObject(id);

	if (objectp)
	{		
		if (objectp->getType() <= LLAssetType::AT_NONE ||
			objectp->getType() >= LLAssetType::AT_COUNT)
		{
			LL_DEBUGS("Inventory") << "LLInventoryPanel::buildNewViews called with objectp->mType == " 
				<< ((S32) objectp->getType())
				<< " (shouldn't happen)" << LL_ENDL;
		}
		else if (objectp->getType() == LLAssetType::AT_CATEGORY) // build new view for category
		{
			LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(objectp->getType(),
													LLInventoryType::IT_CATEGORY,
													this,
													objectp->getUUID());

			if (new_listener)
			{
				LLFolderViewFolder* folderp = new LLFolderViewFolder(new_listener->getDisplayName(),
													new_listener->getIcon(),
													mFolders,
													new_listener);
				
				folderp->setItemSortOrder(mFolders->getSortOrder());
				itemp = folderp;
			}
		}
		else // build new view for item
		{
			LLInventoryItem* item = (LLInventoryItem*)objectp;
			LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(
				item->getType(),
				item->getInventoryType(),
				this,
				item->getUUID(),
				item->getFlags());
			if (new_listener)
			{
				itemp = new LLFolderViewItem(new_listener->getDisplayName(),
												new_listener->getIcon(),
												new_listener->getCreationDate(),
												mFolders,
												new_listener);
			}
		}

		LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)mFolders->getItemByID(objectp->getParentUUID());

		if (itemp)
		{
			if (parent_folder)
			{
				itemp->addToFolder(parent_folder, mFolders);
			}
			else
			{
				llwarns << "Couldn't find parent folder for child " << itemp->getLabel() << llendl;
				delete itemp;
			}
		}
	}

	if ((id.isNull() ||
		(objectp && objectp->getType() == LLAssetType::AT_CATEGORY)))
	{
		LLViewerInventoryCategory::cat_array_t* categories;
		LLViewerInventoryItem::item_array_t* items;

		mInventory->lockDirectDescendentArrays(id, categories, items);
		if(categories)
		{
			S32 count = categories->count();
			for(S32 i = 0; i < count; ++i)
			{
				LLInventoryCategory* cat = categories->get(i);
				buildNewViews(cat->getUUID());
			}
		}
		if(items)
		{
			S32 count = items->count();
			for(S32 i = 0; i < count; ++i)
			{
				LLInventoryItem* item = items->get(i);
				buildNewViews(item->getUUID());
			}
		}
		mInventory->unlockDirectDescendentArrays(id);
	}
}
void LLMaterialMgr::processGetQueue()
{
	get_queue_t::iterator loopRegionQueue = mGetQueue.begin();
	while (mGetQueue.end() != loopRegionQueue)
	{
		get_queue_t::iterator itRegionQueue = loopRegionQueue++;

		const LLUUID& region_id = itRegionQueue->first;
		if (isGetAllPending(region_id))
		{
			continue;
		}

		LLViewerRegion* regionp = LLWorld::instance().getRegionFromID(region_id);
		if (!regionp)
		{
			LL_WARNS("Materials") << "Unknown region with id " << region_id.asString() << LL_ENDL;
			mGetQueue.erase(itRegionQueue);
			continue;
		}
		else if (!regionp->capabilitiesReceived() || regionp->materialsCapThrottled())
		{
			continue;
		}
		else if (mGetAllRequested.end() == mGetAllRequested.find(region_id))
		{
			LL_DEBUGS("Materials") << "calling getAll for " << regionp->getName() << LL_ENDL;
			getAll(region_id);
			continue;
		}

		const std::string capURL = regionp->getCapability(MATERIALS_CAPABILITY_NAME);
		if (capURL.empty())
		{
			LL_WARNS("Materials") << "Capability '" << MATERIALS_CAPABILITY_NAME
				<< "' is not defined on region '" << regionp->getName() << "'" << LL_ENDL;
			mGetQueue.erase(itRegionQueue);
			continue;
		}

		LLSD materialsData = LLSD::emptyArray();

		material_queue_t& materials = itRegionQueue->second;
		U32 max_entries = regionp->getMaxMaterialsPerTransaction();
		material_queue_t::iterator loopMaterial = materials.begin();
		while ( (materials.end() != loopMaterial) && (materialsData.size() < (int)max_entries) )
		{
			material_queue_t::iterator itMaterial = loopMaterial++;
			materialsData.append((*itMaterial).asLLSD());
			materials.erase(itMaterial);
			markGetPending(region_id, *itMaterial);
		}
		if (materials.empty())
		{
			mGetQueue.erase(itRegionQueue);
		}
		
		std::string materialString = zip_llsd(materialsData);

		S32 materialSize = materialString.size();
		if (materialSize <= 0)
		{
			LL_ERRS("Materials") << "cannot zip LLSD binary content" << LL_ENDL;
			return;
		}

		LLSD::Binary materialBinary;
		materialBinary.resize(materialSize);
		memcpy(materialBinary.data(), materialString.data(), materialSize);

		LLSD postData = LLSD::emptyMap();
		postData[MATERIALS_CAP_ZIP_FIELD] = materialBinary;

		LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("POST", capURL, boost::bind(&LLMaterialMgr::onGetResponse, this, _1, _2, region_id));
		LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '"<< capURL << " for " << materialsData.size() << " materials." 
			<< "\ndata: " << ll_pretty_print_sd(materialsData) << LL_ENDL;
		LLHTTPClient::post(capURL, postData, materialsResponder);
		regionp->resetMaterialsCapThrottle();
	}
}
//
// LLGridManager::initialze - initialize the list of known grids based
// on the fixed list of linden grids (fixed for security reasons)
// the grids.xml file
// and the command line.
void LLGridManager::initialize(const std::string& grid_file)
{
	// default grid list.
	// Don't move to a modifiable file for security reasons,
	mGrid.clear() ;
	// set to undefined
	mGridList = LLSD();
	mGridFile = grid_file;
	// as we don't want an attacker to override our grid list
	// to point the default grid to an invalid grid
	addSystemGrid("None", "", "", "", DEFAULT_LOGIN_PAGE);
	


  	addSystemGrid("Agni",                                                                                             
				  MAINGRID,                                               
				  "https://login.agni.lindenlab.com/cgi-bin/login.cgi",                    
				  "https://secondlife.com/helpers/",     
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Aditi",                                                                                             
				  "util.aditi.lindenlab.com",                                              
				  "https://login.aditi.lindenlab.com/cgi-bin/login.cgi",                   
				  "http://aditi-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Aruna",                                                                                            
				  "util.aruna.lindenlab.com",                                              
				  "https://login.aruna.lindenlab.com/cgi-bin/login.cgi",                   
				  "http://aruna-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Bharati",                                                                                            
				  "util.bharati.lindenlab.com",                                              
				  "https://login.bharati.lindenlab.com/cgi-bin/login.cgi",                   
				  "http://bharati-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Chandra",                                                                                            
				  "util.chandra.lindenlab.com",                                              
				  "https://login.chandra.lindenlab.com/cgi-bin/login.cgi",                   
				  "http://chandra-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Damballah",                                                                                            
				  "util.damballah.lindenlab.com",                                              
				  "https://login.damballah.lindenlab.com/cgi-bin/login.cgi",                   
				  "http://damballah-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Danu",                                                                                            
				  "util.danu.lindenlab.com",                                              
				  "https://login.danu.lindenlab.com/cgi-bin/login.cgi",                   
				  "http://danu-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Durga",                                                                                            
				  "util.durga.lindenlab.com",                                              
				  "https://login.durga.lindenlab.com/cgi-bin/login.cgi",                   
				  "http://durga-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Ganga",                                                                                            
				  "util.ganga.lindenlab.com",                                              
				  "https://login.ganga.lindenlab.com/cgi-bin/login.cgi",                   
				  "http://ganga-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Mitra",                                                                                            
				  "util.mitra.lindenlab.com",                                              
				  "https://login.mitra.lindenlab.com/cgi-bin/login.cgi",                   
				  "http://mitra-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Mohini",                                                                                           
				  "util.mohini.lindenlab.com",                                             
				  "https://login.mohini.lindenlab.com/cgi-bin/login.cgi",                  
				  "http://mohini-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Nandi",                                                                                            
				  "util.nandi.lindenlab.com",                                              
				  "https://login.nandi.lindenlab.com/cgi-bin/login.cgi",                   
				  "http://nandi-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Parvati",                                                                                            
				  "util.parvati.lindenlab.com",                                              
				  "https://login.parvati.lindenlab.com/cgi-bin/login.cgi",                   
				  "http://parvati-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Radha",                                                                                            
				  "util.radha.lindenlab.com",                                              
				  "https://login.radha.lindenlab.com/cgi-bin/login.cgi",                   
				  "http://radha-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Ravi",                                                                                             
				  "util.ravi.lindenlab.com",                                               
				  "https://login.ravi.lindenlab.com/cgi-bin/login.cgi",                    
				  "http://ravi-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Siva",                                                                                             
				  "util.siva.lindenlab.com",                                               
				  "https://login.siva.lindenlab.com/cgi-bin/login.cgi",                    
				  "http://siva-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Shakti",                                                                                           
				  "util.shakti.lindenlab.com",                                             
				  "https://login.shakti.lindenlab.com/cgi-bin/login.cgi",                  
				  "http://shakti-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Soma",                                                                                             
				  "util.soma.lindenlab.com",                                               
				  "https://login.soma.lindenlab.com/cgi-bin/login.cgi",                    
				  "http://soma-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Uma",                                                                                              
				  "util.uma.lindenlab.com",                                                
				  "https://login.uma.lindenlab.com/cgi-bin/login.cgi",                     
				  "http://uma-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Vaak",                                                                                             
				  "util.vaak.lindenlab.com",                                               
				  "https://login.vaak.lindenlab.com/cgi-bin/login.cgi",                    
				  "http://vaak-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Yami",                                                                                             
				  "util.yami.lindenlab.com",                                               
				  "https://login.yami.lindenlab.com/cgi-bin/login.cgi",                    
				  "http://yami-secondlife.webdev.lindenlab.com/helpers/",
				  DEFAULT_LOGIN_PAGE);
	addSystemGrid("Local (Linden)",                                                                                    
				  "localhost",                                                             
				  "https://login.dmz.lindenlab.com/cgi-bin/login.cgi",                     
				  "",
				  DEFAULT_LOGIN_PAGE); 

	
	LLSD other_grids;
	llifstream llsd_xml;
	if (!grid_file.empty())
	{
		llsd_xml.open( grid_file.c_str(), std::ios::in | std::ios::binary );

		// parse through the gridfile, inserting grids into the list unless
		// they overwrite a linden grid.
		if( llsd_xml.is_open()) 
		{
			LLSDSerialize::fromXMLDocument( other_grids, llsd_xml );
			if(other_grids.isMap())
			{
				for(LLSD::map_iterator grid_itr = other_grids.beginMap(); 
					grid_itr != other_grids.endMap();
					++grid_itr)
				{
					LLSD::String key_name = grid_itr->first;
					LLSD grid = grid_itr->second;
					// TODO:  Make sure gridfile specified label is not 
					// a system grid label
					LL_DEBUGS("GridManager") << "reading: " << key_name << LL_ENDL;
					if (mGridList.has(key_name) &&
						mGridList[key_name].has(GRID_IS_SYSTEM_GRID_VALUE))
					{
						LL_DEBUGS("GridManager") << "Cannot override grid " << key_name << " as it's a system grid" << LL_ENDL;
						// If the system grid does exist in the grids file, and it's marked as a favorite, set it as a favorite.
						if(grid_itr->second.has(GRID_IS_FAVORITE_VALUE) && grid_itr->second[GRID_IS_FAVORITE_VALUE].asBoolean() )
						{
							mGridList[key_name][GRID_IS_FAVORITE_VALUE] = TRUE;
						}
					}
					else
					{
						try
						{
							addGrid(grid);
							LL_DEBUGS("GridManager") << "Added grid: " << key_name << LL_ENDL;
						}
						catch (...)
						{
						}
					}
				}
				llsd_xml.close();
			}	
		}     
	}
	
	// load a grid from the command line.
	// if the actual grid name is specified from the command line,
	// set it as the 'selected' grid.
	std::string cmd_line_grid = gSavedSettings.getString("CmdLineGridChoice");
	if(!cmd_line_grid.empty())
	{
		// try to find the grid assuming the command line parameter is
		// the case-insensitive 'label' of the grid.  ie 'Agni'
		mGrid = getGridByLabel(cmd_line_grid);
		if(mGrid.empty())
		{
			// if we couldn't find it, assume the
			// requested grid is the actual grid 'name' or index,
			// which would be the dns name of the grid (for non
			// linden hosted grids)
			// If the grid isn't there, that's ok, as it will be
			// automatically added later.
			mGrid = cmd_line_grid;
		}
		
	}
	else
	{
		// if a grid was not passed in via the command line, grab it from the CurrentGrid setting.
		// if there's no current grid, that's ok as it'll be either set by the value passed
		// in via the login uri if that's specified, or will default to maingrid
		mGrid = gSavedSettings.getString("CurrentGrid");
	}
	
	if(mGrid.empty())
	{
		// no grid was specified so default to maingrid
		LL_DEBUGS("GridManager") << "Setting grid to MAINGRID as no grid has been specified " << LL_ENDL;
		mGrid = MAINGRID;
		
	}
	
	// generate a 'grid list' entry for any command line parameter overrides
	// or setting overides that we'll add to the grid list or override
	// any grid list entries with.
	LLSD grid = LLSD::emptyMap();	
	
	if(mGridList.has(mGrid))
	{
		grid = mGridList[mGrid];
	}
	else
	{
		grid[GRID_VALUE] = mGrid;
		// add the grid with the additional values, or update the
		// existing grid if it exists with the given values
		addGrid(grid);		
	}

	LLControlVariablePtr grid_control = gSavedSettings.getControl("CurrentGrid");
	if (grid_control.notNull())
	{
		grid_control->getSignal()->connect(boost::bind(&LLGridManager::updateIsInProductionGrid, this));
	}

	// since above only triggers on changes, trigger the callback manually to initialize state
	updateIsInProductionGrid();

	LL_DEBUGS("GridManager") << "Selected grid is " << mGrid << LL_ENDL;		
	setGridChoice(mGrid);
	if(mGridList[mGrid][GRID_LOGIN_URI_VALUE].isArray())
	{
		llinfos << "is array" << llendl;
	}
}
void LLMaterialsResponder::httpSuccess(void)
{
	LL_DEBUGS("Materials") << LL_ENDL;
	mCallback(true, mContent);
}
Example #20
0
void LLAssetStorage::setUpstream(const LLHost &upstream_host)
{
	LL_DEBUGS("AppInit") << "AssetStorage: Setting upstream provider to " << upstream_host << LL_ENDL;
	
	mUpstreamHost = upstream_host;
}
Example #21
0
void LLIMInfo::packInstantMessage(LLMessageSystem* msg) const
{
	LL_DEBUGS() << "LLIMInfo::packInstantMessage()" << LL_ENDL;
	msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
	packMessageBlock(msg);
}
Example #22
0
// IW - uuid is passed by value to avoid side effects, please don't re-add &    
void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LLGetAssetCallback callback, void *user_data, BOOL is_priority)
{
	LL_DEBUGS("AssetStorage") << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << llendl;

	LL_DEBUGS("AssetStorage") << "ASSET_TRACE requesting " << uuid << " type " << LLAssetType::lookup(type) << llendl;

	if (user_data)
	{
		// The *user_data should not be passed without a callback to clean it up.
		llassert(callback != NULL)
	}

	if (mShutDown)
	{
		LL_DEBUGS("AssetStorage") << "ASSET_TRACE cancelled " << uuid << " type " << LLAssetType::lookup(type) << " shutting down" << llendl;

		if (callback)
		{
			callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_NONE);
		}
		return;
	}

	if (uuid.isNull())
	{
		// Special case early out for NULL uuid and for shutting down
		if (callback)
		{
			callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);
		}
		return;
	}

	// Try static VFS first.
	if (findInStaticVFSAndInvokeCallback(uuid,type,callback,user_data))
	{
		LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in static VFS" << llendl;
		return;
	}

	BOOL exists = mVFS->getExists(uuid, type);
	LLVFile file(mVFS, uuid, type);
	U32 size = exists ? file.getSize() : 0;
	
	if (size > 0)
	{
		// we've already got the file
		// theoretically, partial files w/o a pending request shouldn't happen
		// unless there's a weird error
		if (callback)
		{
			callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
		}

		LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in VFS" << llendl;
	}
	else
	{
		if (exists)
		{
			llwarns << "Asset vfile " << uuid << ":" << type << " found with bad size " << file.getSize() << ", removing" << llendl;
			file.remove();
		}
		
		BOOL duplicate = FALSE;
		
		// check to see if there's a pending download of this uuid already
		for (request_list_t::iterator iter = mPendingDownloads.begin();
			 iter != mPendingDownloads.end(); ++iter )
		{
			LLAssetRequest  *tmp = *iter;
			if ((type == tmp->getType()) && (uuid == tmp->getUUID()))
			{
				if (callback == tmp->mDownCallback && user_data == tmp->mUserData)
				{
					// this is a duplicate from the same subsystem - throw it away
					llwarns << "Discarding duplicate request for asset " << uuid
							<< "." << LLAssetType::lookup(type) << llendl;
					return;
				}
				
				// this is a duplicate request
				// queue the request, but don't actually ask for it again
				duplicate = TRUE;
			}
		}
		if (duplicate)
		{
			LL_DEBUGS("AssetStorage") << "Adding additional non-duplicate request for asset " << uuid 
					<< "." << LLAssetType::lookup(type) << llendl;
		}
		
		// This can be overridden by subclasses
		_queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority);	
	}

}
Example #23
0
S32 start_net(S32& socket_out, int& nPort) 
{			
	// Create socket, make non-blocking
    // Init WinSock 
	int nRet;
	int hSocket;

	int snd_size = SEND_BUFFER_SIZE;
	int rec_size = RECEIVE_BUFFER_SIZE;
	int buff_size = 4;
 
	// Initialize windows specific stuff
	if(WSAStartup(0x0202, &stWSAData))
	{
		S32 err = WSAGetLastError();
		WSACleanup();
		LL_WARNS("AppInit") << "Windows Sockets initialization failed, err " << err << LL_ENDL;
		return 1;
	}

	// Get a datagram socket
    hSocket = (int)socket(AF_INET, SOCK_DGRAM, 0);
    if (hSocket == INVALID_SOCKET)
	{
		S32 err = WSAGetLastError();
		WSACleanup();
		LL_WARNS("AppInit") << "socket() failed, err " << err << LL_ENDL;
		return 2;
	}

	// Name the socket (assign the local port number to receive on)
	stLclAddr.sin_family      = AF_INET;
	stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	stLclAddr.sin_port        = htons(nPort);

	S32 attempt_port = nPort;
	LL_DEBUGS("AppInit") << "attempting to connect on port " << attempt_port << LL_ENDL;
	nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr));

	if (nRet == SOCKET_ERROR)
	{
		// If we got an address in use error...
		if (WSAGetLastError() == WSAEADDRINUSE)
		{
			// Try all ports from PORT_DISCOVERY_RANGE_MIN to PORT_DISCOVERY_RANGE_MAX
			for(attempt_port = PORT_DISCOVERY_RANGE_MIN;
				attempt_port <= PORT_DISCOVERY_RANGE_MAX;
				attempt_port++)
			{
				stLclAddr.sin_port = htons(attempt_port);
				LL_DEBUGS("AppInit") << "trying port " << attempt_port << LL_ENDL;
				nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr));

				if (!(nRet == SOCKET_ERROR && 
					WSAGetLastError() == WSAEADDRINUSE))
				{
					break;
				}
			}

			if (nRet == SOCKET_ERROR)
			{
				LL_WARNS("AppInit") << "startNet() : Couldn't find available network port." << LL_ENDL;
				// Fail gracefully here in release
				return 3;
			}
		}
		else
		// Some other socket error
		{
			LL_WARNS("AppInit") << llformat("bind() port: %d failed, Err: %d\n", nPort, WSAGetLastError()) << LL_ENDL;
			// Fail gracefully in release.
			return 4;
		}
	}

	sockaddr_in socket_address;
	S32 socket_address_size = sizeof(socket_address);
	getsockname(hSocket, (SOCKADDR*) &socket_address, &socket_address_size);
	attempt_port = ntohs(socket_address.sin_port);

	LL_INFOS("AppInit") << "connected on port " << attempt_port << LL_ENDL;
	nPort = attempt_port;
	
	// Set socket to be non-blocking
	unsigned long argp = 1;
	nRet = ioctlsocket (hSocket, FIONBIO, &argp);
	if (nRet == SOCKET_ERROR) 
	{
		printf("Failed to set socket non-blocking, Err: %d\n", 
		WSAGetLastError());
	}

	// set a large receive buffer
	nRet = setsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, buff_size);
	if (nRet)
	{
		LL_INFOS("AppInit") << "Can't set receive buffer size!" << LL_ENDL;
	}

	nRet = setsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, buff_size);
	if (nRet)
	{
		LL_INFOS("AppInit") << "Can't set send buffer size!" << LL_ENDL;
	}

	getsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, &buff_size);
	getsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, &buff_size);

	LL_DEBUGS("AppInit") << "startNet - receive buffer size : " << rec_size << LL_ENDL;
	LL_DEBUGS("AppInit") << "startNet - send buffer size    : " << snd_size << LL_ENDL;

	//  Setup a destination address
	char achMCAddr[MAXADDRSTR] = " ";	/* Flawfinder: ignore */ 
	stDstAddr.sin_family =      AF_INET;
    stDstAddr.sin_addr.s_addr = inet_addr(achMCAddr);
    stDstAddr.sin_port =        htons(nPort);

	socket_out = hSocket;
	return 0;
}
Example #24
0
void LLAssetStorage::downloadCompleteCallback(
	S32 result,
	const LLUUID& file_id,
	LLAssetType::EType file_type,
	void* user_data, LLExtStat ext_status)
{
	LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << file_id << " downloadCompleteCallback" << llendl;

	LL_DEBUGS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback() for " << file_id
		 << "," << LLAssetType::lookup(file_type) << llendl;
	LLAssetRequest* req = (LLAssetRequest*)user_data;
	if(!req)
	{
		llwarns << "LLAssetStorage::downloadCompleteCallback called without"
			"a valid request." << llendl;
		return;
	}
	if (!gAssetStorage)
	{
		llwarns << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << llendl;
		return;
	}

	// Inefficient since we're doing a find through a list that may have thousands of elements.
	// This is due for refactoring; we will probably change mPendingDownloads into a set.
	request_list_t::iterator download_iter = std::find(gAssetStorage->mPendingDownloads.begin(), 
													   gAssetStorage->mPendingDownloads.end(),
													   req);
	// If the LLAssetRequest doesn't exist in the downloads queue, then it either has already been deleted
	// by _cleanupRequests, or it's a transfer.
	if (download_iter != gAssetStorage->mPendingDownloads.end())
	{
		req->setUUID(file_id);
		req->setType(file_type);
	}

	if (LL_ERR_NOERR == result)
	{
		// we might have gotten a zero-size file
		LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType());
		if (vfile.getSize() <= 0)
		{
			llwarns << "downloadCompleteCallback has non-existent or zero-size asset " << req->getUUID() << llendl;
			
			result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
			vfile.remove();
		}
	}
	
	// find and callback ALL pending requests for this UUID
	// SJB: We process the callbacks in reverse order, I do not know if this is important,
	//      but I didn't want to mess with it.
	request_list_t requests;
	for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin();
		 iter != gAssetStorage->mPendingDownloads.end();  )
	{
		request_list_t::iterator curiter = iter++;
		LLAssetRequest* tmp = *curiter;
		if ((tmp->getUUID() == file_id) && (tmp->getType()== file_type))
		{
			requests.push_front(tmp);
			iter = gAssetStorage->mPendingDownloads.erase(curiter);
		}
	}
	for (request_list_t::iterator iter = requests.begin();
		 iter != requests.end();  )
	{
		request_list_t::iterator curiter = iter++;
		LLAssetRequest* tmp = *curiter;
		if (tmp->mDownCallback)
		{
			tmp->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), tmp->mUserData, result, ext_status);
		}
		delete tmp;
	}
}
void LLPluginProcessParent::idle(void)
{
	bool idle_again;

	do
	{
		// process queued messages
		mIncomingQueueMutex.lock();
		while(!mIncomingQueue.empty())
		{
			LLPluginMessage message = mIncomingQueue.front();
			mIncomingQueue.pop();
			mIncomingQueueMutex.unlock();
				
			receiveMessage(message);
			
			mIncomingQueueMutex.lock();
		}

		mIncomingQueueMutex.unlock();
		
		// Give time to network processing
		if(mMessagePipe)
		{
			// Drain any queued outgoing messages
			mMessagePipe->pumpOutput();
			
			// Only do input processing here if this instance isn't in a pollset.
			if(!mPolledInput)
			{
				mMessagePipe->pumpInput();
			}
		}
		
		if(mState <= STATE_RUNNING)
		{
			if(APR_STATUS_IS_EOF(mSocketError))
			{
				// Plugin socket was closed.  This covers both normal plugin termination and plugin crashes.
				errorState();
			}
			else if(mSocketError != APR_SUCCESS)
			{
				// The socket is in an error state -- the plugin is gone.
				LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL;
				errorState();
			}
		}	
		
		// If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState().
		// USE THIS CAREFULLY, since it can starve other code.  Specifically make sure there's no way to get into a closed cycle and never return.
		// When in doubt, don't do it.
		idle_again = false;
		switch(mState)
		{
			case STATE_UNINITIALIZED:
			break;

			case STATE_INITIALIZED:
			{
	
				apr_status_t status = APR_SUCCESS;
				apr_sockaddr_t* addr = NULL;
				mListenSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
				mBoundPort = 0;
				
				// This code is based on parts of LLSocket::create() in lliosocket.cpp.
				
				status = apr_sockaddr_info_get(
					&addr,
					"127.0.0.1",
					APR_INET,
					0,	// port 0 = ephemeral ("find me a port")
					0,
					gAPRPoolp);
					
				if(ll_apr_warn_status(status))
				{
					killSockets();
					errorState();
					break;
				}

				// This allows us to reuse the address on quick down/up. This is unlikely to create problems.
				ll_apr_warn_status(apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_REUSEADDR, 1));
				
				status = apr_socket_bind(mListenSocket->getSocket(), addr);
				if(ll_apr_warn_status(status))
				{
					killSockets();
					errorState();
					break;
				}

				// Get the actual port the socket was bound to
				{
					apr_sockaddr_t* bound_addr = NULL;
					if(ll_apr_warn_status(apr_socket_addr_get(&bound_addr, APR_LOCAL, mListenSocket->getSocket())))
					{
						killSockets();
						errorState();
						break;
					}
					mBoundPort = bound_addr->port;	

					if(mBoundPort == 0)
					{
						LL_WARNS("Plugin") << "Bound port number unknown, bailing out." << LL_ENDL;
						
						killSockets();
						errorState();
						break;
					}
				}
				
				LL_DEBUGS("Plugin") << "Bound tcp socket to port: " << addr->port << LL_ENDL;

				// Make the listen socket non-blocking
				status = apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_NONBLOCK, 1);
				if(ll_apr_warn_status(status))
				{
					killSockets();
					errorState();
					break;
				}

				apr_socket_timeout_set(mListenSocket->getSocket(), 0);
				if(ll_apr_warn_status(status))
				{
					killSockets();
					errorState();
					break;
				}
				
				// If it's a stream based socket, we need to tell the OS
				// to keep a queue of incoming connections for ACCEPT.
				status = apr_socket_listen(
					mListenSocket->getSocket(),
					10); // FIXME: Magic number for queue size
					
				if(ll_apr_warn_status(status))
				{
					killSockets();
					errorState();
					break;
				}
				
				// If we got here, we're listening.
				setState(STATE_LISTENING);
			}
			break;
			
			case STATE_LISTENING:
			{
				// Launch the plugin process.
				
				// Only argument to the launcher is the port number we're listening on
				mProcessParams.args.add(stringize(mBoundPort));
				if (! (mProcess = LLProcess::create(mProcessParams)))
				{
					errorState();
				}
				else
				{
					if(mDebug)
					{
						#if LL_DARWIN
						// If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue.
						
						// The command we're constructing would look like this on the command line:
						// osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell'

						LLProcess::Params params;
						params.executable = "/usr/bin/osascript";
						params.args.add("-e");
						params.args.add("tell application \"Terminal\"");
						params.args.add("-e");
						params.args.add(STRINGIZE("set win to do script \"gdb -pid "
												  << mProcess->getProcessID() << "\""));
						params.args.add("-e");
						params.args.add("do script \"continue\" in win");
						params.args.add("-e");
						params.args.add("end tell");
						mDebugger = LLProcess::create(params);

						#endif
					}
					
					// This will allow us to time out if the process never starts.
					mHeartbeat.start();
					mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout);
					setState(STATE_LAUNCHED);
				}
			}
			break;

			case STATE_LAUNCHED:
				// waiting for the plugin to connect
				if(pluginLockedUpOrQuit())
				{
					errorState();
				}
				else
				{
					// Check for the incoming connection.
					if(accept())
					{
						// Stop listening on the server port
						mListenSocket.reset();
						setState(STATE_CONNECTED);
					}
				}
			break;
			
			case STATE_CONNECTED:
				// waiting for hello message from the plugin

				if(pluginLockedUpOrQuit())
				{
					errorState();
				}
			break;

			case STATE_HELLO:
				LL_DEBUGS("Plugin") << "received hello message" << LL_ENDL;
				
				// Send the message to load the plugin
				{
					LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin");
					message.setValue("file", mPluginFile);
					message.setValue("dir", mPluginDir);
					sendMessage(message);
				}

				setState(STATE_LOADING);
			break;
			
			case STATE_LOADING:
				// The load_plugin_response message will kick us from here into STATE_RUNNING
				if(pluginLockedUpOrQuit())
				{
					errorState();
				}
			break;
			
			case STATE_RUNNING:
				if(pluginLockedUpOrQuit())
				{
					errorState();
				}
			break;
			
			case STATE_EXITING:
				if (! LLProcess::isRunning(mProcess))
				{
					setState(STATE_CLEANUP);
				}
				else if(pluginLockedUp())
				{
					LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << LL_ENDL;
					errorState();
				}
			break;

			case STATE_LAUNCH_FAILURE:
				if(mOwner != NULL)
				{
					mOwner->pluginLaunchFailed();
				}
				setState(STATE_CLEANUP);
			break;

			case STATE_ERROR:
				if(mOwner != NULL)
				{
					mOwner->pluginDied();
				}
				setState(STATE_CLEANUP);
			break;
			
			case STATE_CLEANUP:
				LLProcess::kill(mProcess);
				killSockets();
				setState(STATE_DONE);
			break;
			
			
			case STATE_DONE:
				// just sit here.
			break;
			
		}
	
	} while (idle_again);
}
Example #26
0
void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id,
									 const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id,
									 const LLUUID &asset_id, LLAssetType::EType atype,
									 LLGetAssetCallback callback, void *user_data, BOOL is_priority)
{
	lldebugs << "LLAssetStorage::getInvItemAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << llendl;

	//
	// Probably will get rid of this early out?
	//
	//if (asset_id.isNull())
	//{
	//	// Special case early out for NULL uuid
	//	if (callback)
	//	{
	//		callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE);
	//	}
	//	return;
	//}

	bool exists = false; 
	U32 size = 0;

	if(asset_id.notNull())
	{
		// Try static VFS first.
		if (findInStaticVFSAndInvokeCallback( asset_id, atype, callback, user_data))
		{
			return;
		}

		exists = mVFS->getExists(asset_id, atype);
		LLVFile file(mVFS, asset_id, atype);
		size = exists ? file.getSize() : 0;
		if(exists && size < 1)
		{
			llwarns << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << llendl;
			file.remove();
		}

	}

	if (size > 0)
	{
		// we've already got the file
		// theoretically, partial files w/o a pending request shouldn't happen
		// unless there's a weird error
		if (callback)
		{
			callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
		}
	}
	else
	{
		// See whether we should talk to the object's originating sim,
		// or the upstream provider.
		LLHost source_host;
		if (object_sim.isOk())
		{
			source_host = object_sim;
		}
		else
		{
			source_host = mUpstreamHost;
		}
		if (source_host.isOk())
		{
			// stash the callback info so we can find it after we get the response message
			LLInvItemRequest *req = new LLInvItemRequest(asset_id, atype);
			req->mDownCallback = callback;
			req->mUserData = user_data;
			req->mIsPriority = is_priority;

			// send request message to our upstream data provider
			// Create a new asset transfer.
			LLTransferSourceParamsInvItem spi;
			spi.setAgentSession(agent_id, session_id);
			spi.setInvItem(owner_id, task_id, item_id);
			spi.setAsset(asset_id, atype);

			// Set our destination file, and the completion callback.
			LLTransferTargetParamsVFile tpvf;
			tpvf.setAsset(asset_id, atype);
			tpvf.setCallback(downloadInvItemCompleteCallback, req);

			LL_DEBUGS("AssetStorage") << "Starting transfer for inventory asset "
				<< item_id << " owned by " << owner_id << "," << task_id
				<< llendl;
			LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET);
			ttcp->requestTransfer(spi, tpvf, 100.f + (is_priority ? 1.f : 0.f));
		}
		else
		{
			// uh-oh, we shouldn't have gotten here
			llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl;
			if (callback)
			{
				callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
			}
		}
	}
}
void LLPluginProcessParent::poll(F64 timeout)
{
	if(sPollsetNeedsRebuild || !sUseReadThread)
	{
		sPollsetNeedsRebuild = false;
		updatePollset();
	}
	
	if(sPollSet)
	{
		apr_status_t status;
		apr_int32_t count;
		const apr_pollfd_t *descriptors;
		status = apr_pollset_poll(sPollSet, (apr_interval_time_t)(timeout * 1000000), &count, &descriptors);
		if(status == APR_SUCCESS)
		{
			// One or more of the descriptors signalled.  Call them.
			for(int i = 0; i < count; i++)
			{
				LLPluginProcessParent *self = (LLPluginProcessParent *)(descriptors[i].client_data);
				// NOTE: the descriptor returned here is actually a COPY of the original (even though we create the pollset with APR_POLLSET_NOCOPY).
				// This means that even if the parent has set its mPollFD.client_data to NULL, the old pointer may still there in this descriptor.
				// It's even possible that the old pointer no longer points to a valid LLPluginProcessParent.
				// This means that we can't safely dereference the 'self' pointer here without some extra steps...
				if(self)
				{
					// Make sure this pointer is still in the instances list
					bool valid = false;
					{
						LLMutexLock lock(sInstancesMutex);
						for(std::list<LLPluginProcessParent*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
						{
							if(*iter == self)
							{
								// Lock the instance's mutex before unlocking the global mutex.  
								// This avoids a possible race condition where the instance gets deleted between this check and the servicePoll() call.
								self->mIncomingQueueMutex.lock();
								valid = true;
								break;
							}
						}
					}
					
					if(valid)
					{
						// The instance is still valid.
						// Pull incoming messages off the socket
						self->servicePoll();
						self->mIncomingQueueMutex.unlock();
					}
					else
					{
						LL_DEBUGS("PluginPoll") << "detected deleted instance " << self << LL_ENDL;
					}

				}
			}
		}
		else if(APR_STATUS_IS_TIMEUP(status))
		{
			// timed out with no incoming data.  Just return.
		}
		else if(status == EBADF)
		{
			// This happens when one of the file descriptors in the pollset is destroyed, which happens whenever a plugin's socket is closed.
			// The pollset has been or will be recreated, so just return.
			LL_DEBUGS("PluginPoll") << "apr_pollset_poll returned EBADF" << LL_ENDL;
		}
		else if(status != APR_SUCCESS)
		{
			LL_WARNS("PluginPoll") << "apr_pollset_poll failed with status " << status << LL_ENDL;
		}
	}
}
BOOL LLDXHardware::getInfo(BOOL vram_only)
{
	LLTimer hw_timer;
	BOOL ok = FALSE;
    HRESULT       hr;

    CoInitialize(NULL);

    IDxDiagProvider *dx_diag_providerp = NULL;
    IDxDiagContainer *dx_diag_rootp = NULL;
	IDxDiagContainer *devices_containerp = NULL;
	// IDxDiagContainer *system_device_containerp= NULL;
	IDxDiagContainer *device_containerp = NULL;
	IDxDiagContainer *file_containerp = NULL;
	IDxDiagContainer *driver_containerp = NULL;

    // CoCreate a IDxDiagProvider*
	LL_DEBUGS("AppInit") << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL;
    hr = CoCreateInstance(CLSID_DxDiagProvider,
                          NULL,
                          CLSCTX_INPROC_SERVER,
                          IID_IDxDiagProvider,
                          (LPVOID*) &dx_diag_providerp);

	if (FAILED(hr))
	{
		LL_WARNS("AppInit") << "No DXDiag provider found!  DirectX 9 not installed!" << LL_ENDL;
		gWriteDebug("No DXDiag provider found!  DirectX 9 not installed!\n");
		goto LCleanup;
	}
    if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed
    {
        // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize
        // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are 
        // digital signed as logo'd by WHQL which may connect via internet to update 
        // WHQL certificates.    
        DXDIAG_INIT_PARAMS dx_diag_init_params;
        ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS));

        dx_diag_init_params.dwSize                  = sizeof(DXDIAG_INIT_PARAMS);
        dx_diag_init_params.dwDxDiagHeaderVersion   = DXDIAG_DX9_SDK_VERSION;
        dx_diag_init_params.bAllowWHQLChecks        = TRUE;
        dx_diag_init_params.pReserved               = NULL;

		LL_DEBUGS("AppInit") << "dx_diag_providerp->Initialize" << LL_ENDL;
        hr = dx_diag_providerp->Initialize(&dx_diag_init_params);
        if(FAILED(hr))
		{
            goto LCleanup;
		}

		LL_DEBUGS("AppInit") << "dx_diag_providerp->GetRootContainer" << LL_ENDL;
        hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp );
        if(FAILED(hr) || !dx_diag_rootp)
		{
            goto LCleanup;
		}

		HRESULT hr;

		// Get display driver information
		LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer" << LL_ENDL;
		hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp);
		if(FAILED(hr) || !devices_containerp)
		{
            goto LCleanup;
		}

		// Get device 0
		LL_DEBUGS("AppInit") << "devices_containerp->GetChildContainer" << LL_ENDL;
		hr = devices_containerp->GetChildContainer(L"0", &device_containerp);
		if(FAILED(hr) || !device_containerp)
		{
            goto LCleanup;
		}
		
		// Get the English VRAM string
		{
		  std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish");

		  // We don't need the device any more
		  SAFE_RELEASE(device_containerp);

		  // Dump the string as an int into the structure
		  char *stopstring;
		  mVRAM = strtol(ram_str.c_str(), &stopstring, 10); 
		  LL_INFOS("AppInit") << "VRAM Detected: " << mVRAM << " DX9 string: " << ram_str << LL_ENDL;
		}

		if (vram_only)
		{
			ok = TRUE;
			goto LCleanup;
		}


		/* for now, we ONLY do vram_only the rest of this
		   is commented out, to ensure no-one is tempted
		   to use it
		
		// Now let's get device and driver information
		// Get the IDxDiagContainer object called "DxDiag_SystemDevices".
		// This call may take some time while dxdiag gathers the info.
		DWORD num_devices = 0;
	    WCHAR wszContainer[256];
		LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer DxDiag_SystemDevices" << LL_ENDL;
		hr = dx_diag_rootp->GetChildContainer(L"DxDiag_SystemDevices", &system_device_containerp);
		if (FAILED(hr))
		{
			goto LCleanup;
		}

		hr = system_device_containerp->GetNumberOfChildContainers(&num_devices);
		if (FAILED(hr))
		{
			goto LCleanup;
		}

		LL_DEBUGS("AppInit") << "DX9 iterating over devices" << LL_ENDL;
		S32 device_num = 0;
		for (device_num = 0; device_num < (S32)num_devices; device_num++)
		{
			hr = system_device_containerp->EnumChildContainerNames(device_num, wszContainer, 256);
			if (FAILED(hr))
			{
				goto LCleanup;
			}

			hr = system_device_containerp->GetChildContainer(wszContainer, &device_containerp);
			if (FAILED(hr) || device_containerp == NULL)
			{
				goto LCleanup;
			}

			std::string device_name = get_string(device_containerp, L"szDescription");

			std::string device_id = get_string(device_containerp, L"szDeviceID");

			LLDXDevice *dxdevicep = new LLDXDevice;
			dxdevicep->mName = device_name;
			dxdevicep->mPCIString = device_id;
			mDevices[dxdevicep->mPCIString] = dxdevicep;

			// Split the PCI string based on vendor, device, subsys, rev.
			std::string str(device_id);
			typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
			boost::char_separator<char> sep("&\\", "", boost::keep_empty_tokens);
			tokenizer tokens(str, sep);

			tokenizer::iterator iter = tokens.begin();
			S32 count = 0;
			BOOL valid = TRUE;
			for (;(iter != tokens.end()) && (count < 3);++iter)
			{
				switch (count)
				{
				case 0:
					if (strcmp(iter->c_str(), "PCI"))
					{
						valid = FALSE;
					}
					break;
				case 1:
					dxdevicep->mVendorID = iter->c_str();
					break;
				case 2:
					dxdevicep->mDeviceID = iter->c_str();
					break;
				default:
					// Ignore it
					break;
				}
				count++;
			}




			// Now, iterate through the related drivers
			hr = device_containerp->GetChildContainer(L"Drivers", &driver_containerp);
			if (FAILED(hr) || !driver_containerp)
			{
				goto LCleanup;
			}

			DWORD num_files = 0;
			hr = driver_containerp->GetNumberOfChildContainers(&num_files);
			if (FAILED(hr))
			{
				goto LCleanup;
			}

			S32 file_num = 0;
			for (file_num = 0; file_num < (S32)num_files; file_num++ )
			{

				hr = driver_containerp->EnumChildContainerNames(file_num, wszContainer, 256);
				if (FAILED(hr))
				{
					goto LCleanup;
				}

				hr = driver_containerp->GetChildContainer(wszContainer, &file_containerp);
				if (FAILED(hr) || file_containerp == NULL)
				{
					goto LCleanup;
				}

				std::string driver_path = get_string(file_containerp, L"szPath");
				std::string driver_name = get_string(file_containerp, L"szName");
				std::string driver_version = get_string(file_containerp, L"szVersion");
				std::string driver_date = get_string(file_containerp, L"szDatestampEnglish");

				LLDXDriverFile *dxdriverfilep = new LLDXDriverFile;
				dxdriverfilep->mName = driver_name;
				dxdriverfilep->mFilepath= driver_path;
				dxdriverfilep->mVersionString = driver_version;
				dxdriverfilep->mVersion.set(driver_version);
				dxdriverfilep->mDateString = driver_date;

				dxdevicep->mDriverFiles[driver_name] = dxdriverfilep;

				SAFE_RELEASE(file_containerp);
			}
			SAFE_RELEASE(device_containerp);
		}
		*/
    }

    // dumpDevices();
    ok = TRUE;
	
LCleanup:
	if (!ok)
	{
		LL_WARNS("AppInit") << "DX9 probe failed" << LL_ENDL;
		gWriteDebug("DX9 probe failed\n");
	}

	SAFE_RELEASE(file_containerp);
	SAFE_RELEASE(driver_containerp);
	SAFE_RELEASE(device_containerp);
	SAFE_RELEASE(devices_containerp);
    SAFE_RELEASE(dx_diag_rootp);
    SAFE_RELEASE(dx_diag_providerp);
    
    CoUninitialize();
    
    return ok;
    }
void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL animate)
{
	// Look for "/20 foo" channel chats.
	S32 channel = 0;
	LLWString out_text = stripChannelNumber(wtext, &channel);
	std::string utf8_out_text = wstring_to_utf8str(out_text);

	std::string utf8_text = wstring_to_utf8str(wtext);
	utf8_text = utf8str_trim(utf8_text);
	if (!utf8_text.empty())
	{
		utf8_text = utf8str_truncate(utf8_text, MAX_STRING - 1);
	}

// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b
	if ( (0 == channel) && (rlv_handler_t::isEnabled()) )
	{
		// Adjust the (public) chat "volume" on chat and gestures (also takes care of playing the proper animation)
		if ( ((CHAT_TYPE_SHOUT == type) || (CHAT_TYPE_NORMAL == type)) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) )
			type = CHAT_TYPE_WHISPER;
		else if ( (CHAT_TYPE_SHOUT == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) )
			type = CHAT_TYPE_NORMAL;
		else if ( (CHAT_TYPE_WHISPER == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) )
			type = CHAT_TYPE_NORMAL;

		animate &= !gRlvHandler.hasBehaviour( (!RlvUtil::isEmote(utf8_text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE );
	}
// [/RLVa:KB]

	LLCachedControl<bool> disable_chat_animation("SGDisableChatAnimation");

	// Don't animate for chats people can't hear (chat to scripts)
	if (animate && (channel == 0) && !disable_chat_animation)
	{
		if (type == CHAT_TYPE_WHISPER)
		{
			LL_DEBUGS() << "You whisper " << utf8_text << LL_ENDL;
			gAgent.sendAnimationRequest(ANIM_AGENT_WHISPER, ANIM_REQUEST_START);
		}
		else if (type == CHAT_TYPE_NORMAL)
		{
			LL_DEBUGS() << "You say " << utf8_text << LL_ENDL;
			gAgent.sendAnimationRequest(ANIM_AGENT_TALK, ANIM_REQUEST_START);
		}
		else if (type == CHAT_TYPE_SHOUT)
		{
			LL_DEBUGS() << "You shout " << utf8_text << LL_ENDL;
			gAgent.sendAnimationRequest(ANIM_AGENT_SHOUT, ANIM_REQUEST_START);
		}
		else
		{
			LL_INFOS() << "send_chat_from_viewer() - invalid volume" << LL_ENDL;
			return;
		}
	}
	else
	{
		if (type != CHAT_TYPE_START && type != CHAT_TYPE_STOP)
		{
			LL_DEBUGS() << "Channel chat: " << utf8_text << LL_ENDL;
		}
	}

	send_chat_from_viewer(utf8_out_text, type, channel);
}
Example #30
0
// There are three types of water objects:
// Region water objects: the water in a region.
// Hole water objects: water in the void but within current draw distance.
// Edge water objects: the water outside the draw distance, up till the horizon.
//
// For example:
//
// -----------------------horizon-------------------------
// |                 |                 |                 |
// |  Edge Water     |                 |                 |
// |                 |                 |                 |
// |                 |                 |                 |
// |                 |                 |                 |
// |                 |                 |                 |
// |                 |      rwidth     |                 |
// |                 |     <----->     |                 |
// -------------------------------------------------------
// |                 |Hole |other|     |                 |
// |                 |Water|reg. |     |                 |
// |                 |-----------------|                 |
// |                 |other|cur. |<--> |                 |
// |                 |reg. | reg.|  \__|_ draw distance  |
// |                 |-----------------|                 |
// |                 |     |     |<--->|                 |
// |                 |     |     |  \__|_ range          |
// -------------------------------------------------------
// |                 |<----width------>|<--horizon ext.->|
// |                 |                 |                 |
// |                 |                 |                 |
// |                 |                 |                 |
// |                 |                 |                 |
// |                 |                 |                 |
// |                 |                 |                 |
// |                 |                 |                 |
// -------------------------------------------------------
//
void LLWorld::updateWaterObjects()
{
	if (!gAgent.getRegion())
	{
		return;
	}
	if (mRegionList.empty())
	{
		llwarns << "No regions!" << llendl;
		return;
	}

	LLViewerRegion const* regionp = gAgent.getRegion();

	// Region width in meters.
	S32 const rwidth = (S32)regionp->getWidth();

	// The distance we might see into the void
	// when standing on the edge of a region, in meters.
	S32 const draw_distance = llceil(mLandFarClip);

	// We can only have "holes" in the water (where there no region) if we
	// can have existing regions around it. Taking into account that this
	// code is only executed when we enter a region, and not when we walk
	// around in it, we (only) need to take into account regions that fall
	// within the draw_distance.
	//
	// Set 'range' to draw_distance, rounded up to the nearest multiple of rwidth.
	S32 const nsims = (draw_distance + rwidth - 1) / rwidth;
	S32 const range = nsims * rwidth;

	// Get South-West corner of current region.
	U32 region_x, region_y;
	from_region_handle(regionp->getHandle(), &region_x, &region_y);

	// The min. and max. coordinates of the South-West corners of the Hole water objects.
	S32 const min_x = (S32)region_x - range;
	S32 const min_y = (S32)region_y - range;
	S32 const max_x = (S32)region_x + rwidth-256 + range;
	S32 const max_y = (S32)region_y + rwidth-256 + range;

	// Attempt to determine a sensible water height for all the
	// Hole Water objects.
	//
	// It make little sense to try to guess what the best water
	// height should be when that isn't completely obvious: if it's
	// impossible to satisfy every region's water height without
	// getting a jump in the water height.
	//
	// In order to keep the reasoning simple, we assume something
	// logical as a group of connected regions, where the coastline
	// is at the outer edge. Anything more complex that would "break"
	// under such an assumption would probably break anyway (would
	// depend on terrain editing and existing mega prims, say, if
	// anything would make sense at all).
	//
	// So, what we do is find all connected regions within the
	// draw distance that border void, and then pick the lowest
	// water height of those (coast) regions.
	S32 const n = 2 * nsims + 1;
	S32 const origin = nsims + nsims * n;
	std::vector<F32> water_heights(n * n);
	std::vector<U8> checked(n * n, 0);		// index = nx + ny * n + origin;
	U8 const region_bit = 1;
	U8 const hole_bit = 2;
	U8 const bordering_hole_bit = 4;
	U8 const bordering_edge_bit = 8;
	// Use the legacy waterheight for the Edge water in the case
	// that we don't find any Hole water at all.
	F32 water_height = DEFAULT_WATER_HEIGHT;
	int max_count = 0;
	LL_DEBUGS("WaterHeight") << "Current region: " << regionp->getName() << "; water height: " << regionp->getWaterHeight() << " m." << LL_ENDL;
	std::map<S32, int> water_height_counts;
	typedef std::queue<std::pair<S32, S32>, std::deque<std::pair<S32, S32> > > nxny_pairs_type;
	nxny_pairs_type nxny_pairs;
	nxny_pairs.push(nxny_pairs_type::value_type(0, 0));
	water_heights[origin] = regionp->getWaterHeight();
	checked[origin] = region_bit;
	// For debugging purposes.
	int number_of_connected_regions = 1;
	int uninitialized_regions = 0;
	int bordering_hole = 0;
	int bordering_edge = 0;
	while(!nxny_pairs.empty())
	{
		S32 const nx = nxny_pairs.front().first;
		S32 const ny = nxny_pairs.front().second;
		LL_DEBUGS("WaterHeight") << "nx,ny = " << nx << "," << ny << LL_ENDL;
		S32 const index = nx + ny * n + origin;
		nxny_pairs.pop();
		for (S32 dir = 0; dir < 4; ++dir)
		{
			S32 const cnx = nx + gDirAxes[dir][0];
			S32 const cny = ny + gDirAxes[dir][1];
			LL_DEBUGS("WaterHeight") << "dir = " << dir << "; cnx,cny = " << cnx << "," << cny << LL_ENDL;
			S32 const cindex = cnx + cny * n + origin;
			bool is_hole = false;
			bool is_edge = false;
			LLViewerRegion* new_region_found = NULL;
			if (cnx < -nsims || cnx > nsims ||
			    cny < -nsims || cny > nsims)
			{
				LL_DEBUGS("WaterHeight") << "  Edge Water!" << LL_ENDL;
				// Bumped into Edge water object.
				is_edge = true;
			}
			else if (checked[cindex])
			{
				LL_DEBUGS("WaterHeight") << "  Already checked before!" << LL_ENDL;
				// Already checked.
				is_hole = (checked[cindex] & hole_bit);
			}
			else
			{
				S32 x = (S32)region_x + cnx * rwidth;
				S32 y = (S32)region_y + cny * rwidth;
				U64 region_handle = to_region_handle(x, y);
				new_region_found = getRegionFromHandle(region_handle);
				is_hole = !new_region_found;
				checked[cindex] = is_hole ? hole_bit : region_bit;
			}
			if (is_hole)
			{
				// This was a region that borders at least one 'hole'.
				// Count the found coastline.
				F32 new_water_height = water_heights[index];
				LL_DEBUGS("WaterHeight") << "  This is void; counting coastline with water height of " << new_water_height << LL_ENDL;
				S32 new_water_height_cm = llround(new_water_height * 100);
				int count = (water_height_counts[new_water_height_cm] += 1);
				// Just use the lowest water height: this is mainly about the horizon water,
				// and whatever we do, we don't want it to be possible to look under the water
				// when looking in the distance: it is better to make a step downwards in water
				// height when going away from the avie than a step upwards. However, since
				// everyone is used to DEFAULT_WATER_HEIGHT, don't allow a single region
				// to drag the water level below DEFAULT_WATER_HEIGHT on it's own.
				if (bordering_hole == 0 ||			// First time we get here.
				    (new_water_height >= DEFAULT_WATER_HEIGHT &&
					 new_water_height < water_height) ||
				    (new_water_height < DEFAULT_WATER_HEIGHT &&
					 count > max_count)
				   )
				{
					water_height = new_water_height;
				}
				if (count > max_count)
				{
					max_count = count;
				}
				if (!(checked[index] & bordering_hole_bit))
				{
					checked[index] |= bordering_hole_bit;
					++bordering_hole;
				}
			}
			else if (is_edge && !(checked[index] & bordering_edge_bit))
			{
				checked[index] |= bordering_edge_bit;
				++bordering_edge;
			}
			if (!new_region_found)
			{
				// Dead end, there is no region here.
				continue;
			}
			// Found a new connected region.
			++number_of_connected_regions;
			if (new_region_found->getName().empty())
			{
				// Uninitialized LLViewerRegion, don't use it's water height.
				LL_DEBUGS("WaterHeight") << "  Uninitialized region." << LL_ENDL;
				++uninitialized_regions;
				continue;
			}
			nxny_pairs.push(nxny_pairs_type::value_type(cnx, cny));
			water_heights[cindex] = new_region_found->getWaterHeight();
			LL_DEBUGS("WaterHeight") << "  Found a new region (name: " << new_region_found->getName() << "; water height: " << water_heights[cindex] << " m)!" << LL_ENDL;
		}
	}
	llinfos << "Number of connected regions: " << number_of_connected_regions << " (" << uninitialized_regions <<
		" uninitialized); number of regions bordering Hole water: " << bordering_hole <<
		"; number of regions bordering Edge water: " << bordering_edge << llendl;
	llinfos << "Coastline count (height, count): ";
	bool first = true;
	for (std::map<S32, int>::iterator iter = water_height_counts.begin(); iter != water_height_counts.end(); ++iter)
	{
		if (!first) llcont << ", ";
		llcont << "(" << (iter->first / 100.f) << ", " << iter->second << ")";
		first = false;
	}
	llcont << llendl;
	llinfos << "Water height used for Hole and Edge water objects: " << water_height << llendl;

	// Update all Region water objects.
	for (region_list_t::iterator iter = mRegionList.begin(); iter != mRegionList.end(); ++iter)
	{
		LLViewerRegion* regionp = *iter;
		LLVOWater* waterp = regionp->getLand().getWaterObj();
		if (waterp)
		{
			gObjectList.updateActive(waterp);
		}
	}

	// Clean up all existing Hole water objects.
	for (std::list<LLVOWater*>::iterator iter = mHoleWaterObjects.begin();
		 iter != mHoleWaterObjects.end(); ++iter)
	{
		LLVOWater* waterp = *iter;
		gObjectList.killObject(waterp);
	}
	mHoleWaterObjects.clear();

	// Let the Edge and Hole water boxes be 1024 meter high so that they
	// are never too small to be drawn (A LL_VO_*_WATER box has water
	// rendered on it's bottom surface only), and put their bottom at
	// the current regions water height.
	F32 const box_height = 1024;
	F32 const water_center_z = water_height + box_height / 2;
	const S32 step = 256;
	// Create new Hole water objects within 'range' where there is no region.
	for (S32 x = min_x; x <= max_x; x += step)
	{
		for (S32 y = min_y; y <= max_y; y += step)
		{
			U64 region_handle = to_region_handle(x, y);
			if (!getRegionFromHandle(region_handle))
			{
				LLVOWater* waterp = (LLVOWater*)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER, gAgent.getRegion());
				waterp->setUseTexture(FALSE);
				waterp->setPositionGlobal(LLVector3d(x + step / 2, y + step / 2, water_center_z));
				waterp->setScale(LLVector3((F32)step, (F32)step, box_height));
				gPipeline.createObject(waterp);
				mHoleWaterObjects.push_back(waterp);
			}
		}
	}

	// Center of the region.
	S32 const center_x = region_x + step / 2;
	S32 const center_y = region_y + step / 2;
	// Width of the area with Hole water objects.
	S32 const width = step + 2 * range;
	S32 const horizon_extend = 2048 + 512 - range;	// Legacy value.
	// The overlap is needed to get rid of sky pixels being visible between the
	// Edge and Hole water object at greater distances (due to floating point
	// round off errors).
	S32 const edge_hole_overlap = 1;		// Twice the actual overlap.
		
	for (S32 dir = 0; dir < 8; ++dir)
	{
		// Size of the Edge water objects.
		S32 const dim_x = (gDirAxes[dir][0] == 0) ? width : (horizon_extend + edge_hole_overlap);
		S32 const dim_y = (gDirAxes[dir][1] == 0) ? width : (horizon_extend + edge_hole_overlap);
		// And their position.
		S32 const water_center_x = center_x + (width + horizon_extend) / 2 * gDirAxes[dir][0];
		S32 const water_center_y = center_y + (width + horizon_extend) / 2 * gDirAxes[dir][1];

		LLVOWater* waterp = mEdgeWaterObjects[dir];
		if (!waterp || waterp->isDead())
		{
			// The edge water objects can be dead because they're attached to the region that the
			// agent was in when they were originally created.
			mEdgeWaterObjects[dir] = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER, gAgent.getRegion());
			waterp = mEdgeWaterObjects[dir];
			waterp->setUseTexture(FALSE);
			waterp->setIsEdgePatch(TRUE);		// Mark that this is edge water and not hole water.
			gPipeline.createObject(waterp);
		}

		waterp->setRegion(gAgent.getRegion());
		LLVector3d water_pos(water_center_x, water_center_y, water_center_z);
		LLVector3 water_scale((F32) dim_x, (F32) dim_y, box_height);

		waterp->setPositionGlobal(water_pos);
		waterp->setScale(water_scale);

		gObjectList.updateActive(waterp);
	}
}